On Tue, Oct 30, 2018 at 7:00 AM robbieko <robbi...@synology.com> wrote:
>
> From: Robbie Ko <robbi...@synology.com>
>
> In apply_children_dir_moves, we first create an empty list (stack),
> then we get an entry from pending_dir_moves and add it to the stack,
> but we didn't delete the entry from rb_tree.
>
> So, in add_pending_dir_move, we create a new entry and then use the
> parent_ino in the current rb_tree to find the corresponding entry,
> and if so, add the new entry to the corresponding list.
>
> However, the entry may have been added to the stack, causing new
> entries to be added to the stack as well.
>
> Finally, each time we take the first entry from the stack and start
> processing, it ends up with an infinite loop.
>
> Fix this problem by remove node from pending_dir_moves,
> avoid add new pending_dir_move to error list.

I can't parse that explanation.
Can you give a concrete example (reproducer) or did this came out of thin air?

Thanks.

>
> Signed-off-by: Robbie Ko <robbi...@synology.com>
> ---
>  fs/btrfs/send.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
> index 094cc144..5be83b5 100644
> --- a/fs/btrfs/send.c
> +++ b/fs/btrfs/send.c
> @@ -3340,7 +3340,8 @@ static void free_pending_move(struct send_ctx *sctx, 
> struct pending_dir_move *m)
>         kfree(m);
>  }
>
> -static void tail_append_pending_moves(struct pending_dir_move *moves,
> +static void tail_append_pending_moves(struct send_ctx *sctx,
> +                                     struct pending_dir_move *moves,
>                                       struct list_head *stack)
>  {
>         if (list_empty(&moves->list)) {
> @@ -3351,6 +3352,10 @@ static void tail_append_pending_moves(struct 
> pending_dir_move *moves,
>                 list_add_tail(&moves->list, stack);
>                 list_splice_tail(&list, stack);
>         }
> +       if (!RB_EMPTY_NODE(&moves->node)) {
> +               rb_erase(&moves->node, &sctx->pending_dir_moves);
> +               RB_CLEAR_NODE(&moves->node);
> +       }
>  }
>
>  static int apply_children_dir_moves(struct send_ctx *sctx)
> @@ -3365,7 +3370,7 @@ static int apply_children_dir_moves(struct send_ctx 
> *sctx)
>                 return 0;
>
>         INIT_LIST_HEAD(&stack);
> -       tail_append_pending_moves(pm, &stack);
> +       tail_append_pending_moves(sctx, pm, &stack);
>
>         while (!list_empty(&stack)) {
>                 pm = list_first_entry(&stack, struct pending_dir_move, list);
> @@ -3376,7 +3381,7 @@ static int apply_children_dir_moves(struct send_ctx 
> *sctx)
>                         goto out;
>                 pm = get_pending_dir_moves(sctx, parent_ino);
>                 if (pm)
> -                       tail_append_pending_moves(pm, &stack);
> +                       tail_append_pending_moves(sctx, pm, &stack);
>         }
>         return 0;
>
> --
> 1.9.1
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”

Reply via email to