dm bufio: implement discard

Add functions dm_bufio_issue_discard and dm_bufio_discard_buffers.
dm_bufio_issue_discard sends discard request to the underlying device.
dm_bufio_discard_buffers frees buffers in the range and then calls
dm_bufio_issue_discard.

Also, factor out block_to_sector for reuse in dm_bufio_issue_discard.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
Mikulas Patocka 2020-02-07 15:59:25 -05:00 committed by Mike Snitzer
parent d3c7b35c20
commit 6fbeb0048e
2 changed files with 76 additions and 5 deletions

View file

@ -631,6 +631,19 @@ dmio:
submit_bio(bio);
}
static inline sector_t block_to_sector(struct dm_bufio_client *c, sector_t block)
{
sector_t sector;
if (likely(c->sectors_per_block_bits >= 0))
sector = block << c->sectors_per_block_bits;
else
sector = block * (c->block_size >> SECTOR_SHIFT);
sector += c->start;
return sector;
}
static void submit_io(struct dm_buffer *b, int rw, void (*end_io)(struct dm_buffer *, blk_status_t))
{
unsigned n_sectors;
@ -639,11 +652,7 @@ static void submit_io(struct dm_buffer *b, int rw, void (*end_io)(struct dm_buff
b->end_io = end_io;
if (likely(b->c->sectors_per_block_bits >= 0))
sector = b->block << b->c->sectors_per_block_bits;
else
sector = b->block * (b->c->block_size >> SECTOR_SHIFT);
sector += b->c->start;
sector = block_to_sector(b->c, b->block);
if (rw != REQ_OP_WRITE) {
n_sectors = b->c->block_size >> SECTOR_SHIFT;
@ -1325,6 +1334,56 @@ int dm_bufio_issue_flush(struct dm_bufio_client *c)
}
EXPORT_SYMBOL_GPL(dm_bufio_issue_flush);
/*
* Use dm-io to send a discard request to flush the device.
*/
int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t count)
{
struct dm_io_request io_req = {
.bi_op = REQ_OP_DISCARD,
.bi_op_flags = REQ_SYNC,
.mem.type = DM_IO_KMEM,
.mem.ptr.addr = NULL,
.client = c->dm_io,
};
struct dm_io_region io_reg = {
.bdev = c->bdev,
.sector = block_to_sector(c, block),
.count = block_to_sector(c, count),
};
BUG_ON(dm_bufio_in_request());
return dm_io(&io_req, 1, &io_reg, NULL);
}
EXPORT_SYMBOL_GPL(dm_bufio_issue_discard);
/*
* Free the specified range of buffers. If a buffer is held by other process, it
* is not freed. If a buffer is dirty, it is discarded without writeback.
* Finally, send the discard request to the device.
*/
int dm_bufio_discard_buffers(struct dm_bufio_client *c, sector_t block, sector_t count)
{
sector_t i;
for (i = block; i < block + count; i++) {
struct dm_buffer *b;
dm_bufio_lock(c);
b = __find(c, i);
if (b && likely(!b->hold_count)) {
wait_on_bit_io(&b->state, B_READING, TASK_UNINTERRUPTIBLE);
wait_on_bit_io(&b->state, B_WRITING, TASK_UNINTERRUPTIBLE);
__unlink_buffer(b);
__free_buffer_wake(b);
}
dm_bufio_unlock(c);
}
return dm_bufio_issue_discard(c, block, count);
}
EXPORT_SYMBOL_GPL(dm_bufio_discard_buffers);
/*
* We first delete any other buffer that may be at that new location.
*

View file

@ -118,6 +118,18 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c);
*/
int dm_bufio_issue_flush(struct dm_bufio_client *c);
/*
* Send a discard request to the underlying device.
*/
int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t count);
/*
* Free the specified range of buffers. If a buffer is held by other process, it
* is not freed. If a buffer is dirty, it is discarded without writeback.
* Finally, send the discard request to the device.
*/
int dm_bufio_discard_buffers(struct dm_bufio_client *c, sector_t block, sector_t count);
/*
* Like dm_bufio_release but also move the buffer to the new
* block. dm_bufio_write_dirty_buffers is needed to commit the new block.