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:54 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:47 -0400
commit30b0463a9394d9e41596e96def5461fe33222f13 (patch)
treeda71470b17140319065525250062db98f0bf5e15 /fs/btrfs/ctree.c
parent90f8d62ebb55e2188c1618b650378f9857f9e9a4 (diff)
Btrfs: fix accessing the root pointer in tree mod log functions
The tree mod log functions were accessing root->node->... directly, without use of btrfs_root_node() or explicit rcu locking. This could lead to an extent buffer reference being leaked and another reference being freed too early when preemtion was enabled. 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.c40
1 files changed, 20 insertions, 20 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 1180209965db..d7e0576038fb 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1069,11 +1069,11 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
1069 */ 1069 */
1070static struct tree_mod_elem * 1070static struct tree_mod_elem *
1071__tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, 1071__tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
1072 struct btrfs_root *root, u64 time_seq) 1072 struct extent_buffer *eb_root, u64 time_seq)
1073{ 1073{
1074 struct tree_mod_elem *tm; 1074 struct tree_mod_elem *tm;
1075 struct tree_mod_elem *found = NULL; 1075 struct tree_mod_elem *found = NULL;
1076 u64 root_logical = root->node->start; 1076 u64 root_logical = eb_root->start;
1077 int looped = 0; 1077 int looped = 0;
1078 1078
1079 if (!time_seq) 1079 if (!time_seq)
@@ -1107,7 +1107,6 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
1107 1107
1108 found = tm; 1108 found = tm;
1109 root_logical = tm->old_root.logical; 1109 root_logical = tm->old_root.logical;
1110 BUG_ON(root_logical == root->node->start);
1111 looped = 1; 1110 looped = 1;
1112 } 1111 }
1113 1112
@@ -1245,30 +1244,31 @@ static inline struct extent_buffer *
1245get_old_root(struct btrfs_root *root, u64 time_seq) 1244get_old_root(struct btrfs_root *root, u64 time_seq)
1246{ 1245{
1247 struct tree_mod_elem *tm; 1246 struct tree_mod_elem *tm;
1248 struct extent_buffer *eb; 1247 struct extent_buffer *eb = NULL;
1248 struct extent_buffer *eb_root;
1249 struct extent_buffer *old; 1249 struct extent_buffer *old;
1250 struct tree_mod_root *old_root = NULL; 1250 struct tree_mod_root *old_root = NULL;
1251 u64 old_generation = 0; 1251 u64 old_generation = 0;
1252 u64 logical; 1252 u64 logical;
1253 u32 blocksize; 1253 u32 blocksize;
1254 1254
1255 eb = btrfs_read_lock_root_node(root); 1255 eb_root = btrfs_read_lock_root_node(root);
1256 tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); 1256 tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
1257 if (!tm) 1257 if (!tm)
1258 return root->node; 1258 return eb_root;
1259 1259
1260 if (tm->op == MOD_LOG_ROOT_REPLACE) { 1260 if (tm->op == MOD_LOG_ROOT_REPLACE) {
1261 old_root = &tm->old_root; 1261 old_root = &tm->old_root;
1262 old_generation = tm->generation; 1262 old_generation = tm->generation;
1263 logical = old_root->logical; 1263 logical = old_root->logical;
1264 } else { 1264 } else {
1265 logical = root->node->start; 1265 logical = eb_root->start;
1266 } 1266 }
1267 1267
1268 tm = tree_mod_log_search(root->fs_info, logical, time_seq); 1268 tm = tree_mod_log_search(root->fs_info, logical, time_seq);
1269 if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) { 1269 if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
1270 btrfs_tree_read_unlock(root->node); 1270 btrfs_tree_read_unlock(eb_root);
1271 free_extent_buffer(root->node); 1271 free_extent_buffer(eb_root);
1272 blocksize = btrfs_level_size(root, old_root->level); 1272 blocksize = btrfs_level_size(root, old_root->level);
1273 old = read_tree_block(root, logical, blocksize, 0); 1273 old = read_tree_block(root, logical, blocksize, 0);
1274 if (!old) { 1274 if (!old) {
@@ -1280,13 +1280,13 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
1280 free_extent_buffer(old); 1280 free_extent_buffer(old);
1281 } 1281 }
1282 } else if (old_root) { 1282 } else if (old_root) {
1283 btrfs_tree_read_unlock(root->node); 1283 btrfs_tree_read_unlock(eb_root);
1284 free_extent_buffer(root->node); 1284 free_extent_buffer(eb_root);
1285 eb = alloc_dummy_extent_buffer(logical, root->nodesize); 1285 eb = alloc_dummy_extent_buffer(logical, root->nodesize);
1286 } else { 1286 } else {
1287 eb = btrfs_clone_extent_buffer(root->node); 1287 eb = btrfs_clone_extent_buffer(eb_root);
1288 btrfs_tree_read_unlock(root->node); 1288 btrfs_tree_read_unlock(eb_root);
1289 free_extent_buffer(root->node); 1289 free_extent_buffer(eb_root);
1290 } 1290 }
1291 1291
1292 if (!eb) 1292 if (!eb)
@@ -1296,7 +1296,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
1296 if (old_root) { 1296 if (old_root) {
1297 btrfs_set_header_bytenr(eb, eb->start); 1297 btrfs_set_header_bytenr(eb, eb->start);
1298 btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); 1298 btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);
1299 btrfs_set_header_owner(eb, root->root_key.objectid); 1299 btrfs_set_header_owner(eb, btrfs_header_owner(eb_root));
1300 btrfs_set_header_level(eb, old_root->level); 1300 btrfs_set_header_level(eb, old_root->level);
1301 btrfs_set_header_generation(eb, old_generation); 1301 btrfs_set_header_generation(eb, old_generation);
1302 } 1302 }
@@ -1313,15 +1313,15 @@ int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
1313{ 1313{
1314 struct tree_mod_elem *tm; 1314 struct tree_mod_elem *tm;
1315 int level; 1315 int level;
1316 struct extent_buffer *eb_root = btrfs_root_node(root);
1316 1317
1317 tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); 1318 tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
1318 if (tm && tm->op == MOD_LOG_ROOT_REPLACE) { 1319 if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
1319 level = tm->old_root.level; 1320 level = tm->old_root.level;
1320 } else { 1321 } else {
1321 rcu_read_lock(); 1322 level = btrfs_header_level(eb_root);
1322 level = btrfs_header_level(root->node);
1323 rcu_read_unlock();
1324 } 1323 }
1324 free_extent_buffer(eb_root);
1325 1325
1326 return level; 1326 return level;
1327} 1327}