inode_state_did_delete,
 };
 
-static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen)
+static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen,
+                              u64 *send_gen, u64 *parent_gen)
 {
        int ret;
        int left_ret;
                goto out;
        left_ret = (info.nlink == 0) ? -ENOENT : ret;
        left_gen = info.gen;
+       if (send_gen)
+               *send_gen = ((left_ret == -ENOENT) ? 0 : info.gen);
 
        if (!sctx->parent_root) {
                right_ret = -ENOENT;
                        goto out;
                right_ret = (info.nlink == 0) ? -ENOENT : ret;
                right_gen = info.gen;
+               if (parent_gen)
+                       *parent_gen = ((right_ret == -ENOENT) ? 0 : info.gen);
        }
 
        if (!left_ret && !right_ret) {
        return ret;
 }
 
-static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen)
+static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen,
+                            u64 *send_gen, u64 *parent_gen)
 {
        int ret;
 
        if (ino == BTRFS_FIRST_FREE_OBJECTID)
                return 1;
 
-       ret = get_cur_inode_state(sctx, ino, gen);
+       ret = get_cur_inode_state(sctx, ino, gen, send_gen, parent_gen);
        if (ret < 0)
                goto out;
 
                              u64 *who_ino, u64 *who_gen, u64 *who_mode)
 {
        int ret;
-       u64 gen;
+       u64 parent_root_dir_gen;
        u64 other_inode = 0;
        struct btrfs_inode_info info;
 
        if (!sctx->parent_root)
                return 0;
 
-       ret = is_inode_existent(sctx, dir, dir_gen);
+       ret = is_inode_existent(sctx, dir, dir_gen, NULL, &parent_root_dir_gen);
        if (ret <= 0)
                return 0;
 
         * If we have a parent root we need to verify that the parent dir was
         * not deleted and then re-created, if it was then we have no overwrite
         * and we can just unlink this entry.
+        *
+        * @parent_root_dir_gen was set to 0 if the inode does not exist in the
+        * parent root.
         */
-       if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) {
-               ret = get_inode_gen(sctx->parent_root, dir, &gen);
-               if (ret == -ENOENT)
-                       return 0;
-               else if (ret < 0)
-                       return ret;
-
-               if (gen != dir_gen)
-                       return 0;
-       }
+       if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID &&
+           parent_root_dir_gen != dir_gen)
+               return 0;
 
        ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len,
                                    &other_inode);
        int ret;
        u64 ow_inode;
        u64 ow_gen = 0;
+       u64 send_root_dir_gen;
 
        if (!sctx->parent_root)
                return 0;
 
-       ret = is_inode_existent(sctx, dir, dir_gen);
+       ret = is_inode_existent(sctx, dir, dir_gen, &send_root_dir_gen, NULL);
        if (ret <= 0)
                return ret;
 
-       if (dir != BTRFS_FIRST_FREE_OBJECTID) {
-               u64 gen;
-
-               ret = get_inode_gen(sctx->send_root, dir, &gen);
-               if (ret == -ENOENT)
-                       return 0;
-               else if (ret < 0)
-                       return ret;
-
-               if (gen != dir_gen)
-                       return 0;
-       }
+       /*
+        * @send_root_dir_gen was set to 0 if the inode does not exist in the
+        * send root.
+        */
+       if (dir != BTRFS_FIRST_FREE_OBJECTID && send_root_dir_gen != dir_gen)
+               return 0;
 
        /* check if the ref was overwritten by another ref */
        ret = lookup_dir_item_inode(sctx->send_root, dir, name, name_len,
         * This should only happen for the parent dir that we determine in
         * record_new_ref_if_needed().
         */
-       ret = is_inode_existent(sctx, ino, gen);
+       ret = is_inode_existent(sctx, ino, gen, NULL, NULL);
        if (ret < 0)
                goto out;
 
         * "testdir_2".
         */
        list_for_each_entry(cur, &sctx->new_refs, list) {
-               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen);
+               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen, NULL, NULL);
                if (ret < 0)
                        goto out;
                if (ret == inode_state_will_create)
                 * parent directory out of order. But we need to check if this
                 * did already happen before due to other refs in the same dir.
                 */
-               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen);
+               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen, NULL, NULL);
                if (ret < 0)
                        goto out;
                if (ret == inode_state_will_create) {
                if (cur->dir > sctx->cur_ino)
                        continue;
 
-               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen);
+               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen, NULL, NULL);
                if (ret < 0)
                        goto out;