Commit bcb21c8c authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe

block: loop: set discard granularity and alignment for block device backed loop

In case of block device backend, if the backend supports write zeros, the
loop device will set queue flag of QUEUE_FLAG_DISCARD. However,
limits.discard_granularity isn't setup, and this way is wrong,
see the following description in Documentation/ABI/testing/sysfs-block:

	A discard_granularity of 0 means that the device does not support
	discard functionality.

Especially 9b15d109 ("block: improve discard bio alignment in
__blkdev_issue_discard()") starts to take q->limits.discard_granularity
for computing max discard sectors. And zero discard granularity may cause
kernel oops, or fail discard request even though the loop queue claims
discard support via QUEUE_FLAG_DISCARD.

Fix the issue by setup discard granularity and alignment.

Fixes: c52abf56 ("loop: Better discard support for block devices")
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarColy Li <colyli@suse.de>
Cc: Hannes Reinecke <hare@suse.com>
Cc: Xiao Ni <xni@redhat.com>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Evan Green <evgreen@chromium.org>
Cc: Gwendal Grignou <gwendal@chromium.org>
Cc: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Cc: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent d7d8535f
...@@ -878,6 +878,7 @@ static void loop_config_discard(struct loop_device *lo) ...@@ -878,6 +878,7 @@ static void loop_config_discard(struct loop_device *lo)
struct file *file = lo->lo_backing_file; struct file *file = lo->lo_backing_file;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
struct request_queue *q = lo->lo_queue; struct request_queue *q = lo->lo_queue;
u32 granularity, max_discard_sectors;
/* /*
* If the backing device is a block device, mirror its zeroing * If the backing device is a block device, mirror its zeroing
...@@ -890,11 +891,10 @@ static void loop_config_discard(struct loop_device *lo) ...@@ -890,11 +891,10 @@ static void loop_config_discard(struct loop_device *lo)
struct request_queue *backingq; struct request_queue *backingq;
backingq = bdev_get_queue(inode->i_bdev); backingq = bdev_get_queue(inode->i_bdev);
blk_queue_max_discard_sectors(q,
backingq->limits.max_write_zeroes_sectors);
blk_queue_max_write_zeroes_sectors(q, max_discard_sectors = backingq->limits.max_write_zeroes_sectors;
backingq->limits.max_write_zeroes_sectors); granularity = backingq->limits.discard_granularity ?:
queue_physical_block_size(backingq);
/* /*
* We use punch hole to reclaim the free space used by the * We use punch hole to reclaim the free space used by the
...@@ -903,23 +903,26 @@ static void loop_config_discard(struct loop_device *lo) ...@@ -903,23 +903,26 @@ static void loop_config_discard(struct loop_device *lo)
* useful information. * useful information.
*/ */
} else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) { } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) {
q->limits.discard_granularity = 0; max_discard_sectors = 0;
q->limits.discard_alignment = 0; granularity = 0;
blk_queue_max_discard_sectors(q, 0);
blk_queue_max_write_zeroes_sectors(q, 0);
} else { } else {
q->limits.discard_granularity = inode->i_sb->s_blocksize; max_discard_sectors = UINT_MAX >> 9;
q->limits.discard_alignment = 0; granularity = inode->i_sb->s_blocksize;
blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
} }
if (q->limits.max_write_zeroes_sectors) if (max_discard_sectors) {
q->limits.discard_granularity = granularity;
blk_queue_max_discard_sectors(q, max_discard_sectors);
blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
else } else {
q->limits.discard_granularity = 0;
blk_queue_max_discard_sectors(q, 0);
blk_queue_max_write_zeroes_sectors(q, 0);
blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
}
q->limits.discard_alignment = 0;
} }
static void loop_unprepare_queue(struct loop_device *lo) static void loop_unprepare_queue(struct loop_device *lo)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment