diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-17 18:49:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-17 18:49:54 -0500 |
commit | f9156c7288e2d11501ded4d7fe6d9a3a41ee4057 (patch) | |
tree | 7bd26fc9a111c6af1601ecd2d1b0ab60da32f3f0 /fs/btrfs/ioctl.c | |
parent | 67175b855bfd6ed95ffeff95532173c07de6432d (diff) | |
parent | 96bdc7dc61fb1b1e8e858dafb13abee8482ba064 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (62 commits)
Btrfs: use larger system chunks
Btrfs: add a delalloc mutex to inodes for delalloc reservations
Btrfs: space leak tracepoints
Btrfs: protect orphan block rsv with spin_lock
Btrfs: add allocator tracepoints
Btrfs: don't call btrfs_throttle in file write
Btrfs: release space on error in page_mkwrite
Btrfs: fix btrfsck error 400 when truncating a compressed
Btrfs: do not use btrfs_end_transaction_throttle everywhere
Btrfs: add balance progress reporting
Btrfs: allow for resuming restriper after it was paused
Btrfs: allow for canceling restriper
Btrfs: allow for pausing restriper
Btrfs: add skip_balance mount option
Btrfs: recover balance on mount
Btrfs: save balance parameters to disk
Btrfs: soft profile changing mode (aka soft convert)
Btrfs: implement online profile changing
Btrfs: do not reduce profile in do_chunk_alloc()
Btrfs: virtual address space subset filter
...
Fix up trivial conflict in fs/btrfs/ioctl.c due to the use of the new
mnt_drop_write_file() helper.
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 261 |
1 files changed, 233 insertions, 28 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5441ff1480fd..2db7c1455c7f 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -176,6 +176,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
176 | struct btrfs_trans_handle *trans; | 176 | struct btrfs_trans_handle *trans; |
177 | unsigned int flags, oldflags; | 177 | unsigned int flags, oldflags; |
178 | int ret; | 178 | int ret; |
179 | u64 ip_oldflags; | ||
180 | unsigned int i_oldflags; | ||
179 | 181 | ||
180 | if (btrfs_root_readonly(root)) | 182 | if (btrfs_root_readonly(root)) |
181 | return -EROFS; | 183 | return -EROFS; |
@@ -192,6 +194,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
192 | 194 | ||
193 | mutex_lock(&inode->i_mutex); | 195 | mutex_lock(&inode->i_mutex); |
194 | 196 | ||
197 | ip_oldflags = ip->flags; | ||
198 | i_oldflags = inode->i_flags; | ||
199 | |||
195 | flags = btrfs_mask_flags(inode->i_mode, flags); | 200 | flags = btrfs_mask_flags(inode->i_mode, flags); |
196 | oldflags = btrfs_flags_to_ioctl(ip->flags); | 201 | oldflags = btrfs_flags_to_ioctl(ip->flags); |
197 | if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { | 202 | if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { |
@@ -249,19 +254,24 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
249 | ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); | 254 | ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); |
250 | } | 255 | } |
251 | 256 | ||
252 | trans = btrfs_join_transaction(root); | 257 | trans = btrfs_start_transaction(root, 1); |
253 | BUG_ON(IS_ERR(trans)); | 258 | if (IS_ERR(trans)) { |
259 | ret = PTR_ERR(trans); | ||
260 | goto out_drop; | ||
261 | } | ||
254 | 262 | ||
255 | btrfs_update_iflags(inode); | 263 | btrfs_update_iflags(inode); |
256 | inode->i_ctime = CURRENT_TIME; | 264 | inode->i_ctime = CURRENT_TIME; |
257 | ret = btrfs_update_inode(trans, root, inode); | 265 | ret = btrfs_update_inode(trans, root, inode); |
258 | BUG_ON(ret); | ||
259 | 266 | ||
260 | btrfs_end_transaction(trans, root); | 267 | btrfs_end_transaction(trans, root); |
268 | out_drop: | ||
269 | if (ret) { | ||
270 | ip->flags = ip_oldflags; | ||
271 | inode->i_flags = i_oldflags; | ||
272 | } | ||
261 | 273 | ||
262 | mnt_drop_write_file(file); | 274 | mnt_drop_write_file(file); |
263 | |||
264 | ret = 0; | ||
265 | out_unlock: | 275 | out_unlock: |
266 | mutex_unlock(&inode->i_mutex); | 276 | mutex_unlock(&inode->i_mutex); |
267 | return ret; | 277 | return ret; |
@@ -358,7 +368,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
358 | return PTR_ERR(trans); | 368 | return PTR_ERR(trans); |
359 | 369 | ||
360 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, | 370 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, |
361 | 0, objectid, NULL, 0, 0, 0); | 371 | 0, objectid, NULL, 0, 0, 0, 0); |
362 | if (IS_ERR(leaf)) { | 372 | if (IS_ERR(leaf)) { |
363 | ret = PTR_ERR(leaf); | 373 | ret = PTR_ERR(leaf); |
364 | goto fail; | 374 | goto fail; |
@@ -858,10 +868,8 @@ static int cluster_pages_for_defrag(struct inode *inode, | |||
858 | return 0; | 868 | return 0; |
859 | file_end = (isize - 1) >> PAGE_CACHE_SHIFT; | 869 | file_end = (isize - 1) >> PAGE_CACHE_SHIFT; |
860 | 870 | ||
861 | mutex_lock(&inode->i_mutex); | ||
862 | ret = btrfs_delalloc_reserve_space(inode, | 871 | ret = btrfs_delalloc_reserve_space(inode, |
863 | num_pages << PAGE_CACHE_SHIFT); | 872 | num_pages << PAGE_CACHE_SHIFT); |
864 | mutex_unlock(&inode->i_mutex); | ||
865 | if (ret) | 873 | if (ret) |
866 | return ret; | 874 | return ret; |
867 | again: | 875 | again: |
@@ -1203,13 +1211,21 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1203 | if (!capable(CAP_SYS_ADMIN)) | 1211 | if (!capable(CAP_SYS_ADMIN)) |
1204 | return -EPERM; | 1212 | return -EPERM; |
1205 | 1213 | ||
1214 | mutex_lock(&root->fs_info->volume_mutex); | ||
1215 | if (root->fs_info->balance_ctl) { | ||
1216 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
1217 | ret = -EINVAL; | ||
1218 | goto out; | ||
1219 | } | ||
1220 | |||
1206 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1221 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
1207 | if (IS_ERR(vol_args)) | 1222 | if (IS_ERR(vol_args)) { |
1208 | return PTR_ERR(vol_args); | 1223 | ret = PTR_ERR(vol_args); |
1224 | goto out; | ||
1225 | } | ||
1209 | 1226 | ||
1210 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 1227 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
1211 | 1228 | ||
1212 | mutex_lock(&root->fs_info->volume_mutex); | ||
1213 | sizestr = vol_args->name; | 1229 | sizestr = vol_args->name; |
1214 | devstr = strchr(sizestr, ':'); | 1230 | devstr = strchr(sizestr, ':'); |
1215 | if (devstr) { | 1231 | if (devstr) { |
@@ -1226,7 +1242,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1226 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", | 1242 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", |
1227 | (unsigned long long)devid); | 1243 | (unsigned long long)devid); |
1228 | ret = -EINVAL; | 1244 | ret = -EINVAL; |
1229 | goto out_unlock; | 1245 | goto out_free; |
1230 | } | 1246 | } |
1231 | if (!strcmp(sizestr, "max")) | 1247 | if (!strcmp(sizestr, "max")) |
1232 | new_size = device->bdev->bd_inode->i_size; | 1248 | new_size = device->bdev->bd_inode->i_size; |
@@ -1241,7 +1257,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1241 | new_size = memparse(sizestr, NULL); | 1257 | new_size = memparse(sizestr, NULL); |
1242 | if (new_size == 0) { | 1258 | if (new_size == 0) { |
1243 | ret = -EINVAL; | 1259 | ret = -EINVAL; |
1244 | goto out_unlock; | 1260 | goto out_free; |
1245 | } | 1261 | } |
1246 | } | 1262 | } |
1247 | 1263 | ||
@@ -1250,7 +1266,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1250 | if (mod < 0) { | 1266 | if (mod < 0) { |
1251 | if (new_size > old_size) { | 1267 | if (new_size > old_size) { |
1252 | ret = -EINVAL; | 1268 | ret = -EINVAL; |
1253 | goto out_unlock; | 1269 | goto out_free; |
1254 | } | 1270 | } |
1255 | new_size = old_size - new_size; | 1271 | new_size = old_size - new_size; |
1256 | } else if (mod > 0) { | 1272 | } else if (mod > 0) { |
@@ -1259,11 +1275,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1259 | 1275 | ||
1260 | if (new_size < 256 * 1024 * 1024) { | 1276 | if (new_size < 256 * 1024 * 1024) { |
1261 | ret = -EINVAL; | 1277 | ret = -EINVAL; |
1262 | goto out_unlock; | 1278 | goto out_free; |
1263 | } | 1279 | } |
1264 | if (new_size > device->bdev->bd_inode->i_size) { | 1280 | if (new_size > device->bdev->bd_inode->i_size) { |
1265 | ret = -EFBIG; | 1281 | ret = -EFBIG; |
1266 | goto out_unlock; | 1282 | goto out_free; |
1267 | } | 1283 | } |
1268 | 1284 | ||
1269 | do_div(new_size, root->sectorsize); | 1285 | do_div(new_size, root->sectorsize); |
@@ -1276,7 +1292,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1276 | trans = btrfs_start_transaction(root, 0); | 1292 | trans = btrfs_start_transaction(root, 0); |
1277 | if (IS_ERR(trans)) { | 1293 | if (IS_ERR(trans)) { |
1278 | ret = PTR_ERR(trans); | 1294 | ret = PTR_ERR(trans); |
1279 | goto out_unlock; | 1295 | goto out_free; |
1280 | } | 1296 | } |
1281 | ret = btrfs_grow_device(trans, device, new_size); | 1297 | ret = btrfs_grow_device(trans, device, new_size); |
1282 | btrfs_commit_transaction(trans, root); | 1298 | btrfs_commit_transaction(trans, root); |
@@ -1284,9 +1300,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1284 | ret = btrfs_shrink_device(device, new_size); | 1300 | ret = btrfs_shrink_device(device, new_size); |
1285 | } | 1301 | } |
1286 | 1302 | ||
1287 | out_unlock: | 1303 | out_free: |
1288 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1289 | kfree(vol_args); | 1304 | kfree(vol_args); |
1305 | out: | ||
1306 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1290 | return ret; | 1307 | return ret; |
1291 | } | 1308 | } |
1292 | 1309 | ||
@@ -2052,14 +2069,25 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) | |||
2052 | if (!capable(CAP_SYS_ADMIN)) | 2069 | if (!capable(CAP_SYS_ADMIN)) |
2053 | return -EPERM; | 2070 | return -EPERM; |
2054 | 2071 | ||
2072 | mutex_lock(&root->fs_info->volume_mutex); | ||
2073 | if (root->fs_info->balance_ctl) { | ||
2074 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
2075 | ret = -EINVAL; | ||
2076 | goto out; | ||
2077 | } | ||
2078 | |||
2055 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2079 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2056 | if (IS_ERR(vol_args)) | 2080 | if (IS_ERR(vol_args)) { |
2057 | return PTR_ERR(vol_args); | 2081 | ret = PTR_ERR(vol_args); |
2082 | goto out; | ||
2083 | } | ||
2058 | 2084 | ||
2059 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 2085 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
2060 | ret = btrfs_init_new_device(root, vol_args->name); | 2086 | ret = btrfs_init_new_device(root, vol_args->name); |
2061 | 2087 | ||
2062 | kfree(vol_args); | 2088 | kfree(vol_args); |
2089 | out: | ||
2090 | mutex_unlock(&root->fs_info->volume_mutex); | ||
2063 | return ret; | 2091 | return ret; |
2064 | } | 2092 | } |
2065 | 2093 | ||
@@ -2074,14 +2102,25 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
2074 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 2102 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
2075 | return -EROFS; | 2103 | return -EROFS; |
2076 | 2104 | ||
2105 | mutex_lock(&root->fs_info->volume_mutex); | ||
2106 | if (root->fs_info->balance_ctl) { | ||
2107 | printk(KERN_INFO "btrfs: balance in progress\n"); | ||
2108 | ret = -EINVAL; | ||
2109 | goto out; | ||
2110 | } | ||
2111 | |||
2077 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 2112 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
2078 | if (IS_ERR(vol_args)) | 2113 | if (IS_ERR(vol_args)) { |
2079 | return PTR_ERR(vol_args); | 2114 | ret = PTR_ERR(vol_args); |
2115 | goto out; | ||
2116 | } | ||
2080 | 2117 | ||
2081 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 2118 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
2082 | ret = btrfs_rm_device(root, vol_args->name); | 2119 | ret = btrfs_rm_device(root, vol_args->name); |
2083 | 2120 | ||
2084 | kfree(vol_args); | 2121 | kfree(vol_args); |
2122 | out: | ||
2123 | mutex_unlock(&root->fs_info->volume_mutex); | ||
2085 | return ret; | 2124 | return ret; |
2086 | } | 2125 | } |
2087 | 2126 | ||
@@ -2427,7 +2466,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2427 | disko, diskl, 0, | 2466 | disko, diskl, 0, |
2428 | root->root_key.objectid, | 2467 | root->root_key.objectid, |
2429 | btrfs_ino(inode), | 2468 | btrfs_ino(inode), |
2430 | new_key.offset - datao); | 2469 | new_key.offset - datao, |
2470 | 0); | ||
2431 | BUG_ON(ret); | 2471 | BUG_ON(ret); |
2432 | } | 2472 | } |
2433 | } else if (type == BTRFS_FILE_EXTENT_INLINE) { | 2473 | } else if (type == BTRFS_FILE_EXTENT_INLINE) { |
@@ -2977,7 +3017,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, | |||
2977 | { | 3017 | { |
2978 | int ret = 0; | 3018 | int ret = 0; |
2979 | int size; | 3019 | int size; |
2980 | u64 extent_offset; | 3020 | u64 extent_item_pos; |
2981 | struct btrfs_ioctl_logical_ino_args *loi; | 3021 | struct btrfs_ioctl_logical_ino_args *loi; |
2982 | struct btrfs_data_container *inodes = NULL; | 3022 | struct btrfs_data_container *inodes = NULL; |
2983 | struct btrfs_path *path = NULL; | 3023 | struct btrfs_path *path = NULL; |
@@ -3008,15 +3048,17 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, | |||
3008 | } | 3048 | } |
3009 | 3049 | ||
3010 | ret = extent_from_logical(root->fs_info, loi->logical, path, &key); | 3050 | ret = extent_from_logical(root->fs_info, loi->logical, path, &key); |
3051 | btrfs_release_path(path); | ||
3011 | 3052 | ||
3012 | if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) | 3053 | if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) |
3013 | ret = -ENOENT; | 3054 | ret = -ENOENT; |
3014 | if (ret < 0) | 3055 | if (ret < 0) |
3015 | goto out; | 3056 | goto out; |
3016 | 3057 | ||
3017 | extent_offset = loi->logical - key.objectid; | 3058 | extent_item_pos = loi->logical - key.objectid; |
3018 | ret = iterate_extent_inodes(root->fs_info, path, key.objectid, | 3059 | ret = iterate_extent_inodes(root->fs_info, path, key.objectid, |
3019 | extent_offset, build_ino_list, inodes); | 3060 | extent_item_pos, build_ino_list, |
3061 | inodes); | ||
3020 | 3062 | ||
3021 | if (ret < 0) | 3063 | if (ret < 0) |
3022 | goto out; | 3064 | goto out; |
@@ -3034,6 +3076,163 @@ out: | |||
3034 | return ret; | 3076 | return ret; |
3035 | } | 3077 | } |
3036 | 3078 | ||
3079 | void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, | ||
3080 | struct btrfs_ioctl_balance_args *bargs) | ||
3081 | { | ||
3082 | struct btrfs_balance_control *bctl = fs_info->balance_ctl; | ||
3083 | |||
3084 | bargs->flags = bctl->flags; | ||
3085 | |||
3086 | if (atomic_read(&fs_info->balance_running)) | ||
3087 | bargs->state |= BTRFS_BALANCE_STATE_RUNNING; | ||
3088 | if (atomic_read(&fs_info->balance_pause_req)) | ||
3089 | bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ; | ||
3090 | if (atomic_read(&fs_info->balance_cancel_req)) | ||
3091 | bargs->state |= BTRFS_BALANCE_STATE_CANCEL_REQ; | ||
3092 | |||
3093 | memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); | ||
3094 | memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); | ||
3095 | memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); | ||
3096 | |||
3097 | if (lock) { | ||
3098 | spin_lock(&fs_info->balance_lock); | ||
3099 | memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); | ||
3100 | spin_unlock(&fs_info->balance_lock); | ||
3101 | } else { | ||
3102 | memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); | ||
3103 | } | ||
3104 | } | ||
3105 | |||
3106 | static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg) | ||
3107 | { | ||
3108 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
3109 | struct btrfs_ioctl_balance_args *bargs; | ||
3110 | struct btrfs_balance_control *bctl; | ||
3111 | int ret; | ||
3112 | |||
3113 | if (!capable(CAP_SYS_ADMIN)) | ||
3114 | return -EPERM; | ||
3115 | |||
3116 | if (fs_info->sb->s_flags & MS_RDONLY) | ||
3117 | return -EROFS; | ||
3118 | |||
3119 | mutex_lock(&fs_info->volume_mutex); | ||
3120 | mutex_lock(&fs_info->balance_mutex); | ||
3121 | |||
3122 | if (arg) { | ||
3123 | bargs = memdup_user(arg, sizeof(*bargs)); | ||
3124 | if (IS_ERR(bargs)) { | ||
3125 | ret = PTR_ERR(bargs); | ||
3126 | goto out; | ||
3127 | } | ||
3128 | |||
3129 | if (bargs->flags & BTRFS_BALANCE_RESUME) { | ||
3130 | if (!fs_info->balance_ctl) { | ||
3131 | ret = -ENOTCONN; | ||
3132 | goto out_bargs; | ||
3133 | } | ||
3134 | |||
3135 | bctl = fs_info->balance_ctl; | ||
3136 | spin_lock(&fs_info->balance_lock); | ||
3137 | bctl->flags |= BTRFS_BALANCE_RESUME; | ||
3138 | spin_unlock(&fs_info->balance_lock); | ||
3139 | |||
3140 | goto do_balance; | ||
3141 | } | ||
3142 | } else { | ||
3143 | bargs = NULL; | ||
3144 | } | ||
3145 | |||
3146 | if (fs_info->balance_ctl) { | ||
3147 | ret = -EINPROGRESS; | ||
3148 | goto out_bargs; | ||
3149 | } | ||
3150 | |||
3151 | bctl = kzalloc(sizeof(*bctl), GFP_NOFS); | ||
3152 | if (!bctl) { | ||
3153 | ret = -ENOMEM; | ||
3154 | goto out_bargs; | ||
3155 | } | ||
3156 | |||
3157 | bctl->fs_info = fs_info; | ||
3158 | if (arg) { | ||
3159 | memcpy(&bctl->data, &bargs->data, sizeof(bctl->data)); | ||
3160 | memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta)); | ||
3161 | memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys)); | ||
3162 | |||
3163 | bctl->flags = bargs->flags; | ||
3164 | } else { | ||
3165 | /* balance everything - no filters */ | ||
3166 | bctl->flags |= BTRFS_BALANCE_TYPE_MASK; | ||
3167 | } | ||
3168 | |||
3169 | do_balance: | ||
3170 | ret = btrfs_balance(bctl, bargs); | ||
3171 | /* | ||
3172 | * bctl is freed in __cancel_balance or in free_fs_info if | ||
3173 | * restriper was paused all the way until unmount | ||
3174 | */ | ||
3175 | if (arg) { | ||
3176 | if (copy_to_user(arg, bargs, sizeof(*bargs))) | ||
3177 | ret = -EFAULT; | ||
3178 | } | ||
3179 | |||
3180 | out_bargs: | ||
3181 | kfree(bargs); | ||
3182 | out: | ||
3183 | mutex_unlock(&fs_info->balance_mutex); | ||
3184 | mutex_unlock(&fs_info->volume_mutex); | ||
3185 | return ret; | ||
3186 | } | ||
3187 | |||
3188 | static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd) | ||
3189 | { | ||
3190 | if (!capable(CAP_SYS_ADMIN)) | ||
3191 | return -EPERM; | ||
3192 | |||
3193 | switch (cmd) { | ||
3194 | case BTRFS_BALANCE_CTL_PAUSE: | ||
3195 | return btrfs_pause_balance(root->fs_info); | ||
3196 | case BTRFS_BALANCE_CTL_CANCEL: | ||
3197 | return btrfs_cancel_balance(root->fs_info); | ||
3198 | } | ||
3199 | |||
3200 | return -EINVAL; | ||
3201 | } | ||
3202 | |||
3203 | static long btrfs_ioctl_balance_progress(struct btrfs_root *root, | ||
3204 | void __user *arg) | ||
3205 | { | ||
3206 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
3207 | struct btrfs_ioctl_balance_args *bargs; | ||
3208 | int ret = 0; | ||
3209 | |||
3210 | if (!capable(CAP_SYS_ADMIN)) | ||
3211 | return -EPERM; | ||
3212 | |||
3213 | mutex_lock(&fs_info->balance_mutex); | ||
3214 | if (!fs_info->balance_ctl) { | ||
3215 | ret = -ENOTCONN; | ||
3216 | goto out; | ||
3217 | } | ||
3218 | |||
3219 | bargs = kzalloc(sizeof(*bargs), GFP_NOFS); | ||
3220 | if (!bargs) { | ||
3221 | ret = -ENOMEM; | ||
3222 | goto out; | ||
3223 | } | ||
3224 | |||
3225 | update_ioctl_balance_args(fs_info, 1, bargs); | ||
3226 | |||
3227 | if (copy_to_user(arg, bargs, sizeof(*bargs))) | ||
3228 | ret = -EFAULT; | ||
3229 | |||
3230 | kfree(bargs); | ||
3231 | out: | ||
3232 | mutex_unlock(&fs_info->balance_mutex); | ||
3233 | return ret; | ||
3234 | } | ||
3235 | |||
3037 | long btrfs_ioctl(struct file *file, unsigned int | 3236 | long btrfs_ioctl(struct file *file, unsigned int |
3038 | cmd, unsigned long arg) | 3237 | cmd, unsigned long arg) |
3039 | { | 3238 | { |
@@ -3078,7 +3277,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3078 | case BTRFS_IOC_DEV_INFO: | 3277 | case BTRFS_IOC_DEV_INFO: |
3079 | return btrfs_ioctl_dev_info(root, argp); | 3278 | return btrfs_ioctl_dev_info(root, argp); |
3080 | case BTRFS_IOC_BALANCE: | 3279 | case BTRFS_IOC_BALANCE: |
3081 | return btrfs_balance(root->fs_info->dev_root); | 3280 | return btrfs_ioctl_balance(root, NULL); |
3082 | case BTRFS_IOC_CLONE: | 3281 | case BTRFS_IOC_CLONE: |
3083 | return btrfs_ioctl_clone(file, arg, 0, 0, 0); | 3282 | return btrfs_ioctl_clone(file, arg, 0, 0, 0); |
3084 | case BTRFS_IOC_CLONE_RANGE: | 3283 | case BTRFS_IOC_CLONE_RANGE: |
@@ -3110,6 +3309,12 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3110 | return btrfs_ioctl_scrub_cancel(root, argp); | 3309 | return btrfs_ioctl_scrub_cancel(root, argp); |
3111 | case BTRFS_IOC_SCRUB_PROGRESS: | 3310 | case BTRFS_IOC_SCRUB_PROGRESS: |
3112 | return btrfs_ioctl_scrub_progress(root, argp); | 3311 | return btrfs_ioctl_scrub_progress(root, argp); |
3312 | case BTRFS_IOC_BALANCE_V2: | ||
3313 | return btrfs_ioctl_balance(root, argp); | ||
3314 | case BTRFS_IOC_BALANCE_CTL: | ||
3315 | return btrfs_ioctl_balance_ctl(root, arg); | ||
3316 | case BTRFS_IOC_BALANCE_PROGRESS: | ||
3317 | return btrfs_ioctl_balance_progress(root, argp); | ||
3113 | } | 3318 | } |
3114 | 3319 | ||
3115 | return -ENOTTY; | 3320 | return -ENOTTY; |