diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 6 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 28 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 7 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 51 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 1 |
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 | } |
2659 | static inline void free_fs_info(struct btrfs_fs_info *fs_info) | 2662 | static 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 | ||
3152 | static 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 | |||
3141 | long btrfs_ioctl(struct file *file, unsigned int | 3165 | long 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 | |||
140 | struct btrfs_ioctl_balance_args { | 146 | struct 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 | ||
2561 | static inline int balance_need_close(struct btrfs_fs_info *fs_info) | ||
2562 | { | ||
2563 | return atomic_read(&fs_info->balance_pause_req) == 0; | ||
2564 | } | ||
2565 | |||
2556 | static void __cancel_balance(struct btrfs_fs_info *fs_info) | 2566 | static 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; |
2697 | out: | 2715 | out: |
@@ -2785,6 +2803,35 @@ out: | |||
2785 | return ret; | 2803 | return ret; |
2786 | } | 2804 | } |
2787 | 2805 | ||
2806 | int 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); | |||
273 | int btrfs_balance(struct btrfs_balance_control *bctl, | 273 | int btrfs_balance(struct btrfs_balance_control *bctl, |
274 | struct btrfs_ioctl_balance_args *bargs); | 274 | struct btrfs_ioctl_balance_args *bargs); |
275 | int btrfs_recover_balance(struct btrfs_root *tree_root); | 275 | int btrfs_recover_balance(struct btrfs_root *tree_root); |
276 | int btrfs_pause_balance(struct btrfs_fs_info *fs_info); | ||
276 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); | 277 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); |
277 | int find_free_dev_extent(struct btrfs_trans_handle *trans, | 278 | int 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, |