Btrfs: don't reserve data with extents locked in btrfs_fallocate
authorChris Mason <chris.mason@oracle.com>
Wed, 1 Feb 2012 01:27:41 +0000 (20:27 -0500)
committerChris Mason <chris.mason@oracle.com>
Wed, 1 Feb 2012 01:27:41 +0000 (20:27 -0500)
btrfs_fallocate tries to allocate space only if ranges in the file don't
already exist.  But the enospc checks it does are not allowed with
extents locked.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/file.c

index 0f61e11a2998d87bbf246447eae3161b79aad278..0621a3a7d5d157161cef85401aa135fd342fe931 100644 (file)
@@ -1603,6 +1603,14 @@ static long btrfs_fallocate(struct file *file, int mode,
        if (mode & ~FALLOC_FL_KEEP_SIZE)
                return -EOPNOTSUPP;
 
+       /*
+        * Make sure we have enough space before we do the
+        * allocation.
+        */
+       ret = btrfs_check_data_free_space(inode, len);
+       if (ret)
+               return ret;
+
        /*
         * wait for ordered IO before we have any locks.  We'll loop again
         * below with the locks held.
@@ -1666,27 +1674,12 @@ static long btrfs_fallocate(struct file *file, int mode,
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
-
-                       /*
-                        * Make sure we have enough space before we do the
-                        * allocation.
-                        */
-                       ret = btrfs_check_data_free_space(inode, last_byte -
-                                                         cur_offset);
-                       if (ret) {
-                               free_extent_map(em);
-                               break;
-                       }
-
                        ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
                                                        last_byte - cur_offset,
                                                        1 << inode->i_blkbits,
                                                        offset + len,
                                                        &alloc_hint);
 
-                       /* Let go of our reservation. */
-                       btrfs_free_reserved_data_space(inode, last_byte -
-                                                      cur_offset);
                        if (ret < 0) {
                                free_extent_map(em);
                                break;
@@ -1714,6 +1707,8 @@ static long btrfs_fallocate(struct file *file, int mode,
                             &cached_state, GFP_NOFS);
 out:
        mutex_unlock(&inode->i_mutex);
+       /* Let go of our reservation. */
+       btrfs_free_reserved_data_space(inode, len);
        return ret;
 }