[4/5] btrfs: skip log replay on orphaned roots
diff mbox series

Message ID 20191206143718.167998-5-josef@toxicpanda.com
State New
Headers show
Series
  • Various fixes
Related show

Commit Message

Josef Bacik Dec. 6, 2019, 2:37 p.m. UTC
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.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/tree-log.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

Comments

Filipe Manana Dec. 6, 2019, 3:23 p.m. UTC | #1
On Fri, Dec 6, 2019 at 2:38 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> 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.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Reviewed-by: Filipe Manana <fdmanana@suse.com>

Looks good, thanks.

> ---
>  fs/btrfs/tree-log.c | 23 +++++++++++++++++++++--
>  1 file changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
> index 6f757361db53..4bbb4fd490b5 100644
> --- a/fs/btrfs/tree-log.c
> +++ b/fs/btrfs/tree-log.c
> @@ -6294,9 +6294,28 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
>                 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,
> +                                                       log->node->start,
> +                                                       log->node->len);
>                         free_extent_buffer(log->node);
>                         free_extent_buffer(log->commit_root);
>                         kfree(log);
> +
> +                       if (!ret)
> +                               goto next;
>                         btrfs_handle_fs_error(fs_info, ret,
>                                 "Couldn't read target root for tree log recovery.");
>                         goto error;
> @@ -6328,7 +6347,6 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
>                                                   &root->highest_objectid);
>                 }
>
> -               key.offset = found_key.offset - 1;
>                 wc.replay_dest->log_root = NULL;
>                 free_extent_buffer(log->node);
>                 free_extent_buffer(log->commit_root);
> @@ -6336,9 +6354,10 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
>
>                 if (ret)
>                         goto error;
> -
> +next:
>                 if (found_key.offset == 0)
>                         break;
> +               key.offset = found_key.offset - 1;
>         }
>         btrfs_release_path(path);
>
> --
> 2.23.0
>

Patch
diff mbox series

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 6f757361db53..4bbb4fd490b5 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -6294,9 +6294,28 @@  int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 		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,
+							log->node->start,
+							log->node->len);
 			free_extent_buffer(log->node);
 			free_extent_buffer(log->commit_root);
 			kfree(log);
+
+			if (!ret)
+				goto next;
 			btrfs_handle_fs_error(fs_info, ret,
 				"Couldn't read target root for tree log recovery.");
 			goto error;
@@ -6328,7 +6347,6 @@  int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 						  &root->highest_objectid);
 		}
 
-		key.offset = found_key.offset - 1;
 		wc.replay_dest->log_root = NULL;
 		free_extent_buffer(log->node);
 		free_extent_buffer(log->commit_root);
@@ -6336,9 +6354,10 @@  int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 
 		if (ret)
 			goto error;
-
+next:
 		if (found_key.offset == 0)
 			break;
+		key.offset = found_key.offset - 1;
 	}
 	btrfs_release_path(path);