aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
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
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')
-rw-r--r--fs/btrfs/ctree.h6
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/ioctl.c135
-rw-r--r--fs/btrfs/ioctl.h43
-rw-r--r--fs/btrfs/volumes.c120
-rw-r--r--fs/btrfs/volumes.h14
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 {
934struct reloc_control; 934struct reloc_control;
935struct btrfs_device; 935struct btrfs_device;
936struct btrfs_fs_devices; 936struct btrfs_fs_devices;
937struct btrfs_balance_control;
937struct btrfs_delayed_root; 938struct btrfs_delayed_root;
938struct btrfs_fs_info { 939struct 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
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;
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 */
116struct 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 */
133struct 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
140struct 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
113struct btrfs_ioctl_ino_lookup_args { 154struct 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);
1454out: 1453out:
1455 mutex_unlock(&root->fs_info->volume_mutex);
1456 mutex_unlock(&uuid_mutex); 1454 mutex_unlock(&uuid_mutex);
1457 return ret; 1455 return ret;
1458error_undo: 1456error_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 }
1760out: 1757
1761 mutex_unlock(&root->fs_info->volume_mutex);
1762 return ret; 1758 return ret;
1763error: 1759error:
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
1772static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, 1768static 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 */
2081static 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
2092static 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
2080static u64 div_factor(u64 num, int factor) 2105static 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
2089int btrfs_balance(struct btrfs_root *dev_root) 2114static 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
2180error: 2203error:
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
2215static void __cancel_balance(struct btrfs_fs_info *fs_info)
2216{
2217 unset_balance_control(fs_info);
2218}
2219
2220void 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 */
2226int 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;
2253out:
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
189struct btrfs_balance_args;
190struct 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
189int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, 200int 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);
229int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); 240int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
230int btrfs_init_new_device(struct btrfs_root *root, char *path); 241int btrfs_init_new_device(struct btrfs_root *root, char *path);
231int btrfs_balance(struct btrfs_root *dev_root); 242int btrfs_balance(struct btrfs_balance_control *bctl,
243 struct btrfs_ioctl_balance_args *bargs);
232int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); 244int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
233int find_free_dev_extent(struct btrfs_trans_handle *trans, 245int 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,