]> www.infradead.org Git - nvme.git/commitdiff
block: Read max write zeroes once for __blkdev_issue_write_zeroes()
authorJohn Garry <john.g.garry@oracle.com>
Thu, 15 Aug 2024 16:32:27 +0000 (16:32 +0000)
committerJens Axboe <axboe@kernel.dk>
Mon, 19 Aug 2024 15:48:59 +0000 (09:48 -0600)
As reported in [0], we may get a hang when formatting a XFS FS on a RAID0
drive.

Commit 73a768d5f955 ("block: factor out a blk_write_zeroes_limit helper")
changed __blkdev_issue_write_zeroes() to read the max write zeroes
value in the loop. This is not safe as max write zeroes may change in
value. Specifically for the case of [0], the value goes to 0, and we get
an infinite loop.

Lift the limit reading out of the loop.

[0] https://lore.kernel.org/linux-xfs/4d31268f-310b-4220-88a2-e191c3932a82@oracle.com/T/#t

Fixes: 73a768d5f955 ("block: factor out a blk_write_zeroes_limit helper")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: John Garry <john.g.garry@oracle.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Link: https://lore.kernel.org/r/20240815163228.216051-2-john.g.garry@oracle.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-lib.c

index 9f735efa6c9459e03f14298382f1c37d31f3b6ab..83eb7761c2bfbd5ef9791e241973b07de7e0b46b 100644 (file)
@@ -111,13 +111,20 @@ static sector_t bio_write_zeroes_limit(struct block_device *bdev)
                (UINT_MAX >> SECTOR_SHIFT) & ~bs_mask);
 }
 
+/*
+ * There is no reliable way for the SCSI subsystem to determine whether a
+ * device supports a WRITE SAME operation without actually performing a write
+ * to media. As a result, write_zeroes is enabled by default and will be
+ * disabled if a zeroing operation subsequently fails. This means that this
+ * queue limit is likely to change at runtime.
+ */
 static void __blkdev_issue_write_zeroes(struct block_device *bdev,
                sector_t sector, sector_t nr_sects, gfp_t gfp_mask,
-               struct bio **biop, unsigned flags)
+               struct bio **biop, unsigned flags, sector_t limit)
 {
+
        while (nr_sects) {
-               unsigned int len = min_t(sector_t, nr_sects,
-                               bio_write_zeroes_limit(bdev));
+               unsigned int len = min(nr_sects, limit);
                struct bio *bio;
 
                if ((flags & BLKDEV_ZERO_KILLABLE) &&
@@ -141,12 +148,14 @@ static void __blkdev_issue_write_zeroes(struct block_device *bdev,
 static int blkdev_issue_write_zeroes(struct block_device *bdev, sector_t sector,
                sector_t nr_sects, gfp_t gfp, unsigned flags)
 {
+       sector_t limit = bio_write_zeroes_limit(bdev);
        struct bio *bio = NULL;
        struct blk_plug plug;
        int ret = 0;
 
        blk_start_plug(&plug);
-       __blkdev_issue_write_zeroes(bdev, sector, nr_sects, gfp, &bio, flags);
+       __blkdev_issue_write_zeroes(bdev, sector, nr_sects, gfp, &bio,
+                       flags, limit);
        if (bio) {
                if ((flags & BLKDEV_ZERO_KILLABLE) &&
                    fatal_signal_pending(current)) {
@@ -165,7 +174,7 @@ static int blkdev_issue_write_zeroes(struct block_device *bdev, sector_t sector,
         * on an I/O error, in which case we'll turn any error into
         * "not supported" here.
         */
-       if (ret && !bdev_write_zeroes_sectors(bdev))
+       if (ret && !limit)
                return -EOPNOTSUPP;
        return ret;
 }
@@ -265,12 +274,14 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
                sector_t nr_sects, gfp_t gfp_mask, struct bio **biop,
                unsigned flags)
 {
+       sector_t limit = bio_write_zeroes_limit(bdev);
+
        if (bdev_read_only(bdev))
                return -EPERM;
 
-       if (bdev_write_zeroes_sectors(bdev)) {
+       if (limit) {
                __blkdev_issue_write_zeroes(bdev, sector, nr_sects,
-                               gfp_mask, biop, flags);
+                               gfp_mask, biop, flags, limit);
        } else {
                if (flags & BLKDEV_ZERO_NOFALLBACK)
                        return -EOPNOTSUPP;