aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:49 -0500
committerIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:49 -0500
commit837d5b6e46d1a4af5b6cc8f2fe83cb5de79a2961 (patch)
tree4ef87d05240e90480749c345274a83094caf66f0 /fs
parent9555c6c180600b40f6e86bd4dc53bf47e06ed663 (diff)
Btrfs: allow for pausing restriper
Implement an ioctl for pausing restriper. This pauses the relocation, but balance is still considered to be "in progress": balance item is not deleted, other volume operations cannot be started, etc. If paused in the middle of profile changing operation we will continue making allocations with the target profile. Add a hook to close_ctree() to pause restriper and free its data structures on unmount. (It's safe to unmount when restriper is in "paused" state, we will resume with the same parameters on the next mount) Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h4
-rw-r--r--fs/btrfs/disk-io.c6
-rw-r--r--fs/btrfs/ioctl.c28
-rw-r--r--fs/btrfs/ioctl.h7
-rw-r--r--fs/btrfs/volumes.c51
-rw-r--r--fs/btrfs/volumes.h1
6 files changed, 94 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 99eb2bcd9aa7..1afda75d5414 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1214,7 +1214,10 @@ struct btrfs_fs_info {
1214 /* restriper state */ 1214 /* restriper state */
1215 spinlock_t balance_lock; 1215 spinlock_t balance_lock;
1216 struct mutex balance_mutex; 1216 struct mutex balance_mutex;
1217 atomic_t balance_running;
1218 atomic_t balance_pause_req;
1217 struct btrfs_balance_control *balance_ctl; 1219 struct btrfs_balance_control *balance_ctl;
1220 wait_queue_head_t balance_wait_q;
1218 1221
1219 unsigned data_chunk_allocations; 1222 unsigned data_chunk_allocations;
1220 unsigned metadata_ratio; 1223 unsigned metadata_ratio;
@@ -2658,6 +2661,7 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
2658} 2661}
2659static inline void free_fs_info(struct btrfs_fs_info *fs_info) 2662static inline void free_fs_info(struct btrfs_fs_info *fs_info)
2660{ 2663{
2664 kfree(fs_info->balance_ctl);
2661 kfree(fs_info->delayed_root); 2665 kfree(fs_info->delayed_root);
2662 kfree(fs_info->extent_root); 2666 kfree(fs_info->extent_root);
2663 kfree(fs_info->tree_root); 2667 kfree(fs_info->tree_root);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index eb7a11ac5b73..8ce837407800 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2004,7 +2004,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
2004 2004
2005 spin_lock_init(&fs_info->balance_lock); 2005 spin_lock_init(&fs_info->balance_lock);
2006 mutex_init(&fs_info->balance_mutex); 2006 mutex_init(&fs_info->balance_mutex);
2007 atomic_set(&fs_info->balance_running, 0);
2008 atomic_set(&fs_info->balance_pause_req, 0);
2007 fs_info->balance_ctl = NULL; 2009 fs_info->balance_ctl = NULL;
2010 init_waitqueue_head(&fs_info->balance_wait_q);
2008 2011
2009 sb->s_blocksize = 4096; 2012 sb->s_blocksize = 4096;
2010 sb->s_blocksize_bits = blksize_bits(4096); 2013 sb->s_blocksize_bits = blksize_bits(4096);
@@ -2980,6 +2983,9 @@ int close_ctree(struct btrfs_root *root)
2980 fs_info->closing = 1; 2983 fs_info->closing = 1;
2981 smp_mb(); 2984 smp_mb();
2982 2985
2986 /* pause restriper - we want to resume on mount */
2987 btrfs_pause_balance(root->fs_info);
2988
2983 btrfs_scrub_cancel(root); 2989 btrfs_scrub_cancel(root);
2984 2990
2985 /* wait for any defraggers to finish */ 2991 /* wait for any defraggers to finish */
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 29b3a94933f0..f572c53dda4f 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3072,6 +3072,11 @@ void update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
3072 3072
3073 bargs->flags = bctl->flags; 3073 bargs->flags = bctl->flags;
3074 3074
3075 if (atomic_read(&fs_info->balance_running))
3076 bargs->state |= BTRFS_BALANCE_STATE_RUNNING;
3077 if (atomic_read(&fs_info->balance_pause_req))
3078 bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ;
3079
3075 memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); 3080 memcpy(&bargs->data, &bctl->data, sizeof(bargs->data));
3076 memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); 3081 memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta));
3077 memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); 3082 memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys));
@@ -3103,6 +3108,11 @@ static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg)
3103 bargs = NULL; 3108 bargs = NULL;
3104 } 3109 }
3105 3110
3111 if (fs_info->balance_ctl) {
3112 ret = -EINPROGRESS;
3113 goto out_bargs;
3114 }
3115
3106 bctl = kzalloc(sizeof(*bctl), GFP_NOFS); 3116 bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
3107 if (!bctl) { 3117 if (!bctl) {
3108 ret = -ENOMEM; 3118 ret = -ENOMEM;
@@ -3123,7 +3133,8 @@ static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg)
3123 3133
3124 ret = btrfs_balance(bctl, bargs); 3134 ret = btrfs_balance(bctl, bargs);
3125 /* 3135 /*
3126 * bctl is freed in __cancel_balance 3136 * bctl is freed in __cancel_balance or in free_fs_info if
3137 * restriper was paused all the way until unmount
3127 */ 3138 */
3128 if (arg) { 3139 if (arg) {
3129 if (copy_to_user(arg, bargs, sizeof(*bargs))) 3140 if (copy_to_user(arg, bargs, sizeof(*bargs)))
@@ -3138,6 +3149,19 @@ out:
3138 return ret; 3149 return ret;
3139} 3150}
3140 3151
3152static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd)
3153{
3154 if (!capable(CAP_SYS_ADMIN))
3155 return -EPERM;
3156
3157 switch (cmd) {
3158 case BTRFS_BALANCE_CTL_PAUSE:
3159 return btrfs_pause_balance(root->fs_info);
3160 }
3161
3162 return -EINVAL;
3163}
3164
3141long btrfs_ioctl(struct file *file, unsigned int 3165long btrfs_ioctl(struct file *file, unsigned int
3142 cmd, unsigned long arg) 3166 cmd, unsigned long arg)
3143{ 3167{
@@ -3216,6 +3240,8 @@ long btrfs_ioctl(struct file *file, unsigned int
3216 return btrfs_ioctl_scrub_progress(root, argp); 3240 return btrfs_ioctl_scrub_progress(root, argp);
3217 case BTRFS_IOC_BALANCE_V2: 3241 case BTRFS_IOC_BALANCE_V2:
3218 return btrfs_ioctl_balance(root, argp); 3242 return btrfs_ioctl_balance(root, argp);
3243 case BTRFS_IOC_BALANCE_CTL:
3244 return btrfs_ioctl_balance_ctl(root, arg);
3219 } 3245 }
3220 3246
3221 return -ENOTTY; 3247 return -ENOTTY;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index c8b37d2c0d77..e972e11a8d77 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -109,6 +109,9 @@ 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/* balance control ioctl modes */
113#define BTRFS_BALANCE_CTL_PAUSE 1
114
112/* 115/*
113 * this is packed, because it should be exactly the same as its disk 116 * this is packed, because it should be exactly the same as its disk
114 * byte order counterpart (struct btrfs_disk_balance_args) 117 * byte order counterpart (struct btrfs_disk_balance_args)
@@ -137,6 +140,9 @@ struct btrfs_balance_progress {
137 __u64 completed; /* # of chunks relocated so far */ 140 __u64 completed; /* # of chunks relocated so far */
138}; 141};
139 142
143#define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0)
144#define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1)
145
140struct btrfs_ioctl_balance_args { 146struct btrfs_ioctl_balance_args {
141 __u64 flags; /* in/out */ 147 __u64 flags; /* in/out */
142 __u64 state; /* out */ 148 __u64 state; /* out */
@@ -315,6 +321,7 @@ struct btrfs_ioctl_logical_ino_args {
315 struct btrfs_ioctl_fs_info_args) 321 struct btrfs_ioctl_fs_info_args)
316#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ 322#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \
317 struct btrfs_ioctl_balance_args) 323 struct btrfs_ioctl_balance_args)
324#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)
318#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ 325#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
319 struct btrfs_ioctl_ino_path_args) 326 struct btrfs_ioctl_ino_path_args)
320#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ 327#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index e0160607e6e2..d32660ce753d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2492,6 +2492,11 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2492 key.type = BTRFS_CHUNK_ITEM_KEY; 2492 key.type = BTRFS_CHUNK_ITEM_KEY;
2493 2493
2494 while (1) { 2494 while (1) {
2495 if (atomic_read(&fs_info->balance_pause_req)) {
2496 ret = -ECANCELED;
2497 goto error;
2498 }
2499
2495 ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); 2500 ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
2496 if (ret < 0) 2501 if (ret < 0)
2497 goto error; 2502 goto error;
@@ -2553,6 +2558,11 @@ error:
2553 return ret; 2558 return ret;
2554} 2559}
2555 2560
2561static inline int balance_need_close(struct btrfs_fs_info *fs_info)
2562{
2563 return atomic_read(&fs_info->balance_pause_req) == 0;
2564}
2565
2556static void __cancel_balance(struct btrfs_fs_info *fs_info) 2566static void __cancel_balance(struct btrfs_fs_info *fs_info)
2557{ 2567{
2558 int ret; 2568 int ret;
@@ -2575,7 +2585,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
2575 u64 allowed; 2585 u64 allowed;
2576 int ret; 2586 int ret;
2577 2587
2578 if (btrfs_fs_closing(fs_info)) { 2588 if (btrfs_fs_closing(fs_info) ||
2589 atomic_read(&fs_info->balance_pause_req)) {
2579 ret = -EINVAL; 2590 ret = -EINVAL;
2580 goto out; 2591 goto out;
2581 } 2592 }
@@ -2680,18 +2691,25 @@ do_balance:
2680 spin_unlock(&fs_info->balance_lock); 2691 spin_unlock(&fs_info->balance_lock);
2681 } 2692 }
2682 2693
2694 atomic_inc(&fs_info->balance_running);
2683 mutex_unlock(&fs_info->balance_mutex); 2695 mutex_unlock(&fs_info->balance_mutex);
2684 2696
2685 ret = __btrfs_balance(fs_info); 2697 ret = __btrfs_balance(fs_info);
2686 2698
2687 mutex_lock(&fs_info->balance_mutex); 2699 mutex_lock(&fs_info->balance_mutex);
2700 atomic_dec(&fs_info->balance_running);
2688 2701
2689 if (bargs) { 2702 if (bargs) {
2690 memset(bargs, 0, sizeof(*bargs)); 2703 memset(bargs, 0, sizeof(*bargs));
2691 update_ioctl_balance_args(fs_info, bargs); 2704 update_ioctl_balance_args(fs_info, bargs);
2692 } 2705 }
2693 2706
2694 __cancel_balance(fs_info); 2707 if ((ret && ret != -ECANCELED && ret != -ENOSPC) ||
2708 balance_need_close(fs_info)) {
2709 __cancel_balance(fs_info);
2710 }
2711
2712 wake_up(&fs_info->balance_wait_q);
2695 2713
2696 return ret; 2714 return ret;
2697out: 2715out:
@@ -2785,6 +2803,35 @@ out:
2785 return ret; 2803 return ret;
2786} 2804}
2787 2805
2806int btrfs_pause_balance(struct btrfs_fs_info *fs_info)
2807{
2808 int ret = 0;
2809
2810 mutex_lock(&fs_info->balance_mutex);
2811 if (!fs_info->balance_ctl) {
2812 mutex_unlock(&fs_info->balance_mutex);
2813 return -ENOTCONN;
2814 }
2815
2816 if (atomic_read(&fs_info->balance_running)) {
2817 atomic_inc(&fs_info->balance_pause_req);
2818 mutex_unlock(&fs_info->balance_mutex);
2819
2820 wait_event(fs_info->balance_wait_q,
2821 atomic_read(&fs_info->balance_running) == 0);
2822
2823 mutex_lock(&fs_info->balance_mutex);
2824 /* we are good with balance_ctl ripped off from under us */
2825 BUG_ON(atomic_read(&fs_info->balance_running));
2826 atomic_dec(&fs_info->balance_pause_req);
2827 } else {
2828 ret = -ENOTCONN;
2829 }
2830
2831 mutex_unlock(&fs_info->balance_mutex);
2832 return ret;
2833}
2834
2788/* 2835/*
2789 * shrinking a device means finding all of the device extents past 2836 * shrinking a device means finding all of the device extents past
2790 * the new size, and then following the back refs to the chunks. 2837 * the new size, and then following the back refs to the chunks.
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index cd25ea58ec35..80953afb12b9 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -273,6 +273,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *path);
273int btrfs_balance(struct btrfs_balance_control *bctl, 273int btrfs_balance(struct btrfs_balance_control *bctl,
274 struct btrfs_ioctl_balance_args *bargs); 274 struct btrfs_ioctl_balance_args *bargs);
275int btrfs_recover_balance(struct btrfs_root *tree_root); 275int btrfs_recover_balance(struct btrfs_root *tree_root);
276int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
276int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); 277int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
277int find_free_dev_extent(struct btrfs_trans_handle *trans, 278int find_free_dev_extent(struct btrfs_trans_handle *trans,
278 struct btrfs_device *device, u64 num_bytes, 279 struct btrfs_device *device, u64 num_bytes,