aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2013-04-13 09:19:55 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:48 -0400
commit47fb091fb787420cd195e66f162737401cce023f (patch)
tree0214d77b462613aa605d3107633bec7445d53d57 /fs/btrfs/ctree.c
parent30b0463a9394d9e41596e96def5461fe33222f13 (diff)
Btrfs: fix unlock after free on rewinded tree blocks
When tree_mod_log_rewind decides to make a copy of the current tree buffer for its modifications, it subsequently freed the buffer before unlocking it. Obviously, those operations are required in reverse order. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index d7e0576038fb..c3c3d37f9c58 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1191,6 +1191,13 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq,
1191 btrfs_set_header_nritems(eb, n); 1191 btrfs_set_header_nritems(eb, n);
1192} 1192}
1193 1193
1194/*
1195 * Called with eb read locked. If the buffer cannot be rewinded, the same buffer
1196 * is returned. If rewind operations happen, a fresh buffer is returned. The
1197 * returned buffer is always read-locked. If the returned buffer is not the
1198 * input buffer, the lock on the input buffer is released and the input buffer
1199 * is freed (its refcount is decremented).
1200 */
1194static struct extent_buffer * 1201static struct extent_buffer *
1195tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, 1202tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
1196 u64 time_seq) 1203 u64 time_seq)
@@ -1224,8 +1231,11 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
1224 } 1231 }
1225 1232
1226 extent_buffer_get(eb_rewin); 1233 extent_buffer_get(eb_rewin);
1234 btrfs_tree_read_unlock(eb);
1227 free_extent_buffer(eb); 1235 free_extent_buffer(eb);
1228 1236
1237 extent_buffer_get(eb_rewin);
1238 btrfs_tree_read_lock(eb_rewin);
1229 __tree_mod_log_rewind(eb_rewin, time_seq, tm); 1239 __tree_mod_log_rewind(eb_rewin, time_seq, tm);
1230 WARN_ON(btrfs_header_nritems(eb_rewin) > 1240 WARN_ON(btrfs_header_nritems(eb_rewin) >
1231 BTRFS_NODEPTRS_PER_BLOCK(fs_info->tree_root)); 1241 BTRFS_NODEPTRS_PER_BLOCK(fs_info->tree_root));
@@ -2794,15 +2804,9 @@ again:
2794 btrfs_clear_path_blocking(p, b, 2804 btrfs_clear_path_blocking(p, b,
2795 BTRFS_READ_LOCK); 2805 BTRFS_READ_LOCK);
2796 } 2806 }
2807 b = tree_mod_log_rewind(root->fs_info, b, time_seq);
2797 p->locks[level] = BTRFS_READ_LOCK; 2808 p->locks[level] = BTRFS_READ_LOCK;
2798 p->nodes[level] = b; 2809 p->nodes[level] = b;
2799 b = tree_mod_log_rewind(root->fs_info, b, time_seq);
2800 if (b != p->nodes[level]) {
2801 btrfs_tree_unlock_rw(p->nodes[level],
2802 p->locks[level]);
2803 p->locks[level] = 0;
2804 p->nodes[level] = b;
2805 }
2806 } else { 2810 } else {
2807 p->slots[level] = slot; 2811 p->slots[level] = slot;
2808 unlock_up(p, level, lowest_unlock, 0, NULL); 2812 unlock_up(p, level, lowest_unlock, 0, NULL);