Commit 6fbeb004 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer
Browse files

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: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent d3c7b35c
Loading
Loading
Loading
Loading
+64 −5
Original line number Diff line number Diff line
@@ -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.
 *
+12 −0
Original line number Diff line number Diff line
@@ -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.