loop: refactor queue limits updates

[ Upstream commit b38c8be255e89ffcdeb817407222d2de0b573a41 ]

Replace loop_reconfigure_limits with a slightly less encompassing
loop_update_limits that expects the caller to acquire and commit the
queue limits to prepare for sorting out the freeze vs limits lock
ordering.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Link: https://lore.kernel.org/r/20250110054726.1499538-11-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: f5c84eff634b ("loop: Add sanity check for read/write_iter")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Christoph Hellwig
2025-01-10 06:47:18 +01:00
committed by Greg Kroah-Hartman
parent 0558ce095b
commit 5e1470b276
+20 -16
View File
@@ -901,12 +901,12 @@ static unsigned int loop_default_blocksize(struct loop_device *lo,
return SECTOR_SIZE; return SECTOR_SIZE;
} }
static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize) static void loop_update_limits(struct loop_device *lo, struct queue_limits *lim,
unsigned int bsize)
{ {
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 block_device *backing_bdev = NULL; struct block_device *backing_bdev = NULL;
struct queue_limits lim;
u32 granularity = 0, max_discard_sectors = 0; u32 granularity = 0, max_discard_sectors = 0;
if (S_ISBLK(inode->i_mode)) if (S_ISBLK(inode->i_mode))
@@ -919,22 +919,20 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize)
loop_get_discard_config(lo, &granularity, &max_discard_sectors); loop_get_discard_config(lo, &granularity, &max_discard_sectors);
lim = queue_limits_start_update(lo->lo_queue); lim->logical_block_size = bsize;
lim.logical_block_size = bsize; lim->physical_block_size = bsize;
lim.physical_block_size = bsize; lim->io_min = bsize;
lim.io_min = bsize; lim->features &= ~(BLK_FEAT_WRITE_CACHE | BLK_FEAT_ROTATIONAL);
lim.features &= ~(BLK_FEAT_WRITE_CACHE | BLK_FEAT_ROTATIONAL);
if (file->f_op->fsync && !(lo->lo_flags & LO_FLAGS_READ_ONLY)) if (file->f_op->fsync && !(lo->lo_flags & LO_FLAGS_READ_ONLY))
lim.features |= BLK_FEAT_WRITE_CACHE; lim->features |= BLK_FEAT_WRITE_CACHE;
if (backing_bdev && !bdev_nonrot(backing_bdev)) if (backing_bdev && !bdev_nonrot(backing_bdev))
lim.features |= BLK_FEAT_ROTATIONAL; lim->features |= BLK_FEAT_ROTATIONAL;
lim.max_hw_discard_sectors = max_discard_sectors; lim->max_hw_discard_sectors = max_discard_sectors;
lim.max_write_zeroes_sectors = max_discard_sectors; lim->max_write_zeroes_sectors = max_discard_sectors;
if (max_discard_sectors) if (max_discard_sectors)
lim.discard_granularity = granularity; lim->discard_granularity = granularity;
else else
lim.discard_granularity = 0; lim->discard_granularity = 0;
return queue_limits_commit_update(lo->lo_queue, &lim);
} }
static int loop_configure(struct loop_device *lo, blk_mode_t mode, static int loop_configure(struct loop_device *lo, blk_mode_t mode,
@@ -943,6 +941,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
{ {
struct file *file = fget(config->fd); struct file *file = fget(config->fd);
struct address_space *mapping; struct address_space *mapping;
struct queue_limits lim;
int error; int error;
loff_t size; loff_t size;
bool partscan; bool partscan;
@@ -1014,7 +1013,9 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
lo->old_gfp_mask = mapping_gfp_mask(mapping); lo->old_gfp_mask = mapping_gfp_mask(mapping);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
error = loop_reconfigure_limits(lo, config->block_size); lim = queue_limits_start_update(lo->lo_queue);
loop_update_limits(lo, &lim, config->block_size);
error = queue_limits_commit_update(lo->lo_queue, &lim);
if (error) if (error)
goto out_unlock; goto out_unlock;
@@ -1382,6 +1383,7 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg)
static int loop_set_block_size(struct loop_device *lo, unsigned long arg) static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
{ {
struct queue_limits lim;
int err = 0; int err = 0;
if (lo->lo_state != Lo_bound) if (lo->lo_state != Lo_bound)
@@ -1394,7 +1396,9 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
invalidate_bdev(lo->lo_device); invalidate_bdev(lo->lo_device);
blk_mq_freeze_queue(lo->lo_queue); blk_mq_freeze_queue(lo->lo_queue);
err = loop_reconfigure_limits(lo, arg); lim = queue_limits_start_update(lo->lo_queue);
loop_update_limits(lo, &lim, arg);
err = queue_limits_commit_update(lo->lo_queue, &lim);
loop_update_dio(lo); loop_update_dio(lo);
blk_mq_unfreeze_queue(lo->lo_queue); blk_mq_unfreeze_queue(lo->lo_queue);