| From: Josef Bacik <josef@toxicpanda.com> |
| Date: Fri, 6 Dec 2019 09:37:17 -0500 |
| Subject: btrfs: skip log replay on orphaned roots |
| |
| commit 9bc574de590510eff899c3ca8dbaf013566b5efe upstream. |
| |
| My fsstress modifications coupled with generic/475 uncovered a failure |
| to mount and replay the log if we hit a orphaned root. We do not want |
| to replay the log for an orphan root, but it's completely legitimate to |
| have an orphaned root with a log attached. Fix this by simply skipping |
| replaying the log. We still need to pin it's root node so that we do |
| not overwrite it while replaying other logs, as we re-read the log root |
| at every stage of the replay. |
| |
| Reviewed-by: Filipe Manana <fdmanana@suse.com> |
| Signed-off-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| [bwh: Backported to 3.16: |
| - Pass fs_info->extent_root, instead of fs_info, as first argument to |
| btrfs_pin_extent_for_log_replay() |
| - Adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/fs/btrfs/tree-log.c |
| +++ b/fs/btrfs/tree-log.c |
| @@ -4583,9 +4583,29 @@ again: |
| wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); |
| if (IS_ERR(wc.replay_dest)) { |
| ret = PTR_ERR(wc.replay_dest); |
| + |
| + /* |
| + * We didn't find the subvol, likely because it was |
| + * deleted. This is ok, simply skip this log and go to |
| + * the next one. |
| + * |
| + * We need to exclude the root because we can't have |
| + * other log replays overwriting this log as we'll read |
| + * it back in a few more times. This will keep our |
| + * block from being modified, and we'll just bail for |
| + * each subsequent pass. |
| + */ |
| + if (ret == -ENOENT) |
| + ret = btrfs_pin_extent_for_log_replay( |
| + fs_info->extent_root, |
| + log->node->start, |
| + log->node->len); |
| free_extent_buffer(log->node); |
| free_extent_buffer(log->commit_root); |
| kfree(log); |
| + |
| + if (!ret) |
| + goto next; |
| btrfs_error(fs_info, ret, "Couldn't read target root " |
| "for tree log recovery."); |
| goto error; |
| @@ -4600,7 +4620,6 @@ again: |
| path); |
| } |
| |
| - key.offset = found_key.offset - 1; |
| wc.replay_dest->log_root = NULL; |
| free_extent_buffer(log->node); |
| free_extent_buffer(log->commit_root); |
| @@ -4608,9 +4627,10 @@ again: |
| |
| if (ret) |
| goto error; |
| - |
| +next: |
| if (found_key.offset == 0) |
| break; |
| + key.offset = found_key.offset - 1; |
| } |
| btrfs_release_path(path); |
| |