This is a note to let you know that I've just added the patch titled loop: Refactor loop_set_status() size calculation to the 4.19-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: loop-refactor-loop_set_status-size-calculation.patch and it can be found in the queue-4.19 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From stable+bounces-25714-greg=kroah.com@xxxxxxxxxxxxxxx Fri Mar 1 02:33:57 2024 From: Genjian <zhanggenjian@xxxxxxx> Date: Fri, 1 Mar 2024 09:30:24 +0800 Subject: loop: Refactor loop_set_status() size calculation To: stable@xxxxxxxxxxxxxxx Cc: axboe@xxxxxxxxx, stable@xxxxxxxxxx, linux-block@xxxxxxxxxxxxxxx, linux-kernel@xxxxxxxxxxxxxxx, zhanggenjian123@xxxxxxxxx, Martijn Coenen <maco@xxxxxxxxxxx>, Christoph Hellwig <hch@xxxxxx>, Genjian Zhang <zhanggenjian@xxxxxxxxxx> Message-ID: <20240301013028.2293831-6-zhanggenjian@xxxxxxx> From: Martijn Coenen <maco@xxxxxxxxxxx> [ Upstream commit b0bd158dd630bd47640e0e418c062cda1e0da5ad ] figure_loop_size() calculates the loop size based on the passed in parameters, but at the same time it updates the offset and sizelimit parameters in the loop device configuration. That is a somewhat unexpected side effect of a function with this name, and it is only only needed by one of the two callers of this function - loop_set_status(). Move the lo_offset and lo_sizelimit assignment back into loop_set_status(), and use the newly factored out functions to validate and apply the newly calculated size. This allows us to get rid of figure_loop_size() in a follow-up commit. Signed-off-by: Martijn Coenen <maco@xxxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> Signed-off-by: Genjian Zhang <zhanggenjian@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/block/loop.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -248,11 +248,6 @@ figure_loop_size(struct loop_device *lo, { loff_t size = get_size(offset, sizelimit, lo->lo_backing_file); - if (lo->lo_offset != offset) - lo->lo_offset = offset; - if (lo->lo_sizelimit != sizelimit) - lo->lo_sizelimit = sizelimit; - loop_set_size(lo, size); } @@ -1225,6 +1220,7 @@ loop_set_status(struct loop_device *lo, kuid_t uid = current_uid(); struct block_device *bdev; bool partscan = false; + bool size_changed = false; err = mutex_lock_killable(&loop_ctl_mutex); if (err) @@ -1246,6 +1242,7 @@ loop_set_status(struct loop_device *lo, if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) { + size_changed = true; sync_blockdev(lo->lo_device); invalidate_bdev(lo->lo_device); } @@ -1253,6 +1250,15 @@ loop_set_status(struct loop_device *lo, /* I/O need to be drained during transfer transition */ blk_mq_freeze_queue(lo->lo_queue); + if (size_changed && lo->lo_device->bd_inode->i_mapping->nrpages) { + /* If any pages were dirtied after invalidate_bdev(), try again */ + err = -EAGAIN; + pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", + __func__, lo->lo_number, lo->lo_file_name, + lo->lo_device->bd_inode->i_mapping->nrpages); + goto out_unfreeze; + } + err = loop_release_xfer(lo); if (err) goto out_unfreeze; @@ -1276,19 +1282,8 @@ loop_set_status(struct loop_device *lo, if (err) goto out_unfreeze; - if (lo->lo_offset != info->lo_offset || - lo->lo_sizelimit != info->lo_sizelimit) { - /* kill_bdev should have truncated all the pages */ - if (lo->lo_device->bd_inode->i_mapping->nrpages) { - err = -EAGAIN; - pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", - __func__, lo->lo_number, lo->lo_file_name, - lo->lo_device->bd_inode->i_mapping->nrpages); - goto out_unfreeze; - } - figure_loop_size(lo, info->lo_offset, info->lo_sizelimit); - } - + lo->lo_offset = info->lo_offset; + lo->lo_sizelimit = info->lo_sizelimit; memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); memcpy(lo->lo_crypt_name, info->lo_crypt_name, LO_NAME_SIZE); lo->lo_file_name[LO_NAME_SIZE-1] = 0; @@ -1312,6 +1307,12 @@ loop_set_status(struct loop_device *lo, lo->lo_key_owner = uid; } + if (size_changed) { + loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit, + lo->lo_backing_file); + loop_set_size(lo, new_size); + } + loop_config_discard(lo); /* update dio if lo_offset or transfer is changed */ Patches currently in stable-queue which might be from kroah.com@xxxxxxxxxxxxxxx are queue-4.19/loop-factor-out-configuring-loop-from-status.patch queue-4.19/loop-call-loop_config_discard-only-after-new-config-is-applied.patch queue-4.19/loop-refactor-loop_set_status-size-calculation.patch queue-4.19/loop-factor-out-setting-loop-device-size.patch queue-4.19/loop-check-for-overflow-while-configuring-loop.patch queue-4.19/loop-properly-observe-rotational-flag-of-underlying-device.patch queue-4.19/loop-remove-sector_t-truncation-checks.patch queue-4.19/revert-loop-check-for-overflow-while-configuring-loop.patch queue-4.19/loop-loop_set_status_from_info-check-before-assignment.patch