summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_ioctl.c')
-rw-r--r--fs/xfs/xfs_ioctl.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 47151b29a7ae..d5597d7b98c0 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1649,6 +1649,51 @@ xfs_ioc_scrub_metadata(
return 0;
}
+STATIC int
+xfs_ioc_scrubv_metadata(
+ struct file *filp,
+ void __user *arg)
+{
+ struct xfs_scrub_vec_head __user *uhead = arg;
+ struct xfs_scrub_vec_head head;
+ struct xfs_scrub_vec_head *vhead;
+ size_t bytes;
+ int error;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&head, uhead, sizeof(head)))
+ return -EFAULT;
+
+ bytes = sizeof_xfs_scrub_vec(head.svh_nr);
+ if (bytes > PAGE_SIZE)
+ return -ENOMEM;
+ vhead = kvmalloc(bytes, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
+ if (!vhead)
+ return -ENOMEM;
+ memcpy(vhead, &head, sizeof(struct xfs_scrub_vec_head));
+
+ if (copy_from_user(&vhead->svh_vecs, &uhead->svh_vecs,
+ head.svh_nr * sizeof(struct xfs_scrub_vec))) {
+ error = -EFAULT;
+ goto err_free;
+ }
+
+ error = xfs_scrubv_metadata(filp, vhead);
+ if (error)
+ goto err_free;
+
+ if (copy_to_user(uhead, vhead, bytes)) {
+ error = -EFAULT;
+ goto err_free;
+ }
+
+err_free:
+ kvfree(vhead);
+ return error;
+}
+
int
xfs_ioc_swapext(
struct xfs_swapext *sxp)
@@ -1914,6 +1959,8 @@ xfs_file_ioctl(
case FS_IOC_GETFSMAP:
return xfs_ioc_getfsmap(ip, arg);
+ case XFS_IOC_SCRUBV_METADATA:
+ return xfs_ioc_scrubv_metadata(filp, arg);
case XFS_IOC_SCRUB_METADATA:
return xfs_ioc_scrub_metadata(filp, arg);