block: introduce blk_validate_byte_range()
authorPavel Begunkov <asml.silence@gmail.com>
Wed, 11 Sep 2024 16:34:40 +0000 (17:34 +0100)
committerJens Axboe <axboe@kernel.dk>
Wed, 11 Sep 2024 16:45:07 +0000 (10:45 -0600)
In preparation to further changes extract a helper function out of
blk_ioctl_discard() that validates if we can do IO against the given
range of disk byte addresses.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/19a7779323c71e742a2f511e4cf49efcfd68cfd4.1726072086.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/ioctl.c

index 44257bd..6eaa3f2 100644 (file)
@@ -92,41 +92,54 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
 }
 #endif
 
+/*
+ * Check that [start, start + len) is a valid range from the block device's
+ * perspective, including verifying that it can be correctly translated into
+ * logical block addresses.
+ */
+static int blk_validate_byte_range(struct block_device *bdev,
+                                  uint64_t start, uint64_t len)
+{
+       unsigned int bs_mask = bdev_logical_block_size(bdev) - 1;
+       uint64_t end;
+
+       if ((start | len) & bs_mask)
+               return -EINVAL;
+       if (!len)
+               return -EINVAL;
+       if (check_add_overflow(start, len, &end) || end > bdev_nr_bytes(bdev))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
                unsigned long arg)
 {
-       unsigned int bs_mask = bdev_logical_block_size(bdev) - 1;
-       uint64_t range[2], start, len, end;
+       uint64_t range[2], start, len;
        struct bio *prev = NULL, *bio;
        sector_t sector, nr_sects;
        struct blk_plug plug;
        int err;
 
-       if (!(mode & BLK_OPEN_WRITE))
-               return -EBADF;
-
-       if (!bdev_max_discard_sectors(bdev))
-               return -EOPNOTSUPP;
-       if (bdev_read_only(bdev))
-               return -EPERM;
-
        if (copy_from_user(range, (void __user *)arg, sizeof(range)))
                return -EFAULT;
-
        start = range[0];
        len = range[1];
 
-       if (!len)
-               return -EINVAL;
-       if ((start | len) & bs_mask)
-               return -EINVAL;
+       if (!bdev_max_discard_sectors(bdev))
+               return -EOPNOTSUPP;
 
-       if (check_add_overflow(start, len, &end) ||
-           end > bdev_nr_bytes(bdev))
-               return -EINVAL;
+       if (!(mode & BLK_OPEN_WRITE))
+               return -EBADF;
+       if (bdev_read_only(bdev))
+               return -EPERM;
+       err = blk_validate_byte_range(bdev, start, len);
+       if (err)
+               return err;
 
        filemap_invalidate_lock(bdev->bd_mapping);
-       err = truncate_bdev_range(bdev, mode, start, end - 1);
+       err = truncate_bdev_range(bdev, mode, start, start + len - 1);
        if (err)
                goto fail;