aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2012-06-21 04:59:13 -0400
committerJan Schmidt <list.btrfs@jan-o-sch.net>2012-06-27 10:34:38 -0400
commit28da9fb4467f7a650cd31af6dfad3a4e4a3abf6e (patch)
tree433fad6b6d2b64b8ce3f97f759347097b851e6b4 /fs/btrfs
parent9345457f4a539a40056431aeb6f068750857472f (diff)
Btrfs: fix tree mod log for root replacements at leaf level
For the tree mod log, we don't log any operations at leaf level. If the root is at the leaf level (i.e. the tree consists only of the root), then __tree_mod_log_oldest_root will find a ROOT_REPLACE operation in the log (because we always log that one no matter which level), but no other operations. With this patch __tree_mod_log_oldest_root exits cleanly instead of BUGging in this situation. get_old_root checks if its really a root at leaf level in case we don't have any operations and WARNs if this assumption breaks. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c28
1 files changed, 15 insertions, 13 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 15cbc2bf4ff0..7d1e4fc5fb6a 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1024,11 +1024,18 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
1024 if (!looped && !tm) 1024 if (!looped && !tm)
1025 return 0; 1025 return 0;
1026 /* 1026 /*
1027 * we must have key remove operations in the log before the 1027 * if there are no tree operation for the oldest root, we simply
1028 * replace operation. 1028 * return it. this should only happen if that (old) root is at
1029 * level 0.
1029 */ 1030 */
1030 BUG_ON(!tm); 1031 if (!tm)
1032 break;
1031 1033
1034 /*
1035 * if there's an operation that's not a root replacement, we
1036 * found the oldest version of our root. normally, we'll find a
1037 * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here.
1038 */
1032 if (tm->op != MOD_LOG_ROOT_REPLACE) 1039 if (tm->op != MOD_LOG_ROOT_REPLACE)
1033 break; 1040 break;
1034 1041
@@ -1192,16 +1199,8 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
1192 } 1199 }
1193 1200
1194 tm = tree_mod_log_search(root->fs_info, logical, time_seq); 1201 tm = tree_mod_log_search(root->fs_info, logical, time_seq);
1195 /*
1196 * there was an item in the log when __tree_mod_log_oldest_root
1197 * returned. this one must not go away, because the time_seq passed to
1198 * us must be blocking its removal.
1199 */
1200 BUG_ON(!tm);
1201
1202 if (old_root) 1202 if (old_root)
1203 eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, 1203 eb = alloc_dummy_extent_buffer(logical, root->nodesize);
1204 root->nodesize);
1205 else 1204 else
1206 eb = btrfs_clone_extent_buffer(root->node); 1205 eb = btrfs_clone_extent_buffer(root->node);
1207 btrfs_tree_read_unlock(root->node); 1206 btrfs_tree_read_unlock(root->node);
@@ -1216,7 +1215,10 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
1216 btrfs_set_header_level(eb, old_root->level); 1215 btrfs_set_header_level(eb, old_root->level);
1217 btrfs_set_header_generation(eb, old_generation); 1216 btrfs_set_header_generation(eb, old_generation);
1218 } 1217 }
1219 __tree_mod_log_rewind(eb, time_seq, tm); 1218 if (tm)
1219 __tree_mod_log_rewind(eb, time_seq, tm);
1220 else
1221 WARN_ON(btrfs_header_level(eb) != 0);
1220 extent_buffer_get(eb); 1222 extent_buffer_get(eb);
1221 1223
1222 return eb; 1224 return eb;