On Tue, Mar 12, 2024 at 08:45:27AM -0600, Christoph Hellwig wrote: > @@ -95,6 +95,8 @@ static int compat_blkpg_ioctl(struct block_device *bdev, > static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, > unsigned long arg) > { > + sector_t bs_mask = (bdev_logical_block_size(bdev) >> SECTOR_SHIFT) - 1; > + sector_t sector, nr_sects; > uint64_t range[2]; > uint64_t start, len; > struct inode *inode = bdev->bd_inode; > @@ -105,18 +107,21 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, > > 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]; > + sector = start >> SECTOR_SHIFT; > + nr_sects = len >> SECTOR_SHIFT; > > - if (start & 511) > + if (!nr_sects) > return -EINVAL; > - if (len & 511) > + if ((sector | nr_sects) & bs_mask) > return -EINVAL; > - > if (start + len > bdev_nr_bytes(bdev)) > return -EINVAL; Maybe you want to shift lower bytes out of consideration, but it is different, right? For example, if I call this ioctl with start=5 and len=555, it would return EINVAL, but your change would let it succeed the same as if start=0, len=512.