struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_state *cached_state = NULL;
-       struct extent_map *em = NULL;
        struct btrfs_chunk_map *map = NULL;
        struct btrfs_device *device = NULL;
        struct btrfs_swap_info bsi = {
                .lowest_ppage = (sector_t)-1ULL,
        };
+       struct btrfs_backref_share_check_ctx *backref_ctx = NULL;
+       struct btrfs_path *path = NULL;
        int ret = 0;
        u64 isize;
-       u64 start;
+       u64 prev_extent_end = 0;
 
        /*
         * Acquire the inode's mmap lock to prevent races with memory mapped
                goto out_unlock_mmap;
        }
 
+       path = btrfs_alloc_path();
+       backref_ctx = btrfs_alloc_backref_share_check_ctx();
+       if (!path || !backref_ctx) {
+               ret = -ENOMEM;
+               goto out_unlock_mmap;
+       }
+
        /*
         * Balance or device remove/replace/resize can move stuff around from
         * under us. The exclop protection makes sure they aren't running/won't
        isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize);
 
        lock_extent(io_tree, 0, isize - 1, &cached_state);
-       start = 0;
-       while (start < isize) {
-               u64 logical_block_start, physical_block_start;
+       while (prev_extent_end < isize) {
+               struct btrfs_key key;
+               struct extent_buffer *leaf;
+               struct btrfs_file_extent_item *ei;
                struct btrfs_block_group *bg;
-               u64 len = isize - start;
+               u64 logical_block_start;
+               u64 physical_block_start;
+               u64 extent_gen;
+               u64 disk_bytenr;
+               u64 len;
 
-               em = btrfs_get_extent(BTRFS_I(inode), NULL, start, len);
-               if (IS_ERR(em)) {
-                       ret = PTR_ERR(em);
+               key.objectid = btrfs_ino(BTRFS_I(inode));
+               key.type = BTRFS_EXTENT_DATA_KEY;
+               key.offset = prev_extent_end;
+
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
                        goto out;
-               }
 
-               if (em->disk_bytenr == EXTENT_MAP_HOLE) {
+               /*
+                * If key not found it means we have an implicit hole (NO_HOLES
+                * is enabled).
+                */
+               if (ret > 0) {
                        btrfs_warn(fs_info, "swapfile must not have holes");
                        ret = -EINVAL;
                        goto out;
                }
-               if (em->disk_bytenr == EXTENT_MAP_INLINE) {
+
+               leaf = path->nodes[0];
+               ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item);
+
+               if (btrfs_file_extent_type(leaf, ei) == BTRFS_FILE_EXTENT_INLINE) {
                        /*
                         * It's unlikely we'll ever actually find ourselves
                         * here, as a file small enough to fit inline won't be
                        ret = -EINVAL;
                        goto out;
                }
-               if (extent_map_is_compressed(em)) {
+
+               if (btrfs_file_extent_compression(leaf, ei) != BTRFS_COMPRESS_NONE) {
                        btrfs_warn(fs_info, "swapfile must not be compressed");
                        ret = -EINVAL;
                        goto out;
                }
 
-               logical_block_start = extent_map_block_start(em) + (start - em->start);
-               len = min(len, em->len - (start - em->start));
-               free_extent_map(em);
-               em = NULL;
+               disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, ei);
+               if (disk_bytenr == 0) {
+                       btrfs_warn(fs_info, "swapfile must not have holes");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               logical_block_start = disk_bytenr + btrfs_file_extent_offset(leaf, ei);
+               extent_gen = btrfs_file_extent_generation(leaf, ei);
+               prev_extent_end = btrfs_file_extent_end(path);
+
+               if (prev_extent_end > isize)
+                       len = isize - key.offset;
+               else
+                       len = btrfs_file_extent_num_bytes(leaf, ei);
 
-               ret = can_nocow_extent(inode, start, &len, NULL, false, true);
+               backref_ctx->curr_leaf_bytenr = leaf->start;
+
+               /*
+                * Don't need the path anymore, release to avoid deadlocks when
+                * calling btrfs_is_data_extent_shared() because when joining a
+                * transaction it can block waiting for the current one's commit
+                * which in turn may be trying to lock the same leaf to flush
+                * delayed items for example.
+                */
+               btrfs_release_path(path);
+
+               ret = btrfs_is_data_extent_shared(BTRFS_I(inode), disk_bytenr,
+                                                 extent_gen, backref_ctx);
                if (ret < 0) {
                        goto out;
-               } else if (ret) {
-                       ret = 0;
-               } else {
+               } else if (ret > 0) {
                        btrfs_warn(fs_info,
                                   "swapfile must not be copy-on-write");
                        ret = -EINVAL;
 
                physical_block_start = (map->stripes[0].physical +
                                        (logical_block_start - map->start));
-               len = min(len, map->chunk_len - (logical_block_start - map->start));
                btrfs_free_chunk_map(map);
                map = NULL;
 
                                if (ret)
                                        goto out;
                        }
-                       bsi.start = start;
+                       bsi.start = key.offset;
                        bsi.block_start = physical_block_start;
                        bsi.block_len = len;
                }
-
-               start += len;
        }
 
        if (bsi.block_len)
                ret = btrfs_add_swap_extent(sis, &bsi);
 
 out:
-       if (!IS_ERR_OR_NULL(em))
-               free_extent_map(em);
        if (!IS_ERR_OR_NULL(map))
                btrfs_free_chunk_map(map);
 
 
 out_unlock_mmap:
        up_write(&BTRFS_I(inode)->i_mmap_lock);
+       btrfs_free_backref_share_ctx(backref_ctx);
+       btrfs_free_path(path);
        if (ret)
                return ret;