Btrfs: share the same code for __record_{new,deleted}_ref
[cascardo/linux.git] / fs / btrfs / send.c
index cb9502a..112eb64 100644 (file)
@@ -112,6 +112,7 @@ struct send_ctx {
        int cur_inode_deleted;
        u64 cur_inode_size;
        u64 cur_inode_mode;
+       u64 cur_inode_rdev;
        u64 cur_inode_last_extent;
 
        u64 send_progress;
@@ -178,6 +179,47 @@ struct send_ctx {
         * own move/rename can be performed.
         */
        struct rb_root waiting_dir_moves;
+
+       /*
+        * A directory that is going to be rm'ed might have a child directory
+        * which is in the pending directory moves index above. In this case,
+        * the directory can only be removed after the move/rename of its child
+        * is performed. Example:
+        *
+        * Parent snapshot:
+        *
+        * .                        (ino 256)
+        * |-- a/                   (ino 257)
+        *     |-- b/               (ino 258)
+        *         |-- c/           (ino 259)
+        *         |   |-- x/       (ino 260)
+        *         |
+        *         |-- y/           (ino 261)
+        *
+        * Send snapshot:
+        *
+        * .                        (ino 256)
+        * |-- a/                   (ino 257)
+        *     |-- b/               (ino 258)
+        *         |-- YY/          (ino 261)
+        *              |-- x/      (ino 260)
+        *
+        * Sequence of steps that lead to the send snapshot:
+        * rm -f /a/b/c/foo.txt
+        * mv /a/b/y /a/b/YY
+        * mv /a/b/c/x /a/b/YY
+        * rmdir /a/b/c
+        *
+        * When the child is processed, its move/rename is delayed until its
+        * parent is processed (as explained above), but all other operations
+        * like update utimes, chown, chgrp, etc, are performed and the paths
+        * that it uses for those operations must use the orphanized name of
+        * its parent (the directory we're going to rm later), so we need to
+        * memorize that name.
+        *
+        * Indexed by the inode number of the directory to be deleted.
+        */
+       struct rb_root orphan_dirs;
 };
 
 struct pending_dir_move {
@@ -192,6 +234,18 @@ struct pending_dir_move {
 struct waiting_dir_move {
        struct rb_node node;
        u64 ino;
+       /*
+        * There might be some directory that could not be removed because it
+        * was waiting for this directory inode to be moved first. Therefore
+        * after this directory is moved, we can try to rmdir the ino rmdir_ino.
+        */
+       u64 rmdir_ino;
+};
+
+struct orphan_dir_info {
+       struct rb_node node;
+       u64 ino;
+       u64 gen;
 };
 
 struct name_cache_entry {
@@ -217,6 +271,11 @@ struct name_cache_entry {
 
 static int is_waiting_for_move(struct send_ctx *sctx, u64 ino);
 
+static struct waiting_dir_move *
+get_waiting_dir_move(struct send_ctx *sctx, u64 ino);
+
+static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino);
+
 static int need_send_hole(struct send_ctx *sctx)
 {
        return (sctx->parent_root && !sctx->cur_inode_new &&
@@ -288,30 +347,24 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
        if (p->buf_len >= len)
                return 0;
 
+       path_len = p->end - p->start;
+       old_buf_len = p->buf_len;
+
        /*
         * First time the inline_buf does not suffice
         */
-       if (p->buf == p->inline_buf) {
-               p->buf = kmalloc(len, GFP_NOFS);
-               if (!p->buf)
-                       return -ENOMEM;
-               /*
-                * The real size of the buffer is bigger, this will let the
-                * fast path happen most of the time
-                */
-               p->buf_len = ksize(p->buf);
-       } else {
-               char *tmp;
-
-               tmp = krealloc(p->buf, len, GFP_NOFS);
-               if (!tmp)
-                       return -ENOMEM;
-               p->buf = tmp;
-               p->buf_len = ksize(p->buf);
-       }
-
-       path_len = p->end - p->start;
-       old_buf_len = p->buf_len;
+       if (p->buf == p->inline_buf)
+               tmp_buf = kmalloc(len, GFP_NOFS);
+       else
+               tmp_buf = krealloc(p->buf, len, GFP_NOFS);
+       if (!tmp_buf)
+               return -ENOMEM;
+       p->buf = tmp_buf;
+       /*
+        * The real size of the buffer is bigger, this will let the fast path
+        * happen most of the time
+        */
+       p->buf_len = ksize(p->buf);
 
        if (p->reversed) {
                tmp_buf = p->buf + old_buf_len - path_len - 1;
@@ -1942,7 +1995,6 @@ static void name_cache_free(struct send_ctx *sctx)
  */
 static int __get_cur_name_and_parent(struct send_ctx *sctx,
                                     u64 ino, u64 gen,
-                                    int skip_name_cache,
                                     u64 *parent_ino,
                                     u64 *parent_gen,
                                     struct fs_path *dest)
@@ -1952,8 +2004,6 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
        struct btrfs_path *path = NULL;
        struct name_cache_entry *nce = NULL;
 
-       if (skip_name_cache)
-               goto get_ref;
        /*
         * First check if we already did a call to this function with the same
         * ino/gen. If yes, check if the cache entry is still up-to-date. If yes
@@ -1998,12 +2048,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
                goto out_cache;
        }
 
-get_ref:
        /*
         * Depending on whether the inode was already processed or not, use
         * send_root or parent_root for ref lookup.
         */
-       if (ino < sctx->send_progress && !skip_name_cache)
+       if (ino < sctx->send_progress)
                ret = get_first_ref(sctx->send_root, ino,
                                    parent_ino, parent_gen, dest);
        else
@@ -2027,8 +2076,6 @@ get_ref:
                        goto out;
                ret = 1;
        }
-       if (skip_name_cache)
-               goto out;
 
 out_cache:
        /*
@@ -2096,7 +2143,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
        u64 parent_inode = 0;
        u64 parent_gen = 0;
        int stop = 0;
-       int skip_name_cache = 0;
 
        name = fs_path_alloc();
        if (!name) {
@@ -2104,25 +2150,33 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
                goto out;
        }
 
-       if (is_waiting_for_move(sctx, ino))
-               skip_name_cache = 1;
-
        dest->reversed = 1;
        fs_path_reset(dest);
 
        while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) {
                fs_path_reset(name);
 
-               ret = __get_cur_name_and_parent(sctx, ino, gen, skip_name_cache,
-                               &parent_inode, &parent_gen, name);
+               if (is_waiting_for_rm(sctx, ino)) {
+                       ret = gen_unique_name(sctx, ino, gen, name);
+                       if (ret < 0)
+                               goto out;
+                       ret = fs_path_add_path(dest, name);
+                       break;
+               }
+
+               if (is_waiting_for_move(sctx, ino)) {
+                       ret = get_first_ref(sctx->parent_root, ino,
+                                           &parent_inode, &parent_gen, name);
+               } else {
+                       ret = __get_cur_name_and_parent(sctx, ino, gen,
+                                                       &parent_inode,
+                                                       &parent_gen, name);
+                       if (ret)
+                               stop = 1;
+               }
+
                if (ret < 0)
                        goto out;
-               if (ret)
-                       stop = 1;
-
-               if (!skip_name_cache &&
-                   is_waiting_for_move(sctx, parent_inode))
-                       skip_name_cache = 1;
 
                ret = fs_path_add_path(dest, name);
                if (ret < 0)
@@ -2386,10 +2440,16 @@ verbose_printk("btrfs: send_create_inode %llu\n", ino);
        if (!p)
                return -ENOMEM;
 
-       ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, NULL,
-                       NULL, &rdev);
-       if (ret < 0)
-               goto out;
+       if (ino != sctx->cur_ino) {
+               ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode,
+                                    NULL, NULL, &rdev);
+               if (ret < 0)
+                       goto out;
+       } else {
+               gen = sctx->cur_inode_gen;
+               mode = sctx->cur_inode_mode;
+               rdev = sctx->cur_inode_rdev;
+       }
 
        if (S_ISREG(mode)) {
                cmd = BTRFS_SEND_C_MKFILE;
@@ -2555,7 +2615,7 @@ struct recorded_ref {
  * everything mixed. So we first record all refs and later process them.
  * This function is a helper to record one ref.
  */
-static int record_ref(struct list_head *head, u64 dir,
+static int __record_ref(struct list_head *head, u64 dir,
                      u64 dir_gen, struct fs_path *path)
 {
        struct recorded_ref *ref;
@@ -2641,12 +2701,78 @@ out:
        return ret;
 }
 
+static struct orphan_dir_info *
+add_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino)
+{
+       struct rb_node **p = &sctx->orphan_dirs.rb_node;
+       struct rb_node *parent = NULL;
+       struct orphan_dir_info *entry, *odi;
+
+       odi = kmalloc(sizeof(*odi), GFP_NOFS);
+       if (!odi)
+               return ERR_PTR(-ENOMEM);
+       odi->ino = dir_ino;
+       odi->gen = 0;
+
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, struct orphan_dir_info, node);
+               if (dir_ino < entry->ino) {
+                       p = &(*p)->rb_left;
+               } else if (dir_ino > entry->ino) {
+                       p = &(*p)->rb_right;
+               } else {
+                       kfree(odi);
+                       return entry;
+               }
+       }
+
+       rb_link_node(&odi->node, parent, p);
+       rb_insert_color(&odi->node, &sctx->orphan_dirs);
+       return odi;
+}
+
+static struct orphan_dir_info *
+get_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino)
+{
+       struct rb_node *n = sctx->orphan_dirs.rb_node;
+       struct orphan_dir_info *entry;
+
+       while (n) {
+               entry = rb_entry(n, struct orphan_dir_info, node);
+               if (dir_ino < entry->ino)
+                       n = n->rb_left;
+               else if (dir_ino > entry->ino)
+                       n = n->rb_right;
+               else
+                       return entry;
+       }
+       return NULL;
+}
+
+static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino)
+{
+       struct orphan_dir_info *odi = get_orphan_dir_info(sctx, dir_ino);
+
+       return odi != NULL;
+}
+
+static void free_orphan_dir_info(struct send_ctx *sctx,
+                                struct orphan_dir_info *odi)
+{
+       if (!odi)
+               return;
+       rb_erase(&odi->node, &sctx->orphan_dirs);
+       kfree(odi);
+}
+
 /*
  * Returns 1 if a directory can be removed at this point in time.
  * We check this by iterating all dir items and checking if the inode behind
  * the dir item was already processed.
  */
-static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress)
+static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen,
+                    u64 send_progress)
 {
        int ret = 0;
        struct btrfs_root *root = sctx->parent_root;
@@ -2674,6 +2800,8 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress)
                goto out;
 
        while (1) {
+               struct waiting_dir_move *dm;
+
                if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
                        ret = btrfs_next_leaf(root, path);
                        if (ret < 0)
@@ -2692,6 +2820,21 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress)
                                struct btrfs_dir_item);
                btrfs_dir_item_key_to_cpu(path->nodes[0], di, &loc);
 
+               dm = get_waiting_dir_move(sctx, loc.objectid);
+               if (dm) {
+                       struct orphan_dir_info *odi;
+
+                       odi = add_orphan_dir_info(sctx, dir);
+                       if (IS_ERR(odi)) {
+                               ret = PTR_ERR(odi);
+                               goto out;
+                       }
+                       odi->gen = dir_gen;
+                       dm->rmdir_ino = dir;
+                       ret = 0;
+                       goto out;
+               }
+
                if (loc.objectid > send_progress) {
                        ret = 0;
                        goto out;
@@ -2709,19 +2852,9 @@ out:
 
 static int is_waiting_for_move(struct send_ctx *sctx, u64 ino)
 {
-       struct rb_node *n = sctx->waiting_dir_moves.rb_node;
-       struct waiting_dir_move *entry;
+       struct waiting_dir_move *entry = get_waiting_dir_move(sctx, ino);
 
-       while (n) {
-               entry = rb_entry(n, struct waiting_dir_move, node);
-               if (ino < entry->ino)
-                       n = n->rb_left;
-               else if (ino > entry->ino)
-                       n = n->rb_right;
-               else
-                       return 1;
-       }
-       return 0;
+       return entry != NULL;
 }
 
 static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
@@ -2734,6 +2867,7 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
        if (!dm)
                return -ENOMEM;
        dm->ino = ino;
+       dm->rmdir_ino = 0;
 
        while (*p) {
                parent = *p;
@@ -2753,24 +2887,31 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
        return 0;
 }
 
-static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino)
+static struct waiting_dir_move *
+get_waiting_dir_move(struct send_ctx *sctx, u64 ino)
 {
        struct rb_node *n = sctx->waiting_dir_moves.rb_node;
        struct waiting_dir_move *entry;
 
        while (n) {
                entry = rb_entry(n, struct waiting_dir_move, node);
-               if (ino < entry->ino) {
+               if (ino < entry->ino)
                        n = n->rb_left;
-               } else if (ino > entry->ino) {
+               else if (ino > entry->ino)
                        n = n->rb_right;
-               } else {
-                       rb_erase(&entry->node, &sctx->waiting_dir_moves);
-                       kfree(entry);
-                       return 0;
-               }
+               else
+                       return entry;
        }
-       return -ENOENT;
+       return NULL;
+}
+
+static void free_waiting_dir_move(struct send_ctx *sctx,
+                                 struct waiting_dir_move *dm)
+{
+       if (!dm)
+               return;
+       rb_erase(&dm->node, &sctx->waiting_dir_moves);
+       kfree(dm);
 }
 
 static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino)
@@ -2861,6 +3002,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        u64 orig_progress = sctx->send_progress;
        struct recorded_ref *cur;
        u64 parent_ino, parent_gen;
+       struct waiting_dir_move *dm = NULL;
+       u64 rmdir_ino = 0;
        int ret;
 
        name = fs_path_alloc();
@@ -2870,8 +3013,10 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                goto out;
        }
 
-       ret = del_waiting_dir_move(sctx, pm->ino);
-       ASSERT(ret == 0);
+       dm = get_waiting_dir_move(sctx, pm->ino);
+       ASSERT(dm);
+       rmdir_ino = dm->rmdir_ino;
+       free_waiting_dir_move(sctx, dm);
 
        ret = get_first_ref(sctx->parent_root, pm->ino,
                            &parent_ino, &parent_gen, name);
@@ -2914,6 +3059,35 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        if (ret < 0)
                goto out;
 
+       if (rmdir_ino) {
+               struct orphan_dir_info *odi;
+
+               odi = get_orphan_dir_info(sctx, rmdir_ino);
+               if (!odi) {
+                       /* already deleted */
+                       goto finish;
+               }
+               ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino + 1);
+               if (ret < 0)
+                       goto out;
+               if (!ret)
+                       goto finish;
+
+               name = fs_path_alloc();
+               if (!name) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               ret = get_cur_path(sctx, rmdir_ino, odi->gen, name);
+               if (ret < 0)
+                       goto out;
+               ret = send_rmdir(sctx, name);
+               if (ret < 0)
+                       goto out;
+               free_orphan_dir_info(sctx, odi);
+       }
+
+finish:
        ret = send_utimes(sctx, pm->ino, pm->gen);
        if (ret < 0)
                goto out;
@@ -2923,6 +3097,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
         * and old parent(s).
         */
        list_for_each_entry(cur, &pm->update_refs, list) {
+               if (cur->dir == rmdir_ino)
+                       continue;
                ret = send_utimes(sctx, cur->dir, cur->dir_gen);
                if (ret < 0)
                        goto out;
@@ -3085,6 +3261,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
        u64 ow_gen;
        int did_overwrite = 0;
        int is_orphan = 0;
+       u64 last_dir_ino_rm = 0;
 
 verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
 
@@ -3258,7 +3435,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                 * later, we do this check again and rmdir it then if possible.
                 * See the use of check_dirs for more details.
                 */
-               ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_ino);
+               ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_inode_gen,
+                               sctx->cur_ino);
                if (ret < 0)
                        goto out;
                if (ret) {
@@ -3349,8 +3527,10 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        ret = send_utimes(sctx, cur->dir, cur->dir_gen);
                        if (ret < 0)
                                goto out;
-               } else if (ret == inode_state_did_delete) {
-                       ret = can_rmdir(sctx, cur->dir, sctx->cur_ino);
+               } else if (ret == inode_state_did_delete &&
+                          cur->dir != last_dir_ino_rm) {
+                       ret = can_rmdir(sctx, cur->dir, cur->dir_gen,
+                                       sctx->cur_ino);
                        if (ret < 0)
                                goto out;
                        if (ret) {
@@ -3361,6 +3541,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                ret = send_rmdir(sctx, valid_path);
                                if (ret < 0)
                                        goto out;
+                               last_dir_ino_rm = cur->dir;
                        }
                }
        }
@@ -3374,9 +3555,8 @@ out:
        return ret;
 }
 
-static int __record_new_ref(int num, u64 dir, int index,
-                           struct fs_path *name,
-                           void *ctx)
+static int record_ref(struct btrfs_root *root, int num, u64 dir, int index,
+                     struct fs_path *name, void *ctx, struct list_head *refs)
 {
        int ret = 0;
        struct send_ctx *sctx = ctx;
@@ -3387,7 +3567,7 @@ static int __record_new_ref(int num, u64 dir, int index,
        if (!p)
                return -ENOMEM;
 
-       ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, NULL,
+       ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL,
                        NULL, NULL);
        if (ret < 0)
                goto out;
@@ -3399,7 +3579,7 @@ static int __record_new_ref(int num, u64 dir, int index,
        if (ret < 0)
                goto out;
 
-       ret = record_ref(&sctx->new_refs, dir, gen, p);
+       ret = __record_ref(refs, dir, gen, p);
 
 out:
        if (ret)
@@ -3407,37 +3587,23 @@ out:
        return ret;
 }
 
+static int __record_new_ref(int num, u64 dir, int index,
+                           struct fs_path *name,
+                           void *ctx)
+{
+       struct send_ctx *sctx = ctx;
+       return record_ref(sctx->send_root, num, dir, index, name,
+                         ctx, &sctx->new_refs);
+}
+
+
 static int __record_deleted_ref(int num, u64 dir, int index,
                                struct fs_path *name,
                                void *ctx)
 {
-       int ret = 0;
        struct send_ctx *sctx = ctx;
-       struct fs_path *p;
-       u64 gen;
-
-       p = fs_path_alloc();
-       if (!p)
-               return -ENOMEM;
-
-       ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, NULL,
-                       NULL, NULL);
-       if (ret < 0)
-               goto out;
-
-       ret = get_cur_path(sctx, dir, gen, p);
-       if (ret < 0)
-               goto out;
-       ret = fs_path_add_path(p, name);
-       if (ret < 0)
-               goto out;
-
-       ret = record_ref(&sctx->deleted_refs, dir, gen, p);
-
-out:
-       if (ret)
-               fs_path_free(p);
-       return ret;
+       return record_ref(sctx->parent_root, num, dir, index, name,
+                         ctx, &sctx->deleted_refs);
 }
 
 static int record_new_ref(struct send_ctx *sctx)
@@ -4776,18 +4942,19 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
                ret = apply_children_dir_moves(sctx);
                if (ret)
                        goto out;
+               /*
+                * Need to send that every time, no matter if it actually
+                * changed between the two trees as we have done changes to
+                * the inode before. If our inode is a directory and it's
+                * waiting to be moved/renamed, we will send its utimes when
+                * it's moved/renamed, therefore we don't need to do it here.
+                */
+               sctx->send_progress = sctx->cur_ino + 1;
+               ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen);
+               if (ret < 0)
+                       goto out;
        }
 
-       /*
-        * Need to send that every time, no matter if it actually
-        * changed between the two trees as we have done changes to
-        * the inode before.
-        */
-       sctx->send_progress = sctx->cur_ino + 1;
-       ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen);
-       if (ret < 0)
-               goto out;
-
 out:
        return ret;
 }
@@ -4853,6 +5020,8 @@ static int changed_inode(struct send_ctx *sctx,
                                sctx->left_path->nodes[0], left_ii);
                sctx->cur_inode_mode = btrfs_inode_mode(
                                sctx->left_path->nodes[0], left_ii);
+               sctx->cur_inode_rdev = btrfs_inode_rdev(
+                               sctx->left_path->nodes[0], left_ii);
                if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
                        ret = send_create_inode_if_needed(sctx);
        } else if (result == BTRFS_COMPARE_TREE_DELETED) {
@@ -4897,6 +5066,8 @@ static int changed_inode(struct send_ctx *sctx,
                                        sctx->left_path->nodes[0], left_ii);
                        sctx->cur_inode_mode = btrfs_inode_mode(
                                        sctx->left_path->nodes[0], left_ii);
+                       sctx->cur_inode_rdev = btrfs_inode_rdev(
+                                       sctx->left_path->nodes[0], left_ii);
                        ret = send_create_inode_if_needed(sctx);
                        if (ret < 0)
                                goto out;
@@ -5386,6 +5557,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
 
        sctx->pending_dir_moves = RB_ROOT;
        sctx->waiting_dir_moves = RB_ROOT;
+       sctx->orphan_dirs = RB_ROOT;
 
        sctx->clone_roots = vzalloc(sizeof(struct clone_root) *
                        (arg->clone_sources_count + 1));
@@ -5523,6 +5695,16 @@ out:
                kfree(dm);
        }
 
+       WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->orphan_dirs));
+       while (sctx && !RB_EMPTY_ROOT(&sctx->orphan_dirs)) {
+               struct rb_node *n;
+               struct orphan_dir_info *odi;
+
+               n = rb_first(&sctx->orphan_dirs);
+               odi = rb_entry(n, struct orphan_dir_info, node);
+               free_orphan_dir_info(sctx, odi);
+       }
+
        if (sort_clone_roots) {
                for (i = 0; i < sctx->clone_roots_cnt; i++)
                        btrfs_root_dec_send_in_progress(