diff options
author | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2013-04-25 12:04:51 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-05-06 15:55:19 -0400 |
commit | 2f2320360b0c35b86938bfc561124474f0dac6e4 (patch) | |
tree | f7b1cbec89d9c6d030f15817e77ee42e5941244a /fs/btrfs/ioctl.c | |
parent | 46b665ceb1edd2ac149ff701313c115f52dc0348 (diff) |
Btrfs: rescan for qgroups
If qgroup tracking is out of sync, a rescan operation can be started. It
iterates the complete extent tree and recalculates all qgroup tracking data.
This is an expensive operation and should not be used unless required.
A filesystem under rescan can still be umounted. The rescan continues on the
next mount. Status information is provided with a separate ioctl while a
rescan operation is in progress.
Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 83 |
1 files changed, 69 insertions, 14 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index a74edc797531..f5f6af338b53 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3701,12 +3701,10 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) | |||
3701 | } | 3701 | } |
3702 | 3702 | ||
3703 | down_write(&root->fs_info->subvol_sem); | 3703 | down_write(&root->fs_info->subvol_sem); |
3704 | if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) { | 3704 | trans = btrfs_start_transaction(root->fs_info->tree_root, 2); |
3705 | trans = btrfs_start_transaction(root->fs_info->tree_root, 2); | 3705 | if (IS_ERR(trans)) { |
3706 | if (IS_ERR(trans)) { | 3706 | ret = PTR_ERR(trans); |
3707 | ret = PTR_ERR(trans); | 3707 | goto out; |
3708 | goto out; | ||
3709 | } | ||
3710 | } | 3708 | } |
3711 | 3709 | ||
3712 | switch (sa->cmd) { | 3710 | switch (sa->cmd) { |
@@ -3716,9 +3714,6 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) | |||
3716 | case BTRFS_QUOTA_CTL_DISABLE: | 3714 | case BTRFS_QUOTA_CTL_DISABLE: |
3717 | ret = btrfs_quota_disable(trans, root->fs_info); | 3715 | ret = btrfs_quota_disable(trans, root->fs_info); |
3718 | break; | 3716 | break; |
3719 | case BTRFS_QUOTA_CTL_RESCAN: | ||
3720 | ret = btrfs_quota_rescan(root->fs_info); | ||
3721 | break; | ||
3722 | default: | 3717 | default: |
3723 | ret = -EINVAL; | 3718 | ret = -EINVAL; |
3724 | break; | 3719 | break; |
@@ -3727,11 +3722,9 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) | |||
3727 | if (copy_to_user(arg, sa, sizeof(*sa))) | 3722 | if (copy_to_user(arg, sa, sizeof(*sa))) |
3728 | ret = -EFAULT; | 3723 | ret = -EFAULT; |
3729 | 3724 | ||
3730 | if (trans) { | 3725 | err = btrfs_commit_transaction(trans, root->fs_info->tree_root); |
3731 | err = btrfs_commit_transaction(trans, root->fs_info->tree_root); | 3726 | if (err && !ret) |
3732 | if (err && !ret) | 3727 | ret = err; |
3733 | ret = err; | ||
3734 | } | ||
3735 | out: | 3728 | out: |
3736 | kfree(sa); | 3729 | kfree(sa); |
3737 | up_write(&root->fs_info->subvol_sem); | 3730 | up_write(&root->fs_info->subvol_sem); |
@@ -3886,6 +3879,64 @@ drop_write: | |||
3886 | return ret; | 3879 | return ret; |
3887 | } | 3880 | } |
3888 | 3881 | ||
3882 | static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg) | ||
3883 | { | ||
3884 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
3885 | struct btrfs_ioctl_quota_rescan_args *qsa; | ||
3886 | int ret; | ||
3887 | |||
3888 | if (!capable(CAP_SYS_ADMIN)) | ||
3889 | return -EPERM; | ||
3890 | |||
3891 | ret = mnt_want_write_file(file); | ||
3892 | if (ret) | ||
3893 | return ret; | ||
3894 | |||
3895 | qsa = memdup_user(arg, sizeof(*qsa)); | ||
3896 | if (IS_ERR(qsa)) { | ||
3897 | ret = PTR_ERR(qsa); | ||
3898 | goto drop_write; | ||
3899 | } | ||
3900 | |||
3901 | if (qsa->flags) { | ||
3902 | ret = -EINVAL; | ||
3903 | goto out; | ||
3904 | } | ||
3905 | |||
3906 | ret = btrfs_qgroup_rescan(root->fs_info); | ||
3907 | |||
3908 | out: | ||
3909 | kfree(qsa); | ||
3910 | drop_write: | ||
3911 | mnt_drop_write_file(file); | ||
3912 | return ret; | ||
3913 | } | ||
3914 | |||
3915 | static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg) | ||
3916 | { | ||
3917 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
3918 | struct btrfs_ioctl_quota_rescan_args *qsa; | ||
3919 | int ret = 0; | ||
3920 | |||
3921 | if (!capable(CAP_SYS_ADMIN)) | ||
3922 | return -EPERM; | ||
3923 | |||
3924 | qsa = kzalloc(sizeof(*qsa), GFP_NOFS); | ||
3925 | if (!qsa) | ||
3926 | return -ENOMEM; | ||
3927 | |||
3928 | if (root->fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
3929 | qsa->flags = 1; | ||
3930 | qsa->progress = root->fs_info->qgroup_rescan_progress.objectid; | ||
3931 | } | ||
3932 | |||
3933 | if (copy_to_user(arg, qsa, sizeof(*qsa))) | ||
3934 | ret = -EFAULT; | ||
3935 | |||
3936 | kfree(qsa); | ||
3937 | return ret; | ||
3938 | } | ||
3939 | |||
3889 | static long btrfs_ioctl_set_received_subvol(struct file *file, | 3940 | static long btrfs_ioctl_set_received_subvol(struct file *file, |
3890 | void __user *arg) | 3941 | void __user *arg) |
3891 | { | 3942 | { |
@@ -4124,6 +4175,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
4124 | return btrfs_ioctl_qgroup_create(file, argp); | 4175 | return btrfs_ioctl_qgroup_create(file, argp); |
4125 | case BTRFS_IOC_QGROUP_LIMIT: | 4176 | case BTRFS_IOC_QGROUP_LIMIT: |
4126 | return btrfs_ioctl_qgroup_limit(file, argp); | 4177 | return btrfs_ioctl_qgroup_limit(file, argp); |
4178 | case BTRFS_IOC_QUOTA_RESCAN: | ||
4179 | return btrfs_ioctl_quota_rescan(file, argp); | ||
4180 | case BTRFS_IOC_QUOTA_RESCAN_STATUS: | ||
4181 | return btrfs_ioctl_quota_rescan_status(file, argp); | ||
4127 | case BTRFS_IOC_DEV_REPLACE: | 4182 | case BTRFS_IOC_DEV_REPLACE: |
4128 | return btrfs_ioctl_dev_replace(root, argp); | 4183 | return btrfs_ioctl_dev_replace(root, argp); |
4129 | case BTRFS_IOC_GET_FSLABEL: | 4184 | case BTRFS_IOC_GET_FSLABEL: |