btrfs: fix condition of commit transaction
authorZhao Lei <zhaolei@cn.fujitsu.com>
Sat, 14 Feb 2015 05:23:45 +0000 (13:23 +0800)
committerChris Mason <clm@fb.com>
Mon, 13 Apr 2015 14:26:40 +0000 (07:26 -0700)
Old code bypass commit transaction when we don't have enough
pinned space, but another case is there exist freed bgs in current
transction, it have possibility to make alloc_chunk success.

This patch modify the condition to:
if (have_free_bg || have_pinned_space) commit_transaction()

Confirmed above action by printk before and after patch.

Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/extent-tree.c

index 875ba51..7b227a6 100644 (file)
@@ -3857,7 +3857,9 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_fs_info *fs_info = root->fs_info;
        u64 used;
-       int ret = 0, committed = 0;
+       int ret = 0;
+       int committed = 0;
+       int have_pinned_space = 1;
 
        /* make sure bytes are sectorsize aligned */
        bytes = ALIGN(bytes, root->sectorsize);
@@ -3925,11 +3927,12 @@ alloc:
 
                /*
                 * If we don't have enough pinned space to deal with this
-                * allocation don't bother committing the transaction.
+                * allocation, and no removed chunk in current transaction,
+                * don't bother committing the transaction.
                 */
                if (percpu_counter_compare(&data_sinfo->total_bytes_pinned,
                                           bytes) < 0)
-                       committed = 1;
+                       have_pinned_space = 0;
                spin_unlock(&data_sinfo->lock);
 
                /* commit the current transaction and try again */
@@ -3941,10 +3944,15 @@ commit_trans:
                        trans = btrfs_join_transaction(root);
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
-                       ret = btrfs_commit_transaction(trans, root);
-                       if (ret)
-                               return ret;
-                       goto again;
+                       if (have_pinned_space ||
+                           trans->transaction->have_free_bgs) {
+                               ret = btrfs_commit_transaction(trans, root);
+                               if (ret)
+                                       return ret;
+                               goto again;
+                       } else {
+                               btrfs_end_transaction(trans, root);
+                       }
                }
 
                trace_btrfs_space_reservation(root->fs_info,