Commit 7a07210b authored by Pavel Begunkov's avatar Pavel Begunkov Committed by Jens Axboe

block: introduce blk_validate_byte_range()

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: default avatarPavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/19a7779323c71e742a2f511e4cf49efcfd68cfd4.1726072086.git.asml.silence@gmail.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent a12c883a
...@@ -92,41 +92,54 @@ static int compat_blkpg_ioctl(struct block_device *bdev, ...@@ -92,41 +92,54 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
} }
#endif #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, static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
unsigned long arg) unsigned long arg)
{ {
unsigned int bs_mask = bdev_logical_block_size(bdev) - 1; uint64_t range[2], start, len;
uint64_t range[2], start, len, end;
struct bio *prev = NULL, *bio; struct bio *prev = NULL, *bio;
sector_t sector, nr_sects; sector_t sector, nr_sects;
struct blk_plug plug; struct blk_plug plug;
int err; 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))) if (copy_from_user(range, (void __user *)arg, sizeof(range)))
return -EFAULT; return -EFAULT;
start = range[0]; start = range[0];
len = range[1]; len = range[1];
if (!len) if (!bdev_max_discard_sectors(bdev))
return -EINVAL; return -EOPNOTSUPP;
if ((start | len) & bs_mask)
return -EINVAL;
if (check_add_overflow(start, len, &end) || if (!(mode & BLK_OPEN_WRITE))
end > bdev_nr_bytes(bdev)) return -EBADF;
return -EINVAL; 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); 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) if (err)
goto fail; goto fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment