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

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.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent a12c883a
Loading
Loading
Loading
Loading
+32 −19
Original line number Diff line number Diff line
@@ -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;