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 | |
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')
-rw-r--r-- | fs/btrfs/ctree.h | 6 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 135 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 43 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 120 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 14 |
6 files changed, 281 insertions, 41 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3f8f11e18b53..c4d98c8df5c5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -934,6 +934,7 @@ struct btrfs_block_group_cache { | |||
934 | struct reloc_control; | 934 | struct reloc_control; |
935 | struct btrfs_device; | 935 | struct btrfs_device; |
936 | struct btrfs_fs_devices; | 936 | struct btrfs_fs_devices; |
937 | struct btrfs_balance_control; | ||
937 | struct btrfs_delayed_root; | 938 | struct btrfs_delayed_root; |
938 | struct btrfs_fs_info { | 939 | struct btrfs_fs_info { |
939 | u8 fsid[BTRFS_FSID_SIZE]; | 940 | u8 fsid[BTRFS_FSID_SIZE]; |
@@ -1159,6 +1160,11 @@ struct btrfs_fs_info { | |||
1159 | u64 avail_metadata_alloc_bits; | 1160 | u64 avail_metadata_alloc_bits; |
1160 | u64 avail_system_alloc_bits; | 1161 | u64 avail_system_alloc_bits; |
1161 | 1162 | ||
1163 | /* restriper state */ | ||
1164 | spinlock_t balance_lock; | ||
1165 | struct mutex balance_mutex; | ||
1166 | struct btrfs_balance_control *balance_ctl; | ||
1167 | |||
1162 | unsigned data_chunk_allocations; | 1168 | unsigned data_chunk_allocations; |
1163 | unsigned metadata_ratio; | 1169 | unsigned metadata_ratio; |
1164 | 1170 | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ce9d0fb3627d..190a1b24c902 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2002,6 +2002,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
2002 | init_rwsem(&fs_info->scrub_super_lock); | 2002 | init_rwsem(&fs_info->scrub_super_lock); |
2003 | fs_info->scrub_workers_refcnt = 0; | 2003 | fs_info->scrub_workers_refcnt = 0; |
2004 | 2004 | ||
2005 | spin_lock_init(&fs_info->balance_lock); | ||
2006 | mutex_init(&fs_info->balance_mutex); | ||
2007 | fs_info->balance_ctl = NULL; | ||
2008 | |||
2005 | sb->s_blocksize = 4096; | 2009 | sb->s_blocksize = 4096; |
2006 | sb->s_blocksize_bits = blksize_bits(4096); | 2010 | sb->s_blocksize_bits = blksize_bits(4096); |
2007 | sb->s_bdi = &fs_info->bdi; | 2011 | sb->s_bdi = &fs_info->bdi; |
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; |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 252ae9915de8..c8b37d2c0d77 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -109,6 +109,47 @@ struct btrfs_ioctl_fs_info_args { | |||
109 | __u64 reserved[124]; /* pad to 1k */ | 109 | __u64 reserved[124]; /* pad to 1k */ |
110 | }; | 110 | }; |
111 | 111 | ||
112 | /* | ||
113 | * this is packed, because it should be exactly the same as its disk | ||
114 | * byte order counterpart (struct btrfs_disk_balance_args) | ||
115 | */ | ||
116 | struct btrfs_balance_args { | ||
117 | __u64 profiles; | ||
118 | __u64 usage; | ||
119 | __u64 devid; | ||
120 | __u64 pstart; | ||
121 | __u64 pend; | ||
122 | __u64 vstart; | ||
123 | __u64 vend; | ||
124 | |||
125 | __u64 target; | ||
126 | |||
127 | __u64 flags; | ||
128 | |||
129 | __u64 unused[8]; | ||
130 | } __attribute__ ((__packed__)); | ||
131 | |||
132 | /* report balance progress to userspace */ | ||
133 | struct btrfs_balance_progress { | ||
134 | __u64 expected; /* estimated # of chunks that will be | ||
135 | * relocated to fulfill the request */ | ||
136 | __u64 considered; /* # of chunks we have considered so far */ | ||
137 | __u64 completed; /* # of chunks relocated so far */ | ||
138 | }; | ||
139 | |||
140 | struct btrfs_ioctl_balance_args { | ||
141 | __u64 flags; /* in/out */ | ||
142 | __u64 state; /* out */ | ||
143 | |||
144 | struct btrfs_balance_args data; /* in/out */ | ||
145 | struct btrfs_balance_args meta; /* in/out */ | ||
146 | struct btrfs_balance_args sys; /* in/out */ | ||
147 | |||
148 | struct btrfs_balance_progress stat; /* out */ | ||
149 | |||
150 | __u64 unused[72]; /* pad to 1k */ | ||
151 | }; | ||
152 | |||
112 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | 153 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 |
113 | struct btrfs_ioctl_ino_lookup_args { | 154 | struct btrfs_ioctl_ino_lookup_args { |
114 | __u64 treeid; | 155 | __u64 treeid; |
@@ -272,6 +313,8 @@ struct btrfs_ioctl_logical_ino_args { | |||
272 | struct btrfs_ioctl_dev_info_args) | 313 | struct btrfs_ioctl_dev_info_args) |
273 | #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ | 314 | #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ |
274 | struct btrfs_ioctl_fs_info_args) | 315 | struct btrfs_ioctl_fs_info_args) |
316 | #define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ | ||
317 | struct btrfs_ioctl_balance_args) | ||
275 | #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ | 318 | #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ |
276 | struct btrfs_ioctl_ino_path_args) | 319 | struct btrfs_ioctl_ino_path_args) |
277 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ | 320 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d5fdee56777f..9fc06e6bc51a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -1282,7 +1282,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1282 | bool clear_super = false; | 1282 | bool clear_super = false; |
1283 | 1283 | ||
1284 | mutex_lock(&uuid_mutex); | 1284 | mutex_lock(&uuid_mutex); |
1285 | mutex_lock(&root->fs_info->volume_mutex); | ||
1286 | 1285 | ||
1287 | all_avail = root->fs_info->avail_data_alloc_bits | | 1286 | all_avail = root->fs_info->avail_data_alloc_bits | |
1288 | root->fs_info->avail_system_alloc_bits | | 1287 | root->fs_info->avail_system_alloc_bits | |
@@ -1452,7 +1451,6 @@ error_close: | |||
1452 | if (bdev) | 1451 | if (bdev) |
1453 | blkdev_put(bdev, FMODE_READ | FMODE_EXCL); | 1452 | blkdev_put(bdev, FMODE_READ | FMODE_EXCL); |
1454 | out: | 1453 | out: |
1455 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1456 | mutex_unlock(&uuid_mutex); | 1454 | mutex_unlock(&uuid_mutex); |
1457 | return ret; | 1455 | return ret; |
1458 | error_undo: | 1456 | error_undo: |
@@ -1629,7 +1627,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1629 | } | 1627 | } |
1630 | 1628 | ||
1631 | filemap_write_and_wait(bdev->bd_inode->i_mapping); | 1629 | filemap_write_and_wait(bdev->bd_inode->i_mapping); |
1632 | mutex_lock(&root->fs_info->volume_mutex); | ||
1633 | 1630 | ||
1634 | devices = &root->fs_info->fs_devices->devices; | 1631 | devices = &root->fs_info->fs_devices->devices; |
1635 | /* | 1632 | /* |
@@ -1757,8 +1754,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1757 | ret = btrfs_relocate_sys_chunks(root); | 1754 | ret = btrfs_relocate_sys_chunks(root); |
1758 | BUG_ON(ret); | 1755 | BUG_ON(ret); |
1759 | } | 1756 | } |
1760 | out: | 1757 | |
1761 | mutex_unlock(&root->fs_info->volume_mutex); | ||
1762 | return ret; | 1758 | return ret; |
1763 | error: | 1759 | error: |
1764 | blkdev_put(bdev, FMODE_EXCL); | 1760 | blkdev_put(bdev, FMODE_EXCL); |
@@ -1766,7 +1762,7 @@ error: | |||
1766 | mutex_unlock(&uuid_mutex); | 1762 | mutex_unlock(&uuid_mutex); |
1767 | up_write(&sb->s_umount); | 1763 | up_write(&sb->s_umount); |
1768 | } | 1764 | } |
1769 | goto out; | 1765 | return ret; |
1770 | } | 1766 | } |
1771 | 1767 | ||
1772 | static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, | 1768 | static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, |
@@ -2077,6 +2073,35 @@ error: | |||
2077 | return ret; | 2073 | return ret; |
2078 | } | 2074 | } |
2079 | 2075 | ||
2076 | /* | ||
2077 | * Should be called with both balance and volume mutexes held to | ||
2078 | * serialize other volume operations (add_dev/rm_dev/resize) with | ||
2079 | * restriper. Same goes for unset_balance_control. | ||
2080 | */ | ||
2081 | static void set_balance_control(struct btrfs_balance_control *bctl) | ||
2082 | { | ||
2083 | struct btrfs_fs_info *fs_info = bctl->fs_info; | ||
2084 | |||
2085 | BUG_ON(fs_info->balance_ctl); | ||
2086 | |||
2087 | spin_lock(&fs_info->balance_lock); | ||
2088 | fs_info->balance_ctl = bctl; | ||
2089 | spin_unlock(&fs_info->balance_lock); | ||
2090 | } | ||
2091 | |||
2092 | static void unset_balance_control(struct btrfs_fs_info *fs_info) | ||
2093 | { | ||
2094 | struct btrfs_balance_control *bctl = fs_info->balance_ctl; | ||
2095 | |||
2096 | BUG_ON(!fs_info->balance_ctl); | ||
2097 | |||
2098 | spin_lock(&fs_info->balance_lock); | ||
2099 | fs_info->balance_ctl = NULL; | ||
2100 | spin_unlock(&fs_info->balance_lock); | ||
2101 | |||
2102 | kfree(bctl); | ||
2103 | } | ||
2104 | |||
2080 | static u64 div_factor(u64 num, int factor) | 2105 | static u64 div_factor(u64 num, int factor) |
2081 | { | 2106 | { |
2082 | if (factor == 10) | 2107 | if (factor == 10) |
@@ -2086,29 +2111,23 @@ static u64 div_factor(u64 num, int factor) | |||
2086 | return num; | 2111 | return num; |
2087 | } | 2112 | } |
2088 | 2113 | ||
2089 | int btrfs_balance(struct btrfs_root *dev_root) | 2114 | static int __btrfs_balance(struct btrfs_fs_info *fs_info) |
2090 | { | 2115 | { |
2091 | int ret; | 2116 | struct btrfs_root *chunk_root = fs_info->chunk_root; |
2092 | struct list_head *devices = &dev_root->fs_info->fs_devices->devices; | 2117 | struct btrfs_root *dev_root = fs_info->dev_root; |
2118 | struct list_head *devices; | ||
2093 | struct btrfs_device *device; | 2119 | struct btrfs_device *device; |
2094 | u64 old_size; | 2120 | u64 old_size; |
2095 | u64 size_to_free; | 2121 | u64 size_to_free; |
2096 | struct btrfs_path *path; | 2122 | struct btrfs_path *path; |
2097 | struct btrfs_key key; | 2123 | struct btrfs_key key; |
2098 | struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; | ||
2099 | struct btrfs_trans_handle *trans; | ||
2100 | struct btrfs_key found_key; | 2124 | struct btrfs_key found_key; |
2101 | 2125 | struct btrfs_trans_handle *trans; | |
2102 | if (dev_root->fs_info->sb->s_flags & MS_RDONLY) | 2126 | int ret; |
2103 | return -EROFS; | 2127 | int enospc_errors = 0; |
2104 | |||
2105 | if (!capable(CAP_SYS_ADMIN)) | ||
2106 | return -EPERM; | ||
2107 | |||
2108 | mutex_lock(&dev_root->fs_info->volume_mutex); | ||
2109 | dev_root = dev_root->fs_info->dev_root; | ||
2110 | 2128 | ||
2111 | /* step one make some room on all the devices */ | 2129 | /* step one make some room on all the devices */ |
2130 | devices = &fs_info->fs_devices->devices; | ||
2112 | list_for_each_entry(device, devices, dev_list) { | 2131 | list_for_each_entry(device, devices, dev_list) { |
2113 | old_size = device->total_bytes; | 2132 | old_size = device->total_bytes; |
2114 | size_to_free = div_factor(old_size, 1); | 2133 | size_to_free = div_factor(old_size, 1); |
@@ -2151,12 +2170,14 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
2151 | * failed | 2170 | * failed |
2152 | */ | 2171 | */ |
2153 | if (ret == 0) | 2172 | if (ret == 0) |
2154 | break; | 2173 | BUG(); /* FIXME break ? */ |
2155 | 2174 | ||
2156 | ret = btrfs_previous_item(chunk_root, path, 0, | 2175 | ret = btrfs_previous_item(chunk_root, path, 0, |
2157 | BTRFS_CHUNK_ITEM_KEY); | 2176 | BTRFS_CHUNK_ITEM_KEY); |
2158 | if (ret) | 2177 | if (ret) { |
2178 | ret = 0; | ||
2159 | break; | 2179 | break; |
2180 | } | ||
2160 | 2181 | ||
2161 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | 2182 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, |
2162 | path->slots[0]); | 2183 | path->slots[0]); |
@@ -2174,12 +2195,63 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
2174 | found_key.offset); | 2195 | found_key.offset); |
2175 | if (ret && ret != -ENOSPC) | 2196 | if (ret && ret != -ENOSPC) |
2176 | goto error; | 2197 | goto error; |
2198 | if (ret == -ENOSPC) | ||
2199 | enospc_errors++; | ||
2177 | key.offset = found_key.offset - 1; | 2200 | key.offset = found_key.offset - 1; |
2178 | } | 2201 | } |
2179 | ret = 0; | 2202 | |
2180 | error: | 2203 | error: |
2181 | btrfs_free_path(path); | 2204 | btrfs_free_path(path); |
2182 | mutex_unlock(&dev_root->fs_info->volume_mutex); | 2205 | if (enospc_errors) { |
2206 | printk(KERN_INFO "btrfs: %d enospc errors during balance\n", | ||
2207 | enospc_errors); | ||
2208 | if (!ret) | ||
2209 | ret = -ENOSPC; | ||
2210 | } | ||
2211 | |||
2212 | return ret; | ||
2213 | } | ||
2214 | |||
2215 | static void __cancel_balance(struct btrfs_fs_info *fs_info) | ||
2216 | { | ||
2217 | unset_balance_control(fs_info); | ||
2218 | } | ||
2219 | |||
2220 | void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, | ||
2221 | struct btrfs_ioctl_balance_args *bargs); | ||
2222 | |||
2223 | /* | ||
2224 | * Should be called with both balance and volume mutexes held | ||
2225 | */ | ||
2226 | int btrfs_balance(struct btrfs_balance_control *bctl, | ||
2227 | struct btrfs_ioctl_balance_args *bargs) | ||
2228 | { | ||
2229 | struct btrfs_fs_info *fs_info = bctl->fs_info; | ||
2230 | int ret; | ||
2231 | |||
2232 | if (btrfs_fs_closing(fs_info)) { | ||
2233 | ret = -EINVAL; | ||
2234 | goto out; | ||
2235 | } | ||
2236 | |||
2237 | set_balance_control(bctl); | ||
2238 | |||
2239 | mutex_unlock(&fs_info->balance_mutex); | ||
2240 | |||
2241 | ret = __btrfs_balance(fs_info); | ||
2242 | |||
2243 | mutex_lock(&fs_info->balance_mutex); | ||
2244 | |||
2245 | if (bargs) { | ||
2246 | memset(bargs, 0, sizeof(*bargs)); | ||
2247 | update_ioctl_balance_args(fs_info, bargs); | ||
2248 | } | ||
2249 | |||
2250 | __cancel_balance(fs_info); | ||
2251 | |||
2252 | return ret; | ||
2253 | out: | ||
2254 | kfree(bctl); | ||
2183 | return ret; | 2255 | return ret; |
2184 | } | 2256 | } |
2185 | 2257 | ||
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 78f2d4d4f37f..882582385283 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -186,6 +186,17 @@ struct map_lookup { | |||
186 | #define map_lookup_size(n) (sizeof(struct map_lookup) + \ | 186 | #define map_lookup_size(n) (sizeof(struct map_lookup) + \ |
187 | (sizeof(struct btrfs_bio_stripe) * (n))) | 187 | (sizeof(struct btrfs_bio_stripe) * (n))) |
188 | 188 | ||
189 | struct btrfs_balance_args; | ||
190 | struct btrfs_balance_control { | ||
191 | struct btrfs_fs_info *fs_info; | ||
192 | |||
193 | struct btrfs_balance_args data; | ||
194 | struct btrfs_balance_args meta; | ||
195 | struct btrfs_balance_args sys; | ||
196 | |||
197 | u64 flags; | ||
198 | }; | ||
199 | |||
189 | int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, | 200 | int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, |
190 | u64 end, u64 *length); | 201 | u64 end, u64 *length); |
191 | 202 | ||
@@ -228,7 +239,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, | |||
228 | u8 *uuid, u8 *fsid); | 239 | u8 *uuid, u8 *fsid); |
229 | int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); | 240 | int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); |
230 | int btrfs_init_new_device(struct btrfs_root *root, char *path); | 241 | int btrfs_init_new_device(struct btrfs_root *root, char *path); |
231 | int btrfs_balance(struct btrfs_root *dev_root); | 242 | int btrfs_balance(struct btrfs_balance_control *bctl, |
243 | struct btrfs_ioctl_balance_args *bargs); | ||
232 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); | 244 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); |
233 | int find_free_dev_extent(struct btrfs_trans_handle *trans, | 245 | int find_free_dev_extent(struct btrfs_trans_handle *trans, |
234 | struct btrfs_device *device, u64 num_bytes, | 246 | struct btrfs_device *device, u64 num_bytes, |