diff options
author | Jeff Mahoney <jeffm@suse.com> | 2011-10-03 23:22:32 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2012-03-21 20:45:30 -0400 |
commit | c2d904e086b6f707b73bf065e4d18ded4b86ae9e (patch) | |
tree | 44ab2acff4eaefca2abd3273bd31fbc74f73f96c /fs/btrfs/extent_io.c | |
parent | 8c3429300181be44b30f9f017d53dc717da56caa (diff) |
btrfs: Catch locking failures in {set,clear,convert}_extent_bit
The *_state functions can only return 0 or -EEXIST. This patch addresses
the cases where those functions returning -EEXIST represent a locking
failure. It handles them by panicking with an appropriate error message.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 58 |
1 files changed, 38 insertions, 20 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index a55fbe6252de..601f23bddea8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -53,6 +53,12 @@ struct extent_page_data { | |||
53 | unsigned int sync_io:1; | 53 | unsigned int sync_io:1; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static inline struct btrfs_fs_info * | ||
57 | tree_fs_info(struct extent_io_tree *tree) | ||
58 | { | ||
59 | return btrfs_sb(tree->mapping->host->i_sb); | ||
60 | } | ||
61 | |||
56 | int __init extent_io_init(void) | 62 | int __init extent_io_init(void) |
57 | { | 63 | { |
58 | extent_state_cache = kmem_cache_create("extent_state", | 64 | extent_state_cache = kmem_cache_create("extent_state", |
@@ -439,6 +445,13 @@ alloc_extent_state_atomic(struct extent_state *prealloc) | |||
439 | return prealloc; | 445 | return prealloc; |
440 | } | 446 | } |
441 | 447 | ||
448 | void extent_io_tree_panic(struct extent_io_tree *tree, int err) | ||
449 | { | ||
450 | btrfs_panic(tree_fs_info(tree), err, "Locking error: " | ||
451 | "Extent tree was modified by another " | ||
452 | "thread while locked."); | ||
453 | } | ||
454 | |||
442 | /* | 455 | /* |
443 | * clear some bits on a range in the tree. This may require splitting | 456 | * clear some bits on a range in the tree. This may require splitting |
444 | * or inserting elements in the tree, so the gfp mask is used to | 457 | * or inserting elements in the tree, so the gfp mask is used to |
@@ -542,7 +555,9 @@ hit_next: | |||
542 | prealloc = alloc_extent_state_atomic(prealloc); | 555 | prealloc = alloc_extent_state_atomic(prealloc); |
543 | BUG_ON(!prealloc); | 556 | BUG_ON(!prealloc); |
544 | err = split_state(tree, state, prealloc, start); | 557 | err = split_state(tree, state, prealloc, start); |
545 | BUG_ON(err == -EEXIST); | 558 | if (err) |
559 | extent_io_tree_panic(tree, err); | ||
560 | |||
546 | prealloc = NULL; | 561 | prealloc = NULL; |
547 | if (err) | 562 | if (err) |
548 | goto out; | 563 | goto out; |
@@ -564,7 +579,9 @@ hit_next: | |||
564 | prealloc = alloc_extent_state_atomic(prealloc); | 579 | prealloc = alloc_extent_state_atomic(prealloc); |
565 | BUG_ON(!prealloc); | 580 | BUG_ON(!prealloc); |
566 | err = split_state(tree, state, prealloc, end + 1); | 581 | err = split_state(tree, state, prealloc, end + 1); |
567 | BUG_ON(err == -EEXIST); | 582 | if (err) |
583 | extent_io_tree_panic(tree, err); | ||
584 | |||
568 | if (wake) | 585 | if (wake) |
569 | wake_up(&state->wq); | 586 | wake_up(&state->wq); |
570 | 587 | ||
@@ -742,8 +759,10 @@ again: | |||
742 | prealloc = alloc_extent_state_atomic(prealloc); | 759 | prealloc = alloc_extent_state_atomic(prealloc); |
743 | BUG_ON(!prealloc); | 760 | BUG_ON(!prealloc); |
744 | err = insert_state(tree, prealloc, start, end, &bits); | 761 | err = insert_state(tree, prealloc, start, end, &bits); |
762 | if (err) | ||
763 | extent_io_tree_panic(tree, err); | ||
764 | |||
745 | prealloc = NULL; | 765 | prealloc = NULL; |
746 | BUG_ON(err == -EEXIST); | ||
747 | goto out; | 766 | goto out; |
748 | } | 767 | } |
749 | state = rb_entry(node, struct extent_state, rb_node); | 768 | state = rb_entry(node, struct extent_state, rb_node); |
@@ -809,7 +828,9 @@ hit_next: | |||
809 | prealloc = alloc_extent_state_atomic(prealloc); | 828 | prealloc = alloc_extent_state_atomic(prealloc); |
810 | BUG_ON(!prealloc); | 829 | BUG_ON(!prealloc); |
811 | err = split_state(tree, state, prealloc, start); | 830 | err = split_state(tree, state, prealloc, start); |
812 | BUG_ON(err == -EEXIST); | 831 | if (err) |
832 | extent_io_tree_panic(tree, err); | ||
833 | |||
813 | prealloc = NULL; | 834 | prealloc = NULL; |
814 | if (err) | 835 | if (err) |
815 | goto out; | 836 | goto out; |
@@ -846,12 +867,9 @@ hit_next: | |||
846 | */ | 867 | */ |
847 | err = insert_state(tree, prealloc, start, this_end, | 868 | err = insert_state(tree, prealloc, start, this_end, |
848 | &bits); | 869 | &bits); |
849 | BUG_ON(err == -EEXIST); | 870 | if (err) |
850 | if (err) { | 871 | extent_io_tree_panic(tree, err); |
851 | free_extent_state(prealloc); | 872 | |
852 | prealloc = NULL; | ||
853 | goto out; | ||
854 | } | ||
855 | cache_state(prealloc, cached_state); | 873 | cache_state(prealloc, cached_state); |
856 | prealloc = NULL; | 874 | prealloc = NULL; |
857 | start = this_end + 1; | 875 | start = this_end + 1; |
@@ -873,7 +891,8 @@ hit_next: | |||
873 | prealloc = alloc_extent_state_atomic(prealloc); | 891 | prealloc = alloc_extent_state_atomic(prealloc); |
874 | BUG_ON(!prealloc); | 892 | BUG_ON(!prealloc); |
875 | err = split_state(tree, state, prealloc, end + 1); | 893 | err = split_state(tree, state, prealloc, end + 1); |
876 | BUG_ON(err == -EEXIST); | 894 | if (err) |
895 | extent_io_tree_panic(tree, err); | ||
877 | 896 | ||
878 | set_state_bits(tree, prealloc, &bits); | 897 | set_state_bits(tree, prealloc, &bits); |
879 | cache_state(prealloc, cached_state); | 898 | cache_state(prealloc, cached_state); |
@@ -946,7 +965,8 @@ again: | |||
946 | } | 965 | } |
947 | err = insert_state(tree, prealloc, start, end, &bits); | 966 | err = insert_state(tree, prealloc, start, end, &bits); |
948 | prealloc = NULL; | 967 | prealloc = NULL; |
949 | BUG_ON(err == -EEXIST); | 968 | if (err) |
969 | extent_io_tree_panic(tree, err); | ||
950 | goto out; | 970 | goto out; |
951 | } | 971 | } |
952 | state = rb_entry(node, struct extent_state, rb_node); | 972 | state = rb_entry(node, struct extent_state, rb_node); |
@@ -1002,7 +1022,8 @@ hit_next: | |||
1002 | goto out; | 1022 | goto out; |
1003 | } | 1023 | } |
1004 | err = split_state(tree, state, prealloc, start); | 1024 | err = split_state(tree, state, prealloc, start); |
1005 | BUG_ON(err == -EEXIST); | 1025 | if (err) |
1026 | extent_io_tree_panic(tree, err); | ||
1006 | prealloc = NULL; | 1027 | prealloc = NULL; |
1007 | if (err) | 1028 | if (err) |
1008 | goto out; | 1029 | goto out; |
@@ -1041,12 +1062,8 @@ hit_next: | |||
1041 | */ | 1062 | */ |
1042 | err = insert_state(tree, prealloc, start, this_end, | 1063 | err = insert_state(tree, prealloc, start, this_end, |
1043 | &bits); | 1064 | &bits); |
1044 | BUG_ON(err == -EEXIST); | 1065 | if (err) |
1045 | if (err) { | 1066 | extent_io_tree_panic(tree, err); |
1046 | free_extent_state(prealloc); | ||
1047 | prealloc = NULL; | ||
1048 | goto out; | ||
1049 | } | ||
1050 | prealloc = NULL; | 1067 | prealloc = NULL; |
1051 | start = this_end + 1; | 1068 | start = this_end + 1; |
1052 | goto search_again; | 1069 | goto search_again; |
@@ -1065,7 +1082,8 @@ hit_next: | |||
1065 | } | 1082 | } |
1066 | 1083 | ||
1067 | err = split_state(tree, state, prealloc, end + 1); | 1084 | err = split_state(tree, state, prealloc, end + 1); |
1068 | BUG_ON(err == -EEXIST); | 1085 | if (err) |
1086 | extent_io_tree_panic(tree, err); | ||
1069 | 1087 | ||
1070 | set_state_bits(tree, prealloc, &bits); | 1088 | set_state_bits(tree, prealloc, &bits); |
1071 | clear_state_bit(tree, prealloc, &clear_bits, 0); | 1089 | clear_state_bit(tree, prealloc, &clear_bits, 0); |