diff options
author | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-06-21 04:59:13 -0400 |
---|---|---|
committer | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-06-27 10:34:38 -0400 |
commit | 28da9fb4467f7a650cd31af6dfad3a4e4a3abf6e (patch) | |
tree | 433fad6b6d2b64b8ce3f97f759347097b851e6b4 /fs/btrfs | |
parent | 9345457f4a539a40056431aeb6f068750857472f (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.c | 28 |
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; |