u64 gid;
        u64 rdev;
        u64 fileattr;
+       u64 nlink;
 };
 
 /*
        info->uid = btrfs_inode_uid(path->nodes[0], ii);
        info->gid = btrfs_inode_gid(path->nodes[0], ii);
        info->rdev = btrfs_inode_rdev(path->nodes[0], ii);
+       info->nlink = btrfs_inode_nlink(path->nodes[0], ii);
        /*
         * Transfer the unchanged u64 value of btrfs_inode_item::flags, that's
         * otherwise logically split to 32/32 parts.
        int right_ret;
        u64 left_gen;
        u64 right_gen;
+       struct btrfs_inode_info info;
 
-       ret = get_inode_gen(sctx->send_root, ino, &left_gen);
+       ret = get_inode_info(sctx->send_root, ino, &info);
        if (ret < 0 && ret != -ENOENT)
                goto out;
-       left_ret = ret;
+       left_ret = (info.nlink == 0) ? -ENOENT : ret;
+       left_gen = info.gen;
 
        if (!sctx->parent_root) {
                right_ret = -ENOENT;
        } else {
-               ret = get_inode_gen(sctx->parent_root, ino, &right_gen);
+               ret = get_inode_info(sctx->parent_root, ino, &info);
                if (ret < 0 && ret != -ENOENT)
                        goto out;
-               right_ret = ret;
+               right_ret = (info.nlink == 0) ? -ENOENT : ret;
+               right_gen = info.gen;
        }
 
        if (!left_ret && !right_ret) {
        return ret;
 }
 
-struct parent_paths_ctx {
-       struct list_head *refs;
-       struct send_ctx *sctx;
-};
-
-static int record_parent_ref(int num, u64 dir, int index, struct fs_path *name,
-                            void *ctx)
-{
-       struct parent_paths_ctx *ppctx = ctx;
-
-       /*
-        * Pass 0 as the generation for the directory, we don't care about it
-        * here as we have no new references to add, we just want to delete all
-        * references for an inode.
-        */
-       return record_ref_in_tree(&ppctx->sctx->rbtree_deleted_refs, ppctx->refs,
-                                 name, dir, 0, ppctx->sctx);
-}
-
-/*
- * Issue unlink operations for all paths of the current inode found in the
- * parent snapshot.
- */
-static int btrfs_unlink_all_paths(struct send_ctx *sctx)
-{
-       LIST_HEAD(deleted_refs);
-       struct btrfs_path *path;
-       struct btrfs_root *root = sctx->parent_root;
-       struct btrfs_key key;
-       struct btrfs_key found_key;
-       struct parent_paths_ctx ctx;
-       int iter_ret = 0;
-       int ret;
-
-       path = alloc_path_for_send();
-       if (!path)
-               return -ENOMEM;
-
-       key.objectid = sctx->cur_ino;
-       key.type = BTRFS_INODE_REF_KEY;
-       key.offset = 0;
-
-       ctx.refs = &deleted_refs;
-       ctx.sctx = sctx;
-
-       btrfs_for_each_slot(root, &key, &found_key, path, iter_ret) {
-               if (found_key.objectid != key.objectid)
-                       break;
-               if (found_key.type != key.type &&
-                   found_key.type != BTRFS_INODE_EXTREF_KEY)
-                       break;
-
-               ret = iterate_inode_ref(root, path, &found_key, 1,
-                                       record_parent_ref, &ctx);
-               if (ret < 0)
-                       goto out;
-       }
-       /* Catch error found during iteration */
-       if (iter_ret < 0) {
-               ret = iter_ret;
-               goto out;
-       }
-
-       while (!list_empty(&deleted_refs)) {
-               struct recorded_ref *ref;
-
-               ref = list_first_entry(&deleted_refs, struct recorded_ref, list);
-               ret = send_unlink(sctx, ref->full_path);
-               if (ret < 0)
-                       goto out;
-               recorded_ref_free(ref);
-       }
-       ret = 0;
-out:
-       btrfs_free_path(path);
-       if (ret)
-               __free_recorded_refs(&deleted_refs);
-       return ret;
-}
-
 static void close_current_inode(struct send_ctx *sctx)
 {
        u64 i_size;
         * file descriptor against it or turning a RO snapshot into RW mode,
         * keep an open file descriptor against a file, delete it and then
         * turn the snapshot back to RO mode before using it for a send
-        * operation. So if we find such cases, ignore the inode and all its
-        * items completely if it's a new inode, or if it's a changed inode
-        * make sure all its previous paths (from the parent snapshot) are all
-        * unlinked and all other the inode items are ignored.
+        * operation. The former is what the receiver operation does.
+        * Therefore, if we want to send these snapshots soon after they're
+        * received, we need to handle orphan inodes as well. Moreover, orphans
+        * can appear not only in the send snapshot but also in the parent
+        * snapshot. Here are several cases:
+        *
+        * Case 1: BTRFS_COMPARE_TREE_NEW
+        *       |  send snapshot  | action
+        * --------------------------------
+        * nlink |        0        | ignore
+        *
+        * Case 2: BTRFS_COMPARE_TREE_DELETED
+        *       | parent snapshot | action
+        * ----------------------------------
+        * nlink |        0        | as usual
+        * Note: No unlinks will be sent because there're no paths for it.
+        *
+        * Case 3: BTRFS_COMPARE_TREE_CHANGED
+        *           |       | parent snapshot | send snapshot | action
+        * -----------------------------------------------------------------------
+        * subcase 1 | nlink |        0        |       0       | ignore
+        * subcase 2 | nlink |       >0        |       0       | new_gen(deletion)
+        * subcase 3 | nlink |        0        |      >0       | new_gen(creation)
+        *
         */
-       if (result == BTRFS_COMPARE_TREE_NEW ||
-           result == BTRFS_COMPARE_TREE_CHANGED) {
-               u32 nlinks;
-
-               nlinks = btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii);
-               if (nlinks == 0) {
+       if (result == BTRFS_COMPARE_TREE_NEW) {
+               if (btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii) == 0) {
                        sctx->ignore_cur_inode = true;
-                       if (result == BTRFS_COMPARE_TREE_CHANGED)
-                               ret = btrfs_unlink_all_paths(sctx);
                        goto out;
                }
-       }
-
-       if (result == BTRFS_COMPARE_TREE_NEW) {
                sctx->cur_inode_gen = left_gen;
                sctx->cur_inode_new = true;
                sctx->cur_inode_deleted = false;
                sctx->cur_inode_mode = btrfs_inode_mode(
                                sctx->right_path->nodes[0], right_ii);
        } else if (result == BTRFS_COMPARE_TREE_CHANGED) {
+               u32 new_nlinks, old_nlinks;
+
+               new_nlinks = btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii);
+               old_nlinks = btrfs_inode_nlink(sctx->right_path->nodes[0], right_ii);
+               if (new_nlinks == 0 && old_nlinks == 0) {
+                       sctx->ignore_cur_inode = true;
+                       goto out;
+               } else if (new_nlinks == 0 || old_nlinks == 0) {
+                       sctx->cur_inode_new_gen = 1;
+               }
                /*
                 * We need to do some special handling in case the inode was
                 * reported as changed with a changed generation number. This
                        /*
                         * Now process the inode as if it was new.
                         */
-                       sctx->cur_inode_gen = left_gen;
-                       sctx->cur_inode_new = true;
-                       sctx->cur_inode_deleted = false;
-                       sctx->cur_inode_size = btrfs_inode_size(
-                                       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;
+                       if (new_nlinks > 0) {
+                               sctx->cur_inode_gen = left_gen;
+                               sctx->cur_inode_new = true;
+                               sctx->cur_inode_deleted = false;
+                               sctx->cur_inode_size = btrfs_inode_size(
+                                               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;
 
-                       ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW);
-                       if (ret < 0)
-                               goto out;
-                       /*
-                        * Advance send_progress now as we did not get into
-                        * process_recorded_refs_if_needed in the new_gen case.
-                        */
-                       sctx->send_progress = sctx->cur_ino + 1;
+                               ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW);
+                               if (ret < 0)
+                                       goto out;
+                               /*
+                                * Advance send_progress now as we did not get
+                                * into process_recorded_refs_if_needed in the
+                                * new_gen case.
+                                */
+                               sctx->send_progress = sctx->cur_ino + 1;
 
-                       /*
-                        * Now process all extents and xattrs of the inode as if
-                        * they were all new.
-                        */
-                       ret = process_all_extents(sctx);
-                       if (ret < 0)
-                               goto out;
-                       ret = process_all_new_xattrs(sctx);
-                       if (ret < 0)
-                               goto out;
+                               /*
+                                * Now process all extents and xattrs of the
+                                * inode as if they were all new.
+                                */
+                               ret = process_all_extents(sctx);
+                               if (ret < 0)
+                                       goto out;
+                               ret = process_all_new_xattrs(sctx);
+                               if (ret < 0)
+                                       goto out;
+                       }
                } else {
                        sctx->cur_inode_gen = left_gen;
                        sctx->cur_inode_new = false;