diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-06-29 23:15:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-21 21:21:31 -0400 |
commit | c701343cd0444bd9440a4236331e80f45c75ece2 (patch) | |
tree | edb845742a6f7584157d58544c5dc9a3e383b63c /fs | |
parent | 8049d11b3af40dc43b45017a1646ee6bd02287a1 (diff) |
Btrfs: hold the tree mod lock in __tree_mod_log_rewind
commit f1ca7e98a67da618d8595866e0860308525154da upstream.
We need to hold the tree mod log lock in __tree_mod_log_rewind since we walk
forward in the tree mod entries, otherwise we'll end up with random entries and
trip the BUG_ON() at the front of __tree_mod_log_rewind. This fixes the panics
people were seeing when running
find /whatever -type f -exec btrfs fi defrag {} \;
Thansk,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 02fae7f7e42c..2543d11b7d8b 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1161,8 +1161,8 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, | |||
1161 | * time_seq). | 1161 | * time_seq). |
1162 | */ | 1162 | */ |
1163 | static void | 1163 | static void |
1164 | __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq, | 1164 | __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, |
1165 | struct tree_mod_elem *first_tm) | 1165 | u64 time_seq, struct tree_mod_elem *first_tm) |
1166 | { | 1166 | { |
1167 | u32 n; | 1167 | u32 n; |
1168 | struct rb_node *next; | 1168 | struct rb_node *next; |
@@ -1172,6 +1172,7 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq, | |||
1172 | unsigned long p_size = sizeof(struct btrfs_key_ptr); | 1172 | unsigned long p_size = sizeof(struct btrfs_key_ptr); |
1173 | 1173 | ||
1174 | n = btrfs_header_nritems(eb); | 1174 | n = btrfs_header_nritems(eb); |
1175 | tree_mod_log_read_lock(fs_info); | ||
1175 | while (tm && tm->seq >= time_seq) { | 1176 | while (tm && tm->seq >= time_seq) { |
1176 | /* | 1177 | /* |
1177 | * all the operations are recorded with the operator used for | 1178 | * all the operations are recorded with the operator used for |
@@ -1226,6 +1227,7 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq, | |||
1226 | if (tm->index != first_tm->index) | 1227 | if (tm->index != first_tm->index) |
1227 | break; | 1228 | break; |
1228 | } | 1229 | } |
1230 | tree_mod_log_read_unlock(fs_info); | ||
1229 | btrfs_set_header_nritems(eb, n); | 1231 | btrfs_set_header_nritems(eb, n); |
1230 | } | 1232 | } |
1231 | 1233 | ||
@@ -1274,7 +1276,7 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, | |||
1274 | 1276 | ||
1275 | extent_buffer_get(eb_rewin); | 1277 | extent_buffer_get(eb_rewin); |
1276 | btrfs_tree_read_lock(eb_rewin); | 1278 | btrfs_tree_read_lock(eb_rewin); |
1277 | __tree_mod_log_rewind(eb_rewin, time_seq, tm); | 1279 | __tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm); |
1278 | WARN_ON(btrfs_header_nritems(eb_rewin) > | 1280 | WARN_ON(btrfs_header_nritems(eb_rewin) > |
1279 | BTRFS_NODEPTRS_PER_BLOCK(fs_info->tree_root)); | 1281 | BTRFS_NODEPTRS_PER_BLOCK(fs_info->tree_root)); |
1280 | 1282 | ||
@@ -1350,7 +1352,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1350 | btrfs_set_header_generation(eb, old_generation); | 1352 | btrfs_set_header_generation(eb, old_generation); |
1351 | } | 1353 | } |
1352 | if (tm) | 1354 | if (tm) |
1353 | __tree_mod_log_rewind(eb, time_seq, tm); | 1355 | __tree_mod_log_rewind(root->fs_info, eb, time_seq, tm); |
1354 | else | 1356 | else |
1355 | WARN_ON(btrfs_header_level(eb) != 0); | 1357 | WARN_ON(btrfs_header_level(eb) != 0); |
1356 | WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root)); | 1358 | WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root)); |