diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-08 14:19:17 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:04 -0400 |
commit | 7d9eb12c8739e7dc80c78c6b3596f912ecd8f941 (patch) | |
tree | 000608285b44920f22e0888753b36299bc762cef /fs | |
parent | a7a16fd772620605c76e8ac8bdbc8ccc9e3df1a0 (diff) |
Btrfs: Add locking around volume management (device add/remove/balance)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 73 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 6 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 58 |
6 files changed, 103 insertions, 40 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c6759fc1004a..bbf9bf374066 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1251,10 +1251,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1251 | WARN_ON(p->nodes[0] != NULL); | 1251 | WARN_ON(p->nodes[0] != NULL); |
1252 | WARN_ON(cow && root == root->fs_info->extent_root && | 1252 | WARN_ON(cow && root == root->fs_info->extent_root && |
1253 | !mutex_is_locked(&root->fs_info->alloc_mutex)); | 1253 | !mutex_is_locked(&root->fs_info->alloc_mutex)); |
1254 | WARN_ON(root == root->fs_info->chunk_root && | ||
1255 | !mutex_is_locked(&root->fs_info->chunk_mutex)); | ||
1256 | WARN_ON(root == root->fs_info->dev_root && | ||
1257 | !mutex_is_locked(&root->fs_info->chunk_mutex)); | ||
1258 | if (ins_len < 0) | 1254 | if (ins_len < 0) |
1259 | lowest_unlock = 2; | 1255 | lowest_unlock = 2; |
1260 | again: | 1256 | again: |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index a28796482b4a..f3783dbd9b60 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -523,6 +523,7 @@ struct btrfs_fs_info { | |||
523 | struct mutex alloc_mutex; | 523 | struct mutex alloc_mutex; |
524 | struct mutex chunk_mutex; | 524 | struct mutex chunk_mutex; |
525 | struct mutex drop_mutex; | 525 | struct mutex drop_mutex; |
526 | struct mutex volume_mutex; | ||
526 | struct list_head trans_list; | 527 | struct list_head trans_list; |
527 | struct list_head hashers; | 528 | struct list_head hashers; |
528 | struct list_head dead_roots; | 529 | struct list_head dead_roots; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 4cdc0b6a2672..8f4c40033e92 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1287,6 +1287,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1287 | mutex_init(&fs_info->chunk_mutex); | 1287 | mutex_init(&fs_info->chunk_mutex); |
1288 | mutex_init(&fs_info->transaction_kthread_mutex); | 1288 | mutex_init(&fs_info->transaction_kthread_mutex); |
1289 | mutex_init(&fs_info->cleaner_mutex); | 1289 | mutex_init(&fs_info->cleaner_mutex); |
1290 | mutex_init(&fs_info->volume_mutex); | ||
1290 | 1291 | ||
1291 | #if 0 | 1292 | #if 0 |
1292 | ret = add_hasher(fs_info, "crc32c"); | 1293 | ret = add_hasher(fs_info, "crc32c"); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5e0857ffbc35..8ebfa6be0790 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -245,6 +245,7 @@ static int noinline find_search_start(struct btrfs_root *root, | |||
245 | u64 search_start = *start_ret; | 245 | u64 search_start = *start_ret; |
246 | int wrapped = 0; | 246 | int wrapped = 0; |
247 | 247 | ||
248 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
248 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); | 249 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); |
249 | free_space_cache = &root->fs_info->free_space_cache; | 250 | free_space_cache = &root->fs_info->free_space_cache; |
250 | 251 | ||
@@ -1242,6 +1243,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
1242 | u64 start; | 1243 | u64 start; |
1243 | u64 end; | 1244 | u64 end; |
1244 | 1245 | ||
1246 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
1245 | while(total) { | 1247 | while(total) { |
1246 | cache = btrfs_lookup_block_group(info, bytenr); | 1248 | cache = btrfs_lookup_block_group(info, bytenr); |
1247 | if (!cache) { | 1249 | if (!cache) { |
@@ -1297,6 +1299,7 @@ static int update_pinned_extents(struct btrfs_root *root, | |||
1297 | struct btrfs_block_group_cache *cache; | 1299 | struct btrfs_block_group_cache *cache; |
1298 | struct btrfs_fs_info *fs_info = root->fs_info; | 1300 | struct btrfs_fs_info *fs_info = root->fs_info; |
1299 | 1301 | ||
1302 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
1300 | if (pin) { | 1303 | if (pin) { |
1301 | set_extent_dirty(&fs_info->pinned_extents, | 1304 | set_extent_dirty(&fs_info->pinned_extents, |
1302 | bytenr, bytenr + num - 1, GFP_NOFS); | 1305 | bytenr, bytenr + num - 1, GFP_NOFS); |
@@ -1391,6 +1394,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, | |||
1391 | int level; | 1394 | int level; |
1392 | int err = 0; | 1395 | int err = 0; |
1393 | 1396 | ||
1397 | WARN_ON(!mutex_is_locked(&extent_root->fs_info->alloc_mutex)); | ||
1394 | btrfs_set_stack_extent_refs(&extent_item, 1); | 1398 | btrfs_set_stack_extent_refs(&extent_item, 1); |
1395 | btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); | 1399 | btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); |
1396 | path = btrfs_alloc_path(); | 1400 | path = btrfs_alloc_path(); |
@@ -1437,6 +1441,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, | |||
1437 | { | 1441 | { |
1438 | int err = 0; | 1442 | int err = 0; |
1439 | 1443 | ||
1444 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
1440 | if (!pending) { | 1445 | if (!pending) { |
1441 | struct extent_buffer *buf; | 1446 | struct extent_buffer *buf; |
1442 | buf = btrfs_find_tree_block(root, bytenr, num_bytes); | 1447 | buf = btrfs_find_tree_block(root, bytenr, num_bytes); |
@@ -1490,6 +1495,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1490 | struct btrfs_extent_item *ei; | 1495 | struct btrfs_extent_item *ei; |
1491 | u32 refs; | 1496 | u32 refs; |
1492 | 1497 | ||
1498 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
1493 | key.objectid = bytenr; | 1499 | key.objectid = bytenr; |
1494 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 1500 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
1495 | key.offset = num_bytes; | 1501 | key.offset = num_bytes; |
@@ -1619,6 +1625,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct | |||
1619 | struct extent_io_tree *pending_del; | 1625 | struct extent_io_tree *pending_del; |
1620 | struct extent_io_tree *pinned_extents; | 1626 | struct extent_io_tree *pinned_extents; |
1621 | 1627 | ||
1628 | WARN_ON(!mutex_is_locked(&extent_root->fs_info->alloc_mutex)); | ||
1622 | pending_del = &extent_root->fs_info->pending_del; | 1629 | pending_del = &extent_root->fs_info->pending_del; |
1623 | pinned_extents = &extent_root->fs_info->pinned_extents; | 1630 | pinned_extents = &extent_root->fs_info->pinned_extents; |
1624 | 1631 | ||
@@ -2428,6 +2435,10 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2428 | btrfs_node_key(node, &found_key, path->slots[level]); | 2435 | btrfs_node_key(node, &found_key, path->slots[level]); |
2429 | WARN_ON(memcmp(&found_key, &root_item->drop_progress, | 2436 | WARN_ON(memcmp(&found_key, &root_item->drop_progress, |
2430 | sizeof(found_key))); | 2437 | sizeof(found_key))); |
2438 | /* | ||
2439 | * unlock our path, this is safe because only this | ||
2440 | * function is allowed to delete this snapshot | ||
2441 | */ | ||
2431 | for (i = 0; i < BTRFS_MAX_LEVEL; i++) { | 2442 | for (i = 0; i < BTRFS_MAX_LEVEL; i++) { |
2432 | if (path->nodes[i] && path->locks[i]) { | 2443 | if (path->nodes[i] && path->locks[i]) { |
2433 | path->locks[i] = 0; | 2444 | path->locks[i] = 0; |
@@ -2611,7 +2622,6 @@ static int find_root_for_ref(struct btrfs_root *root, | |||
2611 | u64 root_search_start = BTRFS_FS_TREE_OBJECTID; | 2622 | u64 root_search_start = BTRFS_FS_TREE_OBJECTID; |
2612 | u64 found_bytenr; | 2623 | u64 found_bytenr; |
2613 | int ret; | 2624 | int ret; |
2614 | int i; | ||
2615 | 2625 | ||
2616 | root_location.offset = (u64)-1; | 2626 | root_location.offset = (u64)-1; |
2617 | root_location.type = BTRFS_ROOT_ITEM_KEY; | 2627 | root_location.type = BTRFS_ROOT_ITEM_KEY; |
@@ -2635,12 +2645,6 @@ static int find_root_for_ref(struct btrfs_root *root, | |||
2635 | found_bytenr = path->nodes[level]->start; | 2645 | found_bytenr = path->nodes[level]->start; |
2636 | } | 2646 | } |
2637 | 2647 | ||
2638 | for (i = level; i < BTRFS_MAX_LEVEL; i++) { | ||
2639 | if (!path->nodes[i]) | ||
2640 | break; | ||
2641 | free_extent_buffer(path->nodes[i]); | ||
2642 | path->nodes[i] = NULL; | ||
2643 | } | ||
2644 | btrfs_release_path(cur_root, path); | 2648 | btrfs_release_path(cur_root, path); |
2645 | 2649 | ||
2646 | if (found_bytenr == bytenr) { | 2650 | if (found_bytenr == bytenr) { |
@@ -2689,6 +2693,8 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2689 | int ret; | 2693 | int ret; |
2690 | int level; | 2694 | int level; |
2691 | 2695 | ||
2696 | WARN_ON(!mutex_is_locked(&extent_root->fs_info->alloc_mutex)); | ||
2697 | |||
2692 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], | 2698 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], |
2693 | struct btrfs_extent_ref); | 2699 | struct btrfs_extent_ref); |
2694 | ref_root = btrfs_ref_root(path->nodes[0], ref); | 2700 | ref_root = btrfs_ref_root(path->nodes[0], ref); |
@@ -2707,6 +2713,7 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2707 | found_root = btrfs_read_fs_root_no_name(extent_root->fs_info, | 2713 | found_root = btrfs_read_fs_root_no_name(extent_root->fs_info, |
2708 | &root_location); | 2714 | &root_location); |
2709 | BUG_ON(!found_root); | 2715 | BUG_ON(!found_root); |
2716 | mutex_unlock(&extent_root->fs_info->alloc_mutex); | ||
2710 | 2717 | ||
2711 | if (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | 2718 | if (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID) { |
2712 | found_key.objectid = ref_objectid; | 2719 | found_key.objectid = ref_objectid; |
@@ -2748,9 +2755,9 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2748 | /* this can happen if the reference is not against | 2755 | /* this can happen if the reference is not against |
2749 | * the latest version of the tree root | 2756 | * the latest version of the tree root |
2750 | */ | 2757 | */ |
2751 | if (is_bad_inode(inode)) { | 2758 | if (is_bad_inode(inode)) |
2752 | goto out; | 2759 | goto out; |
2753 | } | 2760 | |
2754 | *last_file_objectid = inode->i_ino; | 2761 | *last_file_objectid = inode->i_ino; |
2755 | *last_file_root = found_root->root_key.objectid; | 2762 | *last_file_root = found_root->root_key.objectid; |
2756 | *last_file_offset = ref_offset; | 2763 | *last_file_offset = ref_offset; |
@@ -2760,7 +2767,7 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2760 | } else { | 2767 | } else { |
2761 | struct btrfs_trans_handle *trans; | 2768 | struct btrfs_trans_handle *trans; |
2762 | struct extent_buffer *eb; | 2769 | struct extent_buffer *eb; |
2763 | int i; | 2770 | int needs_lock = 0; |
2764 | 2771 | ||
2765 | eb = read_tree_block(found_root, extent_key->objectid, | 2772 | eb = read_tree_block(found_root, extent_key->objectid, |
2766 | extent_key->offset, 0); | 2773 | extent_key->offset, 0); |
@@ -2782,26 +2789,40 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2782 | if (ret) | 2789 | if (ret) |
2783 | goto out; | 2790 | goto out; |
2784 | 2791 | ||
2792 | /* | ||
2793 | * right here almost anything could happen to our key, | ||
2794 | * but that's ok. The cow below will either relocate it | ||
2795 | * or someone else will have relocated it. Either way, | ||
2796 | * it is in a different spot than it was before and | ||
2797 | * we're happy. | ||
2798 | */ | ||
2799 | |||
2785 | trans = btrfs_start_transaction(found_root, 1); | 2800 | trans = btrfs_start_transaction(found_root, 1); |
2786 | 2801 | ||
2802 | if (found_root == extent_root->fs_info->extent_root || | ||
2803 | found_root == extent_root->fs_info->chunk_root || | ||
2804 | found_root == extent_root->fs_info->dev_root) { | ||
2805 | needs_lock = 1; | ||
2806 | mutex_lock(&extent_root->fs_info->alloc_mutex); | ||
2807 | } | ||
2808 | |||
2787 | path->lowest_level = level; | 2809 | path->lowest_level = level; |
2788 | path->reada = 2; | 2810 | path->reada = 2; |
2789 | ret = btrfs_search_slot(trans, found_root, &found_key, path, | 2811 | ret = btrfs_search_slot(trans, found_root, &found_key, path, |
2790 | 0, 1); | 2812 | 0, 1); |
2791 | path->lowest_level = 0; | 2813 | path->lowest_level = 0; |
2792 | for (i = level; i < BTRFS_MAX_LEVEL; i++) { | ||
2793 | if (!path->nodes[i]) | ||
2794 | break; | ||
2795 | free_extent_buffer(path->nodes[i]); | ||
2796 | path->nodes[i] = NULL; | ||
2797 | } | ||
2798 | btrfs_release_path(found_root, path); | 2814 | btrfs_release_path(found_root, path); |
2815 | |||
2799 | if (found_root == found_root->fs_info->extent_root) | 2816 | if (found_root == found_root->fs_info->extent_root) |
2800 | btrfs_extent_post_op(trans, found_root); | 2817 | btrfs_extent_post_op(trans, found_root); |
2818 | if (needs_lock) | ||
2819 | mutex_unlock(&extent_root->fs_info->alloc_mutex); | ||
2820 | |||
2801 | btrfs_end_transaction(trans, found_root); | 2821 | btrfs_end_transaction(trans, found_root); |
2802 | } | ||
2803 | 2822 | ||
2823 | } | ||
2804 | out: | 2824 | out: |
2825 | mutex_lock(&extent_root->fs_info->alloc_mutex); | ||
2805 | return 0; | 2826 | return 0; |
2806 | } | 2827 | } |
2807 | 2828 | ||
@@ -2943,7 +2964,10 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root, | |||
2943 | 2964 | ||
2944 | if (btrfs_block_group_used(&shrink_block_group->item) > 0) { | 2965 | if (btrfs_block_group_used(&shrink_block_group->item) > 0) { |
2945 | 2966 | ||
2967 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
2946 | trans = btrfs_start_transaction(root, 1); | 2968 | trans = btrfs_start_transaction(root, 1); |
2969 | mutex_lock(&root->fs_info->alloc_mutex); | ||
2970 | |||
2947 | new_alloc_flags = update_block_group_flags(root, | 2971 | new_alloc_flags = update_block_group_flags(root, |
2948 | shrink_block_group->flags); | 2972 | shrink_block_group->flags); |
2949 | if (new_alloc_flags != shrink_block_group->flags) { | 2973 | if (new_alloc_flags != shrink_block_group->flags) { |
@@ -2954,7 +2978,10 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root, | |||
2954 | } | 2978 | } |
2955 | do_chunk_alloc(trans, root->fs_info->extent_root, | 2979 | do_chunk_alloc(trans, root->fs_info->extent_root, |
2956 | calc + 2 * 1024 * 1024, new_alloc_flags, force); | 2980 | calc + 2 * 1024 * 1024, new_alloc_flags, force); |
2981 | |||
2982 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
2957 | btrfs_end_transaction(trans, root); | 2983 | btrfs_end_transaction(trans, root); |
2984 | mutex_lock(&root->fs_info->alloc_mutex); | ||
2958 | } | 2985 | } |
2959 | return 0; | 2986 | return 0; |
2960 | } | 2987 | } |
@@ -3031,9 +3058,9 @@ again: | |||
3031 | if (ret < 0) | 3058 | if (ret < 0) |
3032 | goto out; | 3059 | goto out; |
3033 | 3060 | ||
3061 | next: | ||
3034 | leaf = path->nodes[0]; | 3062 | leaf = path->nodes[0]; |
3035 | nritems = btrfs_header_nritems(leaf); | 3063 | nritems = btrfs_header_nritems(leaf); |
3036 | next: | ||
3037 | if (path->slots[0] >= nritems) { | 3064 | if (path->slots[0] >= nritems) { |
3038 | ret = btrfs_next_leaf(root, path); | 3065 | ret = btrfs_next_leaf(root, path); |
3039 | if (ret < 0) | 3066 | if (ret < 0) |
@@ -3083,6 +3110,7 @@ next: | |||
3083 | printk("btrfs relocate found %llu last extent was %llu\n", | 3110 | printk("btrfs relocate found %llu last extent was %llu\n", |
3084 | (unsigned long long)total_found, | 3111 | (unsigned long long)total_found, |
3085 | (unsigned long long)found_key.objectid); | 3112 | (unsigned long long)found_key.objectid); |
3113 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
3086 | trans = btrfs_start_transaction(tree_root, 1); | 3114 | trans = btrfs_start_transaction(tree_root, 1); |
3087 | btrfs_commit_transaction(trans, tree_root); | 3115 | btrfs_commit_transaction(trans, tree_root); |
3088 | 3116 | ||
@@ -3090,6 +3118,7 @@ next: | |||
3090 | 3118 | ||
3091 | trans = btrfs_start_transaction(tree_root, 1); | 3119 | trans = btrfs_start_transaction(tree_root, 1); |
3092 | btrfs_commit_transaction(trans, tree_root); | 3120 | btrfs_commit_transaction(trans, tree_root); |
3121 | mutex_lock(&root->fs_info->alloc_mutex); | ||
3093 | goto again; | 3122 | goto again; |
3094 | } | 3123 | } |
3095 | 3124 | ||
@@ -3097,7 +3126,10 @@ next: | |||
3097 | * we've freed all the extents, now remove the block | 3126 | * we've freed all the extents, now remove the block |
3098 | * group item from the tree | 3127 | * group item from the tree |
3099 | */ | 3128 | */ |
3129 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
3130 | |||
3100 | trans = btrfs_start_transaction(root, 1); | 3131 | trans = btrfs_start_transaction(root, 1); |
3132 | mutex_lock(&root->fs_info->alloc_mutex); | ||
3101 | memcpy(&key, &shrink_block_group->key, sizeof(key)); | 3133 | memcpy(&key, &shrink_block_group->key, sizeof(key)); |
3102 | 3134 | ||
3103 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 3135 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
@@ -3119,8 +3151,12 @@ next: | |||
3119 | kfree(shrink_block_group); | 3151 | kfree(shrink_block_group); |
3120 | 3152 | ||
3121 | btrfs_del_item(trans, root, path); | 3153 | btrfs_del_item(trans, root, path); |
3154 | btrfs_release_path(root, path); | ||
3155 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
3122 | btrfs_commit_transaction(trans, root); | 3156 | btrfs_commit_transaction(trans, root); |
3123 | 3157 | ||
3158 | mutex_lock(&root->fs_info->alloc_mutex); | ||
3159 | |||
3124 | /* the code to unpin extents might set a few bits in the free | 3160 | /* the code to unpin extents might set a few bits in the free |
3125 | * space cache for this range again | 3161 | * space cache for this range again |
3126 | */ | 3162 | */ |
@@ -3263,6 +3299,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
3263 | struct btrfs_block_group_cache *cache; | 3299 | struct btrfs_block_group_cache *cache; |
3264 | struct extent_io_tree *block_group_cache; | 3300 | struct extent_io_tree *block_group_cache; |
3265 | 3301 | ||
3302 | WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); | ||
3266 | extent_root = root->fs_info->extent_root; | 3303 | extent_root = root->fs_info->extent_root; |
3267 | block_group_cache = &root->fs_info->block_group_cache; | 3304 | block_group_cache = &root->fs_info->block_group_cache; |
3268 | 3305 | ||
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 026039a2ac58..83f17a5cbd6a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -307,8 +307,7 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) | |||
307 | goto out; | 307 | goto out; |
308 | } | 308 | } |
309 | 309 | ||
310 | mutex_lock(&root->fs_info->alloc_mutex); | 310 | mutex_lock(&root->fs_info->volume_mutex); |
311 | mutex_lock(&root->fs_info->chunk_mutex); | ||
312 | sizestr = vol_args->name; | 311 | sizestr = vol_args->name; |
313 | devstr = strchr(sizestr, ':'); | 312 | devstr = strchr(sizestr, ':'); |
314 | if (devstr) { | 313 | if (devstr) { |
@@ -378,8 +377,7 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) | |||
378 | } | 377 | } |
379 | 378 | ||
380 | out_unlock: | 379 | out_unlock: |
381 | mutex_lock(&root->fs_info->alloc_mutex); | 380 | mutex_unlock(&root->fs_info->volume_mutex); |
382 | mutex_lock(&root->fs_info->chunk_mutex); | ||
383 | out: | 381 | out: |
384 | kfree(vol_args); | 382 | kfree(vol_args); |
385 | return ret; | 383 | return ret; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4e7cee27aab5..5e6ee7a6f738 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -56,6 +56,18 @@ void btrfs_unlock_volumes(void) | |||
56 | mutex_unlock(&uuid_mutex); | 56 | mutex_unlock(&uuid_mutex); |
57 | } | 57 | } |
58 | 58 | ||
59 | static void lock_chunks(struct btrfs_root *root) | ||
60 | { | ||
61 | mutex_lock(&root->fs_info->alloc_mutex); | ||
62 | mutex_lock(&root->fs_info->chunk_mutex); | ||
63 | } | ||
64 | |||
65 | static void unlock_chunks(struct btrfs_root *root) | ||
66 | { | ||
67 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
68 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
69 | } | ||
70 | |||
59 | int btrfs_cleanup_fs_uuids(void) | 71 | int btrfs_cleanup_fs_uuids(void) |
60 | { | 72 | { |
61 | struct btrfs_fs_devices *fs_devices; | 73 | struct btrfs_fs_devices *fs_devices; |
@@ -822,6 +834,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root, | |||
822 | key.objectid = BTRFS_DEV_ITEMS_OBJECTID; | 834 | key.objectid = BTRFS_DEV_ITEMS_OBJECTID; |
823 | key.type = BTRFS_DEV_ITEM_KEY; | 835 | key.type = BTRFS_DEV_ITEM_KEY; |
824 | key.offset = device->devid; | 836 | key.offset = device->devid; |
837 | lock_chunks(root); | ||
825 | 838 | ||
826 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 839 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
827 | if (ret < 0) | 840 | if (ret < 0) |
@@ -856,6 +869,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root, | |||
856 | total_bytes - 1); | 869 | total_bytes - 1); |
857 | out: | 870 | out: |
858 | btrfs_free_path(path); | 871 | btrfs_free_path(path); |
872 | unlock_chunks(root); | ||
859 | btrfs_commit_transaction(trans, root); | 873 | btrfs_commit_transaction(trans, root); |
860 | return ret; | 874 | return ret; |
861 | } | 875 | } |
@@ -870,9 +884,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
870 | u64 devid; | 884 | u64 devid; |
871 | int ret = 0; | 885 | int ret = 0; |
872 | 886 | ||
873 | mutex_lock(&root->fs_info->alloc_mutex); | ||
874 | mutex_lock(&root->fs_info->chunk_mutex); | ||
875 | mutex_lock(&uuid_mutex); | 887 | mutex_lock(&uuid_mutex); |
888 | mutex_lock(&root->fs_info->volume_mutex); | ||
876 | 889 | ||
877 | all_avail = root->fs_info->avail_data_alloc_bits | | 890 | all_avail = root->fs_info->avail_data_alloc_bits | |
878 | root->fs_info->avail_system_alloc_bits | | 891 | root->fs_info->avail_system_alloc_bits | |
@@ -988,9 +1001,8 @@ error_close: | |||
988 | if (bdev) | 1001 | if (bdev) |
989 | close_bdev_excl(bdev); | 1002 | close_bdev_excl(bdev); |
990 | out: | 1003 | out: |
1004 | mutex_unlock(&root->fs_info->volume_mutex); | ||
991 | mutex_unlock(&uuid_mutex); | 1005 | mutex_unlock(&uuid_mutex); |
992 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
993 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
994 | return ret; | 1006 | return ret; |
995 | } | 1007 | } |
996 | 1008 | ||
@@ -1010,10 +1022,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1010 | return -EIO; | 1022 | return -EIO; |
1011 | } | 1023 | } |
1012 | 1024 | ||
1013 | mutex_lock(&root->fs_info->alloc_mutex); | 1025 | mutex_lock(&root->fs_info->volume_mutex); |
1014 | mutex_lock(&root->fs_info->chunk_mutex); | ||
1015 | 1026 | ||
1016 | trans = btrfs_start_transaction(root, 1); | 1027 | trans = btrfs_start_transaction(root, 1); |
1028 | lock_chunks(root); | ||
1017 | devices = &root->fs_info->fs_devices->devices; | 1029 | devices = &root->fs_info->fs_devices->devices; |
1018 | list_for_each(cur, devices) { | 1030 | list_for_each(cur, devices) { |
1019 | device = list_entry(cur, struct btrfs_device, dev_list); | 1031 | device = list_entry(cur, struct btrfs_device, dev_list); |
@@ -1065,9 +1077,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1065 | root->fs_info->fs_devices->num_devices++; | 1077 | root->fs_info->fs_devices->num_devices++; |
1066 | root->fs_info->fs_devices->open_devices++; | 1078 | root->fs_info->fs_devices->open_devices++; |
1067 | out: | 1079 | out: |
1080 | unlock_chunks(root); | ||
1068 | btrfs_end_transaction(trans, root); | 1081 | btrfs_end_transaction(trans, root); |
1069 | mutex_unlock(&root->fs_info->chunk_mutex); | 1082 | mutex_unlock(&root->fs_info->volume_mutex); |
1070 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
1071 | 1083 | ||
1072 | return ret; | 1084 | return ret; |
1073 | 1085 | ||
@@ -1122,7 +1134,7 @@ out: | |||
1122 | return ret; | 1134 | return ret; |
1123 | } | 1135 | } |
1124 | 1136 | ||
1125 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | 1137 | static int __btrfs_grow_device(struct btrfs_trans_handle *trans, |
1126 | struct btrfs_device *device, u64 new_size) | 1138 | struct btrfs_device *device, u64 new_size) |
1127 | { | 1139 | { |
1128 | struct btrfs_super_block *super_copy = | 1140 | struct btrfs_super_block *super_copy = |
@@ -1134,6 +1146,16 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, | |||
1134 | return btrfs_update_device(trans, device); | 1146 | return btrfs_update_device(trans, device); |
1135 | } | 1147 | } |
1136 | 1148 | ||
1149 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | ||
1150 | struct btrfs_device *device, u64 new_size) | ||
1151 | { | ||
1152 | int ret; | ||
1153 | lock_chunks(device->dev_root); | ||
1154 | ret = __btrfs_grow_device(trans, device, new_size); | ||
1155 | unlock_chunks(device->dev_root); | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1137 | static int btrfs_free_chunk(struct btrfs_trans_handle *trans, | 1159 | static int btrfs_free_chunk(struct btrfs_trans_handle *trans, |
1138 | struct btrfs_root *root, | 1160 | struct btrfs_root *root, |
1139 | u64 chunk_tree, u64 chunk_objectid, | 1161 | u64 chunk_tree, u64 chunk_objectid, |
@@ -1234,6 +1256,8 @@ int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1234 | trans = btrfs_start_transaction(root, 1); | 1256 | trans = btrfs_start_transaction(root, 1); |
1235 | BUG_ON(!trans); | 1257 | BUG_ON(!trans); |
1236 | 1258 | ||
1259 | lock_chunks(root); | ||
1260 | |||
1237 | /* | 1261 | /* |
1238 | * step two, delete the device extents and the | 1262 | * step two, delete the device extents and the |
1239 | * chunk tree entries | 1263 | * chunk tree entries |
@@ -1278,6 +1302,7 @@ int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1278 | /* once for us */ | 1302 | /* once for us */ |
1279 | free_extent_map(em); | 1303 | free_extent_map(em); |
1280 | 1304 | ||
1305 | unlock_chunks(root); | ||
1281 | btrfs_end_transaction(trans, root); | 1306 | btrfs_end_transaction(trans, root); |
1282 | return 0; | 1307 | return 0; |
1283 | } | 1308 | } |
@@ -1308,8 +1333,7 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1308 | struct btrfs_key found_key; | 1333 | struct btrfs_key found_key; |
1309 | 1334 | ||
1310 | 1335 | ||
1311 | BUG(); /* FIXME, needs locking */ | 1336 | mutex_lock(&dev_root->fs_info->volume_mutex); |
1312 | |||
1313 | dev_root = dev_root->fs_info->dev_root; | 1337 | dev_root = dev_root->fs_info->dev_root; |
1314 | 1338 | ||
1315 | /* step one make some room on all the devices */ | 1339 | /* step one make some room on all the devices */ |
@@ -1355,13 +1379,14 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1355 | 1379 | ||
1356 | ret = btrfs_previous_item(chunk_root, path, 0, | 1380 | ret = btrfs_previous_item(chunk_root, path, 0, |
1357 | BTRFS_CHUNK_ITEM_KEY); | 1381 | BTRFS_CHUNK_ITEM_KEY); |
1358 | if (ret) { | 1382 | if (ret) |
1359 | break; | 1383 | break; |
1360 | } | 1384 | |
1361 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | 1385 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, |
1362 | path->slots[0]); | 1386 | path->slots[0]); |
1363 | if (found_key.objectid != key.objectid) | 1387 | if (found_key.objectid != key.objectid) |
1364 | break; | 1388 | break; |
1389 | |||
1365 | chunk = btrfs_item_ptr(path->nodes[0], | 1390 | chunk = btrfs_item_ptr(path->nodes[0], |
1366 | path->slots[0], | 1391 | path->slots[0], |
1367 | struct btrfs_chunk); | 1392 | struct btrfs_chunk); |
@@ -1370,16 +1395,17 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1370 | if (key.offset == 0) | 1395 | if (key.offset == 0) |
1371 | break; | 1396 | break; |
1372 | 1397 | ||
1398 | btrfs_release_path(chunk_root, path); | ||
1373 | ret = btrfs_relocate_chunk(chunk_root, | 1399 | ret = btrfs_relocate_chunk(chunk_root, |
1374 | chunk_root->root_key.objectid, | 1400 | chunk_root->root_key.objectid, |
1375 | found_key.objectid, | 1401 | found_key.objectid, |
1376 | found_key.offset); | 1402 | found_key.offset); |
1377 | BUG_ON(ret); | 1403 | BUG_ON(ret); |
1378 | btrfs_release_path(chunk_root, path); | ||
1379 | } | 1404 | } |
1380 | ret = 0; | 1405 | ret = 0; |
1381 | error: | 1406 | error: |
1382 | btrfs_free_path(path); | 1407 | btrfs_free_path(path); |
1408 | mutex_unlock(&dev_root->fs_info->volume_mutex); | ||
1383 | return ret; | 1409 | return ret; |
1384 | } | 1410 | } |
1385 | 1411 | ||
@@ -1419,14 +1445,18 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
1419 | 1445 | ||
1420 | path->reada = 2; | 1446 | path->reada = 2; |
1421 | 1447 | ||
1448 | lock_chunks(root); | ||
1449 | |||
1422 | device->total_bytes = new_size; | 1450 | device->total_bytes = new_size; |
1423 | ret = btrfs_update_device(trans, device); | 1451 | ret = btrfs_update_device(trans, device); |
1424 | if (ret) { | 1452 | if (ret) { |
1453 | unlock_chunks(root); | ||
1425 | btrfs_end_transaction(trans, root); | 1454 | btrfs_end_transaction(trans, root); |
1426 | goto done; | 1455 | goto done; |
1427 | } | 1456 | } |
1428 | WARN_ON(diff > old_total); | 1457 | WARN_ON(diff > old_total); |
1429 | btrfs_set_super_total_bytes(super_copy, old_total - diff); | 1458 | btrfs_set_super_total_bytes(super_copy, old_total - diff); |
1459 | unlock_chunks(root); | ||
1430 | btrfs_end_transaction(trans, root); | 1460 | btrfs_end_transaction(trans, root); |
1431 | 1461 | ||
1432 | key.objectid = device->devid; | 1462 | key.objectid = device->devid; |