block: ioctl to zero block ranges
[cascardo/linux.git] / block / ioctl.c
index 4476e0e..769d296 100644 (file)
@@ -185,6 +185,22 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
        return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
 }
 
+static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start,
+                            uint64_t len)
+{
+       if (start & 511)
+               return -EINVAL;
+       if (len & 511)
+               return -EINVAL;
+       start >>= 9;
+       len >>= 9;
+
+       if (start + len > (i_size_read(bdev->bd_inode) >> 9))
+               return -EINVAL;
+
+       return blkdev_issue_zeroout(bdev, start, len, GFP_KERNEL);
+}
+
 static int put_ushort(unsigned long arg, unsigned short val)
 {
        return put_user(val, (unsigned short __user *)arg);
@@ -300,6 +316,17 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                return blk_ioctl_discard(bdev, range[0], range[1],
                                         cmd == BLKSECDISCARD);
        }
+       case BLKZEROOUT: {
+               uint64_t range[2];
+
+               if (!(mode & FMODE_WRITE))
+                       return -EBADF;
+
+               if (copy_from_user(range, (void __user *)arg, sizeof(range)))
+                       return -EFAULT;
+
+               return blk_ioctl_zeroout(bdev, range[0], range[1]);
+       }
 
        case HDIO_GETGEO: {
                struct hd_geometry geo;