linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] loop: fix zero sized loop for block special file
@ 2025-08-25  9:32 Yu Kuai
  2025-08-25 10:48 ` Christoph Hellwig
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Yu Kuai @ 2025-08-25  9:32 UTC (permalink / raw)
  To: ming.lei, hch, axboe, yukuai3, rajeevm
  Cc: linux-block, linux-kernel, yukuai1, yi.zhang, yangerkun,
	johnny.chenyi

From: Yu Kuai <yukuai3@huawei.com>

By default, /dev/sda is block specail file from devtmpfs, getattr will
return file size as zero, causing loop failed for raw block device.

We can add bdev_statx() to return device size, however this may introduce
changes that are not acknowledged by user. Fix this problem by reverting
changes for block special file, file mapping host is set to bdev inode
while opening, and use i_size_read() directly to get device size.

Fixes: 47b71abd5846 ("loop: use vfs_getattr_nosec for accurate file size")
Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202508200409.b2459c02-lkp@intel.com
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
---
Changes in v2:
 - don't call vfs_getattr_nosec() for block special file path, by Ming

 drivers/block/loop.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 57263c273f0f..053a086d547e 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -139,20 +139,26 @@ static int part_shift;
 
 static loff_t lo_calculate_size(struct loop_device *lo, struct file *file)
 {
-	struct kstat stat;
 	loff_t loopsize;
 	int ret;
 
-	/*
-	 * Get the accurate file size. This provides better results than
-	 * cached inode data, particularly for network filesystems where
-	 * metadata may be stale.
-	 */
-	ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0);
-	if (ret)
-		return 0;
+	if (S_ISBLK(file_inode(file)->i_mode)) {
+		loopsize = i_size_read(file->f_mapping->host);
+	} else {
+		struct kstat stat;
+
+		/*
+		 * Get the accurate file size. This provides better results than
+		 * cached inode data, particularly for network filesystems where
+		 * metadata may be stale.
+		 */
+		ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0);
+		if (ret)
+			return 0;
+
+		loopsize = stat.size;
+	}
 
-	loopsize = stat.size;
 	if (lo->lo_offset > 0)
 		loopsize -= lo->lo_offset;
 	/* offset is beyond i_size, weird but possible */
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] loop: fix zero sized loop for block special file
  2025-08-25  9:32 [PATCH v2] loop: fix zero sized loop for block special file Yu Kuai
@ 2025-08-25 10:48 ` Christoph Hellwig
  2025-08-25 11:26 ` Ming Lei
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2025-08-25 10:48 UTC (permalink / raw)
  To: Yu Kuai
  Cc: ming.lei, hch, axboe, yukuai3, rajeevm, linux-block, linux-kernel,
	yi.zhang, yangerkun, johnny.chenyi

On Mon, Aug 25, 2025 at 05:32:05PM +0800, Yu Kuai wrote:
> From: Yu Kuai <yukuai3@huawei.com>
> 
> By default, /dev/sda is block specail file from devtmpfs, getattr will

s/specail/special/

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] loop: fix zero sized loop for block special file
  2025-08-25  9:32 [PATCH v2] loop: fix zero sized loop for block special file Yu Kuai
  2025-08-25 10:48 ` Christoph Hellwig
@ 2025-08-25 11:26 ` Ming Lei
  2025-08-25 13:47 ` Jens Axboe
  2025-08-25 13:56 ` Jens Axboe
  3 siblings, 0 replies; 6+ messages in thread
From: Ming Lei @ 2025-08-25 11:26 UTC (permalink / raw)
  To: Yu Kuai
  Cc: hch, axboe, yukuai3, rajeevm, linux-block, linux-kernel, yi.zhang,
	yangerkun, johnny.chenyi

On Mon, Aug 25, 2025 at 5:40 PM Yu Kuai <yukuai1@huaweicloud.com> wrote:
>
> From: Yu Kuai <yukuai3@huawei.com>
>
> By default, /dev/sda is block specail file from devtmpfs, getattr will
> return file size as zero, causing loop failed for raw block device.
>
> We can add bdev_statx() to return device size, however this may introduce
> changes that are not acknowledged by user. Fix this problem by reverting
> changes for block special file, file mapping host is set to bdev inode
> while opening, and use i_size_read() directly to get device size.
>
> Fixes: 47b71abd5846 ("loop: use vfs_getattr_nosec for accurate file size")
> Reported-by: kernel test robot <oliver.sang@intel.com>
> Closes: https://lore.kernel.org/oe-lkp/202508200409.b2459c02-lkp@intel.com
> Signed-off-by: Yu Kuai <yukuai3@huawei.com>
> ---
> Changes in v2:
>  - don't call vfs_getattr_nosec() for block special file path, by Ming

Reviewed-by: Ming Lei <ming.lei@redhat.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] loop: fix zero sized loop for block special file
  2025-08-25  9:32 [PATCH v2] loop: fix zero sized loop for block special file Yu Kuai
  2025-08-25 10:48 ` Christoph Hellwig
  2025-08-25 11:26 ` Ming Lei
@ 2025-08-25 13:47 ` Jens Axboe
  2025-08-25 13:56 ` Jens Axboe
  3 siblings, 0 replies; 6+ messages in thread
From: Jens Axboe @ 2025-08-25 13:47 UTC (permalink / raw)
  To: ming.lei, hch, yukuai3, rajeevm, Yu Kuai
  Cc: linux-block, linux-kernel, yi.zhang, yangerkun, johnny.chenyi


On Mon, 25 Aug 2025 17:32:05 +0800, Yu Kuai wrote:
> By default, /dev/sda is block specail file from devtmpfs, getattr will
> return file size as zero, causing loop failed for raw block device.
> 
> We can add bdev_statx() to return device size, however this may introduce
> changes that are not acknowledged by user. Fix this problem by reverting
> changes for block special file, file mapping host is set to bdev inode
> while opening, and use i_size_read() directly to get device size.
> 
> [...]

Applied, thanks!

[1/1] loop: fix zero sized loop for block special file
      commit: d14469ed7c00314fe8957b2841bda329e4eaf4ab

Best regards,
-- 
Jens Axboe




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] loop: fix zero sized loop for block special file
  2025-08-25  9:32 [PATCH v2] loop: fix zero sized loop for block special file Yu Kuai
                   ` (2 preceding siblings ...)
  2025-08-25 13:47 ` Jens Axboe
@ 2025-08-25 13:56 ` Jens Axboe
  2025-08-25 18:17   ` Cloud User
  3 siblings, 1 reply; 6+ messages in thread
From: Jens Axboe @ 2025-08-25 13:56 UTC (permalink / raw)
  To: Yu Kuai, ming.lei, hch, yukuai3, rajeevm
  Cc: linux-block, linux-kernel, yi.zhang, yangerkun, johnny.chenyi

On 8/25/25 3:32 AM, Yu Kuai wrote:
>  static loff_t lo_calculate_size(struct loop_device *lo, struct file *file)
>  {
> -	struct kstat stat;
>  	loff_t loopsize;
>  	int ret;
>  
> -	/*
> -	 * Get the accurate file size. This provides better results than
> -	 * cached inode data, particularly for network filesystems where
> -	 * metadata may be stale.
> -	 */
> -	ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0);
> -	if (ret)
> -		return 0;
> +	if (S_ISBLK(file_inode(file)->i_mode)) {
> +		loopsize = i_size_read(file->f_mapping->host);
> +	} else {
> +		struct kstat stat;
> +
> +		/*
> +		 * Get the accurate file size. This provides better results than
> +		 * cached inode data, particularly for network filesystems where
> +		 * metadata may be stale.
> +		 */
> +		ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0);
> +		if (ret)
> +			return 0;
> +
> +		loopsize = stat.size;
> +	}

Gah, that was pretty silly...

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] loop: fix zero sized loop for block special file
  2025-08-25 13:56 ` Jens Axboe
@ 2025-08-25 18:17   ` Cloud User
  0 siblings, 0 replies; 6+ messages in thread
From: Cloud User @ 2025-08-25 18:17 UTC (permalink / raw)
  To: yukuai1, ming.lei, hch, yukuai3, rajeevm
  Cc: linux-block, linux-kernel, yi.zhang, yangerkun, johnny.chenyi



Hi Jens, Kuai,

Thank you for your feedback, and apologies for the delay.

I will send the v5 patch in two parts as before.
The final commit will include the fix you suggested.
Below is the final git diff; the key change is the added ISBLK check.

Best regards,
Rajeev Mishra

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1b6ee91f8eb9..1e81620c0c72 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -137,20 +137,33 @@ static void loop_global_unlock(struct loop_device *lo, bool global)
 static int max_part;
 static int part_shift;
 
-static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file)
+static loff_t lo_calculate_size(struct loop_device *lo, struct file *file)
 {
+	struct kstat stat;
 	loff_t loopsize;
+	int ret;
 
-	/* Compute loopsize in bytes */
-	loopsize = i_size_read(file->f_mapping->host);
-	if (offset > 0)
-		loopsize -= offset;
+	/*
+	 * Get the accurate file size. This provides better results than
+	 * cached inode data, particularly for network filesystems where
+	 * metadata may be stale.
+	 */
+	if (S_ISBLK(file->f_inode->i_mode)) {
+		loopsize = i_size_read(file->f_mapping->host);
+	} else {
+		ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0);
+		if (ret)
+		      return 0;
+		loopsize = stat.size;
+	}
+
+	if (lo->lo_offset > 0)
+		loopsize -= lo->lo_offset;
 	/* offset is beyond i_size, weird but possible */
 	if (loopsize < 0)
 		return 0;
-
-	if (sizelimit > 0 && sizelimit < loopsize)
-		loopsize = sizelimit;
+	if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
+		loopsize = lo->lo_sizelimit;
 	/*
 	 * Unfortunately, if we want to do I/O on the device,
 	 * the number of 512-byte sectors has to fit into a sector_t.
@@ -158,11 +171,6 @@ static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file)
 	return loopsize >> 9;
 }
 
-static loff_t get_loop_size(struct loop_device *lo, struct file *file)
-{
-	return get_size(lo->lo_offset, lo->lo_sizelimit, file);
-}
-
 /*
  * We support direct I/O only if lo_offset is aligned with the logical I/O size
  * of backing device, and the logical block size of loop is bigger than that of
@@ -569,7 +577,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
 	error = -EINVAL;
 
 	/* size of the new backing store needs to be the same */
-	if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
+	if (lo_calculate_size(lo, file) != lo_calculate_size(lo, old_file))
 		goto out_err;
 
 	/*
@@ -1063,7 +1071,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
 	loop_update_dio(lo);
 	loop_sysfs_init(lo);
 
-	size = get_loop_size(lo, file);
+	size = lo_calculate_size(lo, file);
 	loop_set_size(lo, size);
 
 	/* Order wrt reading lo_state in loop_validate_file(). */
@@ -1255,8 +1263,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 	if (partscan)
 		clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state);
 	if (!err && size_changed) {
-		loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit,
-					   lo->lo_backing_file);
+		loff_t new_size = lo_calculate_size(lo, lo->lo_backing_file);
 		loop_set_size(lo, new_size);
 	}
 out_unlock:
@@ -1399,7 +1406,7 @@ static int loop_set_capacity(struct loop_device *lo)
 	if (unlikely(lo->lo_state != Lo_bound))
 		return -ENXIO;
 
-	size = get_loop_size(lo, lo->lo_backing_file);
+	size = lo_calculate_size(lo, lo->lo_backing_file);
 	loop_set_size(lo, size);
 
 	return 0;

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-08-25 18:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-25  9:32 [PATCH v2] loop: fix zero sized loop for block special file Yu Kuai
2025-08-25 10:48 ` Christoph Hellwig
2025-08-25 11:26 ` Ming Lei
2025-08-25 13:47 ` Jens Axboe
2025-08-25 13:56 ` Jens Axboe
2025-08-25 18:17   ` Cloud User

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).