size_t num_pages, loff_t pos, size_t write_bytes,
                      struct extent_state **cached);
 int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
+int btrfs_check_can_nocow(struct btrfs_inode *inode, loff_t pos,
+                         size_t *write_bytes, bool nowait);
 
 /* tree-defrag.c */
 int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 
        return ret;
 }
 
-static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
-                                   size_t *write_bytes, bool nowait)
+int btrfs_check_can_nocow(struct btrfs_inode *inode, loff_t pos,
+                         size_t *write_bytes, bool nowait)
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct btrfs_root *root = inode->root;
                if (ret < 0) {
                        if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
                                                      BTRFS_INODE_PREALLOC)) &&
-                           check_can_nocow(BTRFS_I(inode), pos,
-                                           &write_bytes, false) > 0) {
+                           btrfs_check_can_nocow(BTRFS_I(inode), pos,
+                                                 &write_bytes, false) > 0) {
                                /*
                                 * For nodata cow case, no need to reserve
                                 * data space.
                 */
                if (!(BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
                                              BTRFS_INODE_PREALLOC)) ||
-                   check_can_nocow(BTRFS_I(inode), pos, &nocow_bytes,
-                                   true) <= 0) {
+                   btrfs_check_can_nocow(BTRFS_I(inode), pos, &nocow_bytes,
+                                         true) <= 0) {
                        inode_unlock(inode);
                        return -EAGAIN;
                }
 
        struct extent_state *cached_state = NULL;
        struct extent_changeset *data_reserved = NULL;
        char *kaddr;
+       bool only_release_metadata = false;
        u32 blocksize = fs_info->sectorsize;
        pgoff_t index = from >> PAGE_SHIFT;
        unsigned offset = from & (blocksize - 1);
        struct page *page;
        gfp_t mask = btrfs_alloc_write_mask(mapping);
+       size_t write_bytes = blocksize;
        int ret = 0;
        u64 block_start;
        u64 block_end;
        block_start = round_down(from, blocksize);
        block_end = block_start + blocksize - 1;
 
-       ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
-                                          block_start, blocksize);
-       if (ret)
-               goto out;
 
+       ret = btrfs_check_data_free_space(inode, &data_reserved, block_start,
+                                         blocksize);
+       if (ret < 0) {
+               if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
+                                             BTRFS_INODE_PREALLOC)) &&
+                   btrfs_check_can_nocow(BTRFS_I(inode), block_start,
+                                         &write_bytes, false) > 0) {
+                       /* For nocow case, no need to reserve data space */
+                       only_release_metadata = true;
+               } else {
+                       goto out;
+               }
+       }
+       ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), blocksize);
+       if (ret < 0) {
+               if (!only_release_metadata)
+                       btrfs_free_reserved_data_space(inode, data_reserved,
+                                       block_start, blocksize);
+               goto out;
+       }
 again:
        page = find_or_create_page(mapping, index, mask);
        if (!page) {
        set_page_dirty(page);
        unlock_extent_cached(io_tree, block_start, block_end, &cached_state);
 
+       if (only_release_metadata)
+               set_extent_bit(&BTRFS_I(inode)->io_tree, block_start,
+                               block_end, EXTENT_NORESERVE, NULL, NULL,
+                               GFP_NOFS);
+
 out_unlock:
-       if (ret)
-               btrfs_delalloc_release_space(inode, data_reserved, block_start,
-                                            blocksize, true);
+       if (ret) {
+               if (only_release_metadata)
+                       btrfs_delalloc_release_metadata(BTRFS_I(inode),
+                                       blocksize, true);
+               else
+                       btrfs_delalloc_release_space(inode, data_reserved,
+                                       block_start, blocksize, true);
+       }
        btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize);
        unlock_page(page);
        put_page(page);
 out:
+       if (only_release_metadata)
+               btrfs_drew_write_unlock(&BTRFS_I(inode)->root->snapshot_lock);
        extent_changeset_free(data_reserved);
        return ret;
 }