aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-06-29 23:15:19 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-07-02 11:51:18 -0400
commitf1ca7e98a67da618d8595866e0860308525154da (patch)
tree55e4374235a9d6eee5068e55e1297d97cbe859e8 /fs/btrfs
parent261c84b662f93e0eb75bccd6cd732391d005060a (diff)
Btrfs: hold the tree mod lock in __tree_mod_log_rewind
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, Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index c32d03dff4fc..7921e1d9d59c 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 */
1163static void 1163static 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));