aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:47 -0500
committerIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:47 -0500
commitc9e9f97bdfb64d06e9520f8e4f37674ac21cc9bc (patch)
tree22d695a7a461068c773b327e5c89a045ade5d8a3 /fs/btrfs/ioctl.c
parent10ea00f55a07f8f9536d9112b95108a86f700bab (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.c135
1 files changed, 119 insertions, 16 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index c04f02c7d5b..d838d2cfb94 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
1287out_unlock: 1295out_free:
1288 mutex_unlock(&root->fs_info->volume_mutex);
1289 kfree(vol_args); 1296 kfree(vol_args);
1297out:
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);
2081out:
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);
2114out:
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
3068void 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
3080static 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
3130out_bargs:
3131 kfree(bargs);
3132out:
3133 mutex_unlock(&fs_info->balance_mutex);
3134 mutex_unlock(&fs_info->volume_mutex);
3135 return ret;
3136}
3137
3037long btrfs_ioctl(struct file *file, unsigned int 3138long 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;