Btrfs: use FLUSH_LIMIT for relocation in reserve_metadata_bytes
authorJosef Bacik <jbacik@fb.com>
Fri, 27 May 2016 17:24:13 +0000 (13:24 -0400)
committerDavid Sterba <dsterba@suse.com>
Thu, 7 Jul 2016 16:45:53 +0000 (18:45 +0200)
We used to allow you to set FLUSH_ALL and then just wouldn't do things like
commit transactions or wait on ordered extents if we noticed you were in a
transaction.  However now that all the flushing for FLUSH_ALL is asynchronous
we've lost the ability to tell, and we could end up deadlocking.  So instead use
FLUSH_LIMIT in reserve_metadata_bytes in relocation and then return -EAGAIN if
we error out to preserve the previous behavior.  I've also added an ASSERT() to
catch anybody else who tries to do this.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent-tree.c
fs/btrfs/relocation.c

index f3de211173adfec0b859761c1f6c178f6e75e7c3..3a129c42658ebc983fb394be5cb3ebf83998006a 100644 (file)
@@ -5135,6 +5135,8 @@ static int __reserve_metadata_bytes(struct btrfs_root *root,
        int ret = 0;
 
        ASSERT(orig_bytes);
+       ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_ALL);
+
        spin_lock(&space_info->lock);
        ret = -ENOSPC;
        used = space_info->bytes_used + space_info->bytes_reserved +
index 23e16de52e23b83046a98d8b96f1d99599b1923f..fc067b07e31fac354c45a0f0ad1b693886b80a47 100644 (file)
@@ -2604,25 +2604,28 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,
 
        trans->block_rsv = rc->block_rsv;
        rc->reserved_bytes += num_bytes;
+
+       /*
+        * We are under a transaction here so we can only do limited flushing.
+        * If we get an enospc just kick back -EAGAIN so we know to drop the
+        * transaction and try to refill when we can flush all the things.
+        */
        ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes,
-                               BTRFS_RESERVE_FLUSH_ALL);
+                               BTRFS_RESERVE_FLUSH_LIMIT);
        if (ret) {
-               if (ret == -EAGAIN) {
-                       tmp = rc->extent_root->nodesize *
-                               RELOCATION_RESERVED_NODES;
-                       while (tmp <= rc->reserved_bytes)
-                               tmp <<= 1;
-                       /*
-                        * only one thread can access block_rsv at this point,
-                        * so we don't need hold lock to protect block_rsv.
-                        * we expand more reservation size here to allow enough
-                        * space for relocation and we will return earlier in
-                        * enospc case.
-                        */
-                       rc->block_rsv->size = tmp + rc->extent_root->nodesize *
-                                             RELOCATION_RESERVED_NODES;
-               }
-               return ret;
+               tmp = rc->extent_root->nodesize * RELOCATION_RESERVED_NODES;
+               while (tmp <= rc->reserved_bytes)
+                       tmp <<= 1;
+               /*
+                * only one thread can access block_rsv at this point,
+                * so we don't need hold lock to protect block_rsv.
+                * we expand more reservation size here to allow enough
+                * space for relocation and we will return eailer in
+                * enospc case.
+                */
+               rc->block_rsv->size = tmp + rc->extent_root->nodesize *
+                       RELOCATION_RESERVED_NODES;
+               return -EAGAIN;
        }
 
        return 0;