]> git.ipfire.org Git - people/ms/linux.git/blobdiff - fs/btrfs/ioctl.c
Merge branch 'for-6.0/dax' into libnvdimm-fixes
[people/ms/linux.git] / fs / btrfs / ioctl.c
index 0f79af919bc4ea3021404d042c72bed4a33c2385..fe0cc816b4eba2654470cb26c768a031f04c438c 100644 (file)
@@ -1230,16 +1230,18 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
        return em;
 }
 
-static u32 get_extent_max_capacity(const struct extent_map *em)
+static u32 get_extent_max_capacity(const struct btrfs_fs_info *fs_info,
+                                  const struct extent_map *em)
 {
        if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
                return BTRFS_MAX_COMPRESSED;
-       return BTRFS_MAX_EXTENT_SIZE;
+       return fs_info->max_extent_size;
 }
 
 static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
                                     u32 extent_thresh, u64 newer_than, bool locked)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct extent_map *next;
        bool ret = false;
 
@@ -1263,7 +1265,7 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
         * If the next extent is at its max capacity, defragging current extent
         * makes no sense, as the total number of extents won't change.
         */
-       if (next->len >= get_extent_max_capacity(em))
+       if (next->len >= get_extent_max_capacity(fs_info, em))
                goto out;
        /* Skip older extent */
        if (next->generation < newer_than)
@@ -1400,6 +1402,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                                  bool locked, struct list_head *target_list,
                                  u64 *last_scanned_ret)
 {
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
        bool last_is_target = false;
        u64 cur = start;
        int ret = 0;
@@ -1484,7 +1487,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                 * Skip extents already at its max capacity, this is mostly for
                 * compressed extents, which max cap is only 128K.
                 */
-               if (em->len >= get_extent_max_capacity(em))
+               if (em->len >= get_extent_max_capacity(fs_info, em))
                        goto next;
 
                /*
@@ -4243,26 +4246,6 @@ out:
        return ret;
 }
 
-static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
-{
-       struct btrfs_data_container *inodes = ctx;
-       const size_t c = 3 * sizeof(u64);
-
-       if (inodes->bytes_left >= c) {
-               inodes->bytes_left -= c;
-               inodes->val[inodes->elem_cnt] = inum;
-               inodes->val[inodes->elem_cnt + 1] = offset;
-               inodes->val[inodes->elem_cnt + 2] = root;
-               inodes->elem_cnt += 3;
-       } else {
-               inodes->bytes_missing += c - inodes->bytes_left;
-               inodes->bytes_left = 0;
-               inodes->elem_missed += 3;
-       }
-
-       return 0;
-}
-
 static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
                                        void __user *arg, int version)
 {
@@ -4312,7 +4295,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
        }
 
        ret = iterate_inodes_from_logical(loi->logical, fs_info, path,
-                                         build_ino_list, inodes, ignore_offset);
+                                         inodes, ignore_offset);
        if (ret == -EINVAL)
                ret = -ENOENT;
        if (ret < 0)
@@ -4355,13 +4338,79 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
        spin_unlock(&fs_info->balance_lock);
 }
 
+/**
+ * Try to acquire fs_info::balance_mutex as well as set BTRFS_EXLCOP_BALANCE as
+ * required.
+ *
+ * @fs_info:       the filesystem
+ * @excl_acquired: ptr to boolean value which is set to false in case balance
+ *                 is being resumed
+ *
+ * Return 0 on success in which case both fs_info::balance is acquired as well
+ * as exclusive ops are blocked. In case of failure return an error code.
+ */
+static int btrfs_try_lock_balance(struct btrfs_fs_info *fs_info, bool *excl_acquired)
+{
+       int ret;
+
+       /*
+        * Exclusive operation is locked. Three possibilities:
+        *   (1) some other op is running
+        *   (2) balance is running
+        *   (3) balance is paused -- special case (think resume)
+        */
+       while (1) {
+               if (btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
+                       *excl_acquired = true;
+                       mutex_lock(&fs_info->balance_mutex);
+                       return 0;
+               }
+
+               mutex_lock(&fs_info->balance_mutex);
+               if (fs_info->balance_ctl) {
+                       /* This is either (2) or (3) */
+                       if (test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
+                               /* This is (2) */
+                               ret = -EINPROGRESS;
+                               goto out_failure;
+
+                       } else {
+                               mutex_unlock(&fs_info->balance_mutex);
+                               /*
+                                * Lock released to allow other waiters to
+                                * continue, we'll reexamine the status again.
+                                */
+                               mutex_lock(&fs_info->balance_mutex);
+
+                               if (fs_info->balance_ctl &&
+                                   !test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
+                                       /* This is (3) */
+                                       *excl_acquired = false;
+                                       return 0;
+                               }
+                       }
+               } else {
+                       /* This is (1) */
+                       ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+                       goto out_failure;
+               }
+
+               mutex_unlock(&fs_info->balance_mutex);
+       }
+
+out_failure:
+       mutex_unlock(&fs_info->balance_mutex);
+       *excl_acquired = false;
+       return ret;
+}
+
 static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 {
        struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_ioctl_balance_args *bargs;
        struct btrfs_balance_control *bctl;
-       bool need_unlock; /* for mut. excl. ops lock */
+       bool need_unlock = true;
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -4378,53 +4427,12 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
                goto out;
        }
 
-again:
-       if (btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
-               mutex_lock(&fs_info->balance_mutex);
-               need_unlock = true;
-               goto locked;
-       }
-
-       /*
-        * mut. excl. ops lock is locked.  Three possibilities:
-        *   (1) some other op is running
-        *   (2) balance is running
-        *   (3) balance is paused -- special case (think resume)
-        */
-       mutex_lock(&fs_info->balance_mutex);
-       if (fs_info->balance_ctl) {
-               /* this is either (2) or (3) */
-               if (!test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
-                       mutex_unlock(&fs_info->balance_mutex);
-                       /*
-                        * Lock released to allow other waiters to continue,
-                        * we'll reexamine the status again.
-                        */
-                       mutex_lock(&fs_info->balance_mutex);
-
-                       if (fs_info->balance_ctl &&
-                           !test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
-                               /* this is (3) */
-                               need_unlock = false;
-                               goto locked;
-                       }
-
-                       mutex_unlock(&fs_info->balance_mutex);
-                       goto again;
-               } else {
-                       /* this is (2) */
-                       mutex_unlock(&fs_info->balance_mutex);
-                       ret = -EINPROGRESS;
-                       goto out;
-               }
-       } else {
-               /* this is (1) */
-               mutex_unlock(&fs_info->balance_mutex);
-               ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+       ret = btrfs_try_lock_balance(fs_info, &need_unlock);
+       if (ret)
                goto out;
-       }
 
-locked:
+       lockdep_assert_held(&fs_info->balance_mutex);
+
        if (bargs->flags & BTRFS_BALANCE_RESUME) {
                if (!fs_info->balance_ctl) {
                        ret = -ENOTCONN;