diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2012-01-16 15:04:47 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2012-01-16 15:04:47 -0500 |
commit | c9e9f97bdfb64d06e9520f8e4f37674ac21cc9bc (patch) | |
tree | 22d695a7a461068c773b327e5c89a045ade5d8a3 /fs/btrfs/ioctl.c | |
parent | 10ea00f55a07f8f9536d9112b95108a86f700bab (diff) |
Btrfs: add basic restriper infrastructure
Add basic restriper infrastructure: extended balancing ioctl and all
related ioctl data structures, add data structure for tracking
restriper's state to fs_info, etc. The semantics of the old balancing
ioctl are fully preserved.
Explicitly disallow any volume operations when balance is in progress.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 135 |
1 files changed, 119 insertions, 16 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index c04f02c7d5bb..d838d2cfb947 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1203,13 +1203,21 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1203 | if (!capable(CAP_SYS_ADMIN)) | 1203 | if (!capable(CAP_SYS_ADMIN)) |
1204 | return -EPERM; | 1204 | return -EPERM; |
1205 | 1205 | ||
1206 | mutex_lock(&root->fs_info->volume_mutex); | ||
1207 | if (root->fs_info->balance_ctl) { | ||
1208 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
1209 | ret = -EINVAL; | ||
1210 | goto out; | ||
1211 | } | ||
1212 | |||
1206 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1213 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
1207 | if (IS_ERR(vol_args)) | 1214 | if (IS_ERR(vol_args)) { |
1208 | return PTR_ERR(vol_args); | 1215 | ret = PTR_ERR(vol_args); |
1216 | goto out; | ||
1217 | } | ||
1209 | 1218 | ||
1210 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 1219 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
1211 | 1220 | ||
1212 | mutex_lock(&root->fs_info->volume_mutex); | ||
1213 | sizestr = vol_args->name; | 1221 | sizestr = vol_args->name; |
1214 | devstr = strchr(sizestr, ':'); | 1222 | devstr = strchr(sizestr, ':'); |
1215 | if (devstr) { | 1223 | if (devstr) { |
@@ -1226,7 +1234,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1226 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", | 1234 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", |
1227 | (unsigned long long)devid); | 1235 | (unsigned long long)devid); |
1228 | ret = -EINVAL; | 1236 | ret = -EINVAL; |
1229 | goto out_unlock; | 1237 | goto out_free; |
1230 | } | 1238 | } |
1231 | if (!strcmp(sizestr, "max")) | 1239 | if (!strcmp(sizestr, "max")) |
1232 | new_size = device->bdev->bd_inode->i_size; | 1240 | new_size = device->bdev->bd_inode->i_size; |
@@ -1241,7 +1249,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1241 | new_size = memparse(sizestr, NULL); | 1249 | new_size = memparse(sizestr, NULL); |
1242 | if (new_size == 0) { | 1250 | if (new_size == 0) { |
1243 | ret = -EINVAL; | 1251 | ret = -EINVAL; |
1244 | goto out_unlock; | 1252 | goto out_free; |
1245 | } | 1253 | } |
1246 | } | 1254 | } |
1247 | 1255 | ||
@@ -1250,7 +1258,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1250 | if (mod < 0) { | 1258 | if (mod < 0) { |
1251 | if (new_size > old_size) { | 1259 | if (new_size > old_size) { |
1252 | ret = -EINVAL; | 1260 | ret = -EINVAL; |
1253 | goto out_unlock; | 1261 | goto out_free; |
1254 | } | 1262 | } |
1255 | new_size = old_size - new_size; | 1263 | new_size = old_size - new_size; |
1256 | } else if (mod > 0) { | 1264 | } else if (mod > 0) { |
@@ -1259,11 +1267,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1259 | 1267 | ||
1260 | if (new_size < 256 * 1024 * 1024) { | 1268 | if (new_size < 256 * 1024 * 1024) { |
1261 | ret = -EINVAL; | 1269 | ret = -EINVAL; |
1262 | goto out_unlock; | 1270 | goto out_free; |
1263 | } | 1271 | } |
1264 | if (new_size > device->bdev->bd_inode->i_size) { | 1272 | if (new_size > device->bdev->bd_inode->i_size) { |
1265 | ret = -EFBIG; | 1273 | ret = -EFBIG; |
1266 | goto out_unlock; | 1274 | goto out_free; |
1267 | } | 1275 | } |
1268 | 1276 | ||
1269 | do_div(new_size, root->sectorsize); | 1277 | do_div(new_size, root->sectorsize); |
@@ -1276,7 +1284,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1276 | trans = btrfs_start_transaction(root, 0); | 1284 | trans = btrfs_start_transaction(root, 0); |
1277 | if (IS_ERR(trans)) { | 1285 | if (IS_ERR(trans)) { |
1278 | ret = PTR_ERR(trans); | 1286 | ret = PTR_ERR(trans); |
1279 | goto out_unlock; | 1287 | goto out_free; |
1280 | } | 1288 | } |
1281 | ret = btrfs_grow_device(trans, device, new_size); | 1289 | ret = btrfs_grow_device(trans, device, new_size); |
1282 | btrfs_commit_transaction(trans, root); | 1290 | btrfs_commit_transaction(trans, root); |
@@ -1284,9 +1292,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1284 | ret = btrfs_shrink_device(device, new_size); | 1292 | ret = btrfs_shrink_device(device, new_size); |
1285 | } | 1293 | } |
1286 | 1294 | ||
1287 | out_unlock: | 1295 | out_free: |
1288 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1289 | kfree(vol_args); | 1296 | kfree(vol_args); |
1297 | out: | ||
1298 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1290 | return ret; | 1299 | return ret; |
1291 | } | 1300 | } |
1292 | 1301 | ||
@@ -2052,14 +2061,25 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) | |||
2052 | if (!capable(CAP_SYS_ADMIN)) | 2061 | if (!capable(CAP_SYS_ADMIN)) |
2053 | return -EPERM; | 2062 | return -EPERM; |
2054 | 2063 | ||
2064 | mutex_lock(&root->fs_info->volume_mutex); | ||
2065 | if (root->fs_info->balance_ctl) { | ||
2066 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
2067 | ret = -EINVAL; | ||
2068 | goto out; | ||
2069 | } | ||
2070 | |||
2055 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2071 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2056 | if (IS_ERR(vol_args)) | 2072 | if (IS_ERR(vol_args)) { |
2057 | return PTR_ERR(vol_args); | 2073 | ret = PTR_ERR(vol_args); |
2074 | goto out; | ||
2075 | } | ||
2058 | 2076 | ||
2059 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 2077 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
2060 | ret = btrfs_init_new_device(root, vol_args->name); | 2078 | ret = btrfs_init_new_device(root, vol_args->name); |
2061 | 2079 | ||
2062 | kfree(vol_args); | 2080 | kfree(vol_args); |
2081 | out: | ||
2082 | mutex_unlock(&root->fs_info->volume_mutex); | ||
2063 | return ret; | 2083 | return ret; |
2064 | } | 2084 | } |
2065 | 2085 | ||
@@ -2074,14 +2094,25 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
2074 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 2094 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
2075 | return -EROFS; | 2095 | return -EROFS; |
2076 | 2096 | ||
2097 | mutex_lock(&root->fs_info->volume_mutex); | ||
2098 | if (root->fs_info->balance_ctl) { | ||
2099 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
2100 | ret = -EINVAL; | ||
2101 | goto out; | ||
2102 | } | ||
2103 | |||
2077 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2104 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2078 | if (IS_ERR(vol_args)) | 2105 | if (IS_ERR(vol_args)) { |
2079 | return PTR_ERR(vol_args); | 2106 | ret = PTR_ERR(vol_args); |
2107 | goto out; | ||
2108 | } | ||
2080 | 2109 | ||
2081 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 2110 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
2082 | ret = btrfs_rm_device(root, vol_args->name); | 2111 | ret = btrfs_rm_device(root, vol_args->name); |
2083 | 2112 | ||
2084 | kfree(vol_args); | 2113 | kfree(vol_args); |
2114 | out: | ||
2115 | mutex_unlock(&root->fs_info->volume_mutex); | ||
2085 | return ret; | 2116 | return ret; |
2086 | } | 2117 | } |
2087 | 2118 | ||
@@ -3034,6 +3065,76 @@ out: | |||
3034 | return ret; | 3065 | return ret; |
3035 | } | 3066 | } |
3036 | 3067 | ||
3068 | void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, | ||
3069 | struct btrfs_ioctl_balance_args *bargs) | ||
3070 | { | ||
3071 | struct btrfs_balance_control *bctl = fs_info->balance_ctl; | ||
3072 | |||
3073 | bargs->flags = bctl->flags; | ||
3074 | |||
3075 | memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); | ||
3076 | memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); | ||
3077 | memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); | ||
3078 | } | ||
3079 | |||
3080 | static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg) | ||
3081 | { | ||
3082 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
3083 | struct btrfs_ioctl_balance_args *bargs; | ||
3084 | struct btrfs_balance_control *bctl; | ||
3085 | int ret; | ||
3086 | |||
3087 | if (!capable(CAP_SYS_ADMIN)) | ||
3088 | return -EPERM; | ||
3089 | |||
3090 | if (fs_info->sb->s_flags & MS_RDONLY) | ||
3091 | return -EROFS; | ||
3092 | |||
3093 | mutex_lock(&fs_info->volume_mutex); | ||
3094 | mutex_lock(&fs_info->balance_mutex); | ||
3095 | |||
3096 | if (arg) { | ||
3097 | bargs = memdup_user(arg, sizeof(*bargs)); | ||
3098 | if (IS_ERR(bargs)) { | ||
3099 | ret = PTR_ERR(bargs); | ||
3100 | goto out; | ||
3101 | } | ||
3102 | } else { | ||
3103 | bargs = NULL; | ||
3104 | } | ||
3105 | |||
3106 | bctl = kzalloc(sizeof(*bctl), GFP_NOFS); | ||
3107 | if (!bctl) { | ||
3108 | ret = -ENOMEM; | ||
3109 | goto out_bargs; | ||
3110 | } | ||
3111 | |||
3112 | bctl->fs_info = fs_info; | ||
3113 | if (arg) { | ||
3114 | memcpy(&bctl->data, &bargs->data, sizeof(bctl->data)); | ||
3115 | memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta)); | ||
3116 | memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys)); | ||
3117 | |||
3118 | bctl->flags = bargs->flags; | ||
3119 | } | ||
3120 | |||
3121 | ret = btrfs_balance(bctl, bargs); | ||
3122 | /* | ||
3123 | * bctl is freed in __cancel_balance | ||
3124 | */ | ||
3125 | if (arg) { | ||
3126 | if (copy_to_user(arg, bargs, sizeof(*bargs))) | ||
3127 | ret = -EFAULT; | ||
3128 | } | ||
3129 | |||
3130 | out_bargs: | ||
3131 | kfree(bargs); | ||
3132 | out: | ||
3133 | mutex_unlock(&fs_info->balance_mutex); | ||
3134 | mutex_unlock(&fs_info->volume_mutex); | ||
3135 | return ret; | ||
3136 | } | ||
3137 | |||
3037 | long btrfs_ioctl(struct file *file, unsigned int | 3138 | long btrfs_ioctl(struct file *file, unsigned int |
3038 | cmd, unsigned long arg) | 3139 | cmd, unsigned long arg) |
3039 | { | 3140 | { |
@@ -3078,7 +3179,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3078 | case BTRFS_IOC_DEV_INFO: | 3179 | case BTRFS_IOC_DEV_INFO: |
3079 | return btrfs_ioctl_dev_info(root, argp); | 3180 | return btrfs_ioctl_dev_info(root, argp); |
3080 | case BTRFS_IOC_BALANCE: | 3181 | case BTRFS_IOC_BALANCE: |
3081 | return btrfs_balance(root->fs_info->dev_root); | 3182 | return btrfs_ioctl_balance(root, NULL); |
3082 | case BTRFS_IOC_CLONE: | 3183 | case BTRFS_IOC_CLONE: |
3083 | return btrfs_ioctl_clone(file, arg, 0, 0, 0); | 3184 | return btrfs_ioctl_clone(file, arg, 0, 0, 0); |
3084 | case BTRFS_IOC_CLONE_RANGE: | 3185 | case BTRFS_IOC_CLONE_RANGE: |
@@ -3110,6 +3211,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3110 | return btrfs_ioctl_scrub_cancel(root, argp); | 3211 | return btrfs_ioctl_scrub_cancel(root, argp); |
3111 | case BTRFS_IOC_SCRUB_PROGRESS: | 3212 | case BTRFS_IOC_SCRUB_PROGRESS: |
3112 | return btrfs_ioctl_scrub_progress(root, argp); | 3213 | return btrfs_ioctl_scrub_progress(root, argp); |
3214 | case BTRFS_IOC_BALANCE_V2: | ||
3215 | return btrfs_ioctl_balance(root, argp); | ||
3113 | } | 3216 | } |
3114 | 3217 | ||
3115 | return -ENOTTY; | 3218 | return -ENOTTY; |