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.”