|
@@ -1803,6 +1803,75 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
|
|
|
|
+{
|
|
|
|
+ struct btrfs_ioctl_fs_info_args fi_args;
|
|
|
|
+ struct btrfs_device *device;
|
|
|
|
+ struct btrfs_device *next;
|
|
|
|
+ struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
|
|
|
|
+
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ fi_args.num_devices = fs_devices->num_devices;
|
|
|
|
+ fi_args.max_id = 0;
|
|
|
|
+ memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid));
|
|
|
|
+
|
|
|
|
+ mutex_lock(&fs_devices->device_list_mutex);
|
|
|
|
+ list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
|
|
|
|
+ if (device->devid > fi_args.max_id)
|
|
|
|
+ fi_args.max_id = device->devid;
|
|
|
|
+ }
|
|
|
|
+ mutex_unlock(&fs_devices->device_list_mutex);
|
|
|
|
+
|
|
|
|
+ if (copy_to_user(arg, &fi_args, sizeof(fi_args)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
|
|
|
|
+{
|
|
|
|
+ struct btrfs_ioctl_dev_info_args *di_args;
|
|
|
|
+ struct btrfs_device *dev;
|
|
|
|
+ struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
|
|
|
|
+ int ret = 0;
|
|
|
|
+ char *s_uuid = NULL;
|
|
|
|
+ char empty_uuid[BTRFS_UUID_SIZE] = {0};
|
|
|
|
+
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ di_args = memdup_user(arg, sizeof(*di_args));
|
|
|
|
+ if (IS_ERR(di_args))
|
|
|
|
+ return PTR_ERR(di_args);
|
|
|
|
+
|
|
|
|
+ if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
|
|
|
|
+ s_uuid = di_args->uuid;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&fs_devices->device_list_mutex);
|
|
|
|
+ dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
|
|
|
|
+ mutex_unlock(&fs_devices->device_list_mutex);
|
|
|
|
+
|
|
|
|
+ if (!dev) {
|
|
|
|
+ ret = -ENODEV;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ di_args->devid = dev->devid;
|
|
|
|
+ di_args->bytes_used = dev->bytes_used;
|
|
|
|
+ di_args->total_bytes = dev->total_bytes;
|
|
|
|
+ memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
|
|
|
|
+ strncpy(di_args->path, dev->name, sizeof(di_args->path));
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args)))
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+
|
|
|
|
+ kfree(di_args);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|
u64 off, u64 olen, u64 destoff)
|
|
u64 off, u64 olen, u64 destoff)
|
|
{
|
|
{
|
|
@@ -2465,6 +2534,58 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
|
|
return btrfs_wait_for_commit(root, transid);
|
|
return btrfs_wait_for_commit(root, transid);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ struct btrfs_ioctl_scrub_args *sa;
|
|
|
|
+
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ sa = memdup_user(arg, sizeof(*sa));
|
|
|
|
+ if (IS_ERR(sa))
|
|
|
|
+ return PTR_ERR(sa);
|
|
|
|
+
|
|
|
|
+ ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
|
|
|
|
+ &sa->progress);
|
|
|
|
+
|
|
|
|
+ if (copy_to_user(arg, sa, sizeof(*sa)))
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+
|
|
|
|
+ kfree(sa);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
|
|
|
|
+{
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ return btrfs_scrub_cancel(root);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
|
|
|
|
+ void __user *arg)
|
|
|
|
+{
|
|
|
|
+ struct btrfs_ioctl_scrub_args *sa;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ sa = memdup_user(arg, sizeof(*sa));
|
|
|
|
+ if (IS_ERR(sa))
|
|
|
|
+ return PTR_ERR(sa);
|
|
|
|
+
|
|
|
|
+ ret = btrfs_scrub_progress(root, sa->devid, &sa->progress);
|
|
|
|
+
|
|
|
|
+ if (copy_to_user(arg, sa, sizeof(*sa)))
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+
|
|
|
|
+ kfree(sa);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
long btrfs_ioctl(struct file *file, unsigned int
|
|
long btrfs_ioctl(struct file *file, unsigned int
|
|
cmd, unsigned long arg)
|
|
cmd, unsigned long arg)
|
|
{
|
|
{
|
|
@@ -2504,6 +2625,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|
return btrfs_ioctl_add_dev(root, argp);
|
|
return btrfs_ioctl_add_dev(root, argp);
|
|
case BTRFS_IOC_RM_DEV:
|
|
case BTRFS_IOC_RM_DEV:
|
|
return btrfs_ioctl_rm_dev(root, argp);
|
|
return btrfs_ioctl_rm_dev(root, argp);
|
|
|
|
+ case BTRFS_IOC_FS_INFO:
|
|
|
|
+ return btrfs_ioctl_fs_info(root, argp);
|
|
|
|
+ case BTRFS_IOC_DEV_INFO:
|
|
|
|
+ return btrfs_ioctl_dev_info(root, argp);
|
|
case BTRFS_IOC_BALANCE:
|
|
case BTRFS_IOC_BALANCE:
|
|
return btrfs_balance(root->fs_info->dev_root);
|
|
return btrfs_balance(root->fs_info->dev_root);
|
|
case BTRFS_IOC_CLONE:
|
|
case BTRFS_IOC_CLONE:
|
|
@@ -2527,6 +2652,12 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|
return btrfs_ioctl_start_sync(file, argp);
|
|
return btrfs_ioctl_start_sync(file, argp);
|
|
case BTRFS_IOC_WAIT_SYNC:
|
|
case BTRFS_IOC_WAIT_SYNC:
|
|
return btrfs_ioctl_wait_sync(file, argp);
|
|
return btrfs_ioctl_wait_sync(file, argp);
|
|
|
|
+ case BTRFS_IOC_SCRUB:
|
|
|
|
+ return btrfs_ioctl_scrub(root, argp);
|
|
|
|
+ case BTRFS_IOC_SCRUB_CANCEL:
|
|
|
|
+ return btrfs_ioctl_scrub_cancel(root, argp);
|
|
|
|
+ case BTRFS_IOC_SCRUB_PROGRESS:
|
|
|
|
+ return btrfs_ioctl_scrub_progress(root, argp);
|
|
}
|
|
}
|
|
|
|
|
|
return -ENOTTY;
|
|
return -ENOTTY;
|