btrfs_wait_ordered_extents(root, 0);
 
-       trans = btrfs_join_transaction_freeze(root);
+       trans = btrfs_attach_transaction(root);
        if (IS_ERR(trans)) {
-               /* Frozen, don't bother */
-               if (PTR_ERR(trans) == -EPERM)
+               /* no transaction, don't bother */
+               if (PTR_ERR(trans) == -ENOENT)
                        return 0;
                return PTR_ERR(trans);
        }
 
 static int btrfs_freeze(struct super_block *sb)
 {
-       return 0;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *root = btrfs_sb(sb)->tree_root;
+
+       trans = btrfs_attach_transaction(root);
+       if (IS_ERR(trans)) {
+               /* no transaction, don't bother */
+               if (PTR_ERR(trans) == -ENOENT)
+                       return 0;
+               return PTR_ERR(trans);
+       }
+       return btrfs_commit_transaction(trans, root);
 }
 
 static int btrfs_unfreeze(struct super_block *sb)
 
 /*
  * either allocate a new transaction or hop into the existing one
  */
-static noinline int join_transaction(struct btrfs_root *root, int nofail)
+static noinline int join_transaction(struct btrfs_root *root, int type)
 {
        struct btrfs_transaction *cur_trans;
        struct btrfs_fs_info *fs_info = root->fs_info;
        }
 
        if (fs_info->trans_no_join) {
-               if (!nofail) {
+               /* 
+                * If we are JOIN_NOLOCK we're already committing a current
+                * transaction, we just need a handle to deal with something
+                * when committing the transaction, such as inode cache and
+                * space cache. It is a special case.
+                */
+               if (type != TRANS_JOIN_NOLOCK) {
                        spin_unlock(&fs_info->trans_lock);
                        return -EBUSY;
                }
        }
        spin_unlock(&fs_info->trans_lock);
 
+       /*
+        * If we are ATTACH, we just want to catch the current transaction,
+        * and commit it. If there is no transaction, just return ENOENT.
+        */
+       if (type == TRANS_ATTACH)
+               return -ENOENT;
+
        cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS);
        if (!cur_trans)
                return -ENOMEM;
         * because we're already holding a ref.  We need this because we could
         * have raced in and did an fsync() on a file which can kick a commit
         * and then we deadlock with somebody doing a freeze.
+        *
+        * If we are ATTACH, it means we just want to catch the current
+        * transaction and commit it, so we needn't do sb_start_intwrite(). 
         */
-       if (type != TRANS_JOIN_NOLOCK &&
-           !__sb_start_write(root->fs_info->sb, SB_FREEZE_FS, false)) {
-               if (type == TRANS_JOIN_FREEZE) {
-                       kmem_cache_free(btrfs_trans_handle_cachep, h);
-                       return ERR_PTR(-EPERM);
-               }
+       if (type < TRANS_JOIN_NOLOCK)
                sb_start_intwrite(root->fs_info->sb);
-       }
 
        if (may_wait_transaction(root, type))
                wait_current_trans(root);
 
        do {
-               ret = join_transaction(root, type == TRANS_JOIN_NOLOCK);
+               ret = join_transaction(root, type);
                if (ret == -EBUSY)
                        wait_current_trans(root);
        } while (ret == -EBUSY);
 
        if (ret < 0) {
-               sb_end_intwrite(root->fs_info->sb);
+               /* We must get the transaction if we are JOIN_NOLOCK. */
+               BUG_ON(type == TRANS_JOIN_NOLOCK);
+
+               if (type < TRANS_JOIN_NOLOCK)
+                       sb_end_intwrite(root->fs_info->sb);
                kmem_cache_free(btrfs_trans_handle_cachep, h);
                return ERR_PTR(ret);
        }
        return start_transaction(root, 0, TRANS_USERSPACE, 0);
 }
 
-struct btrfs_trans_handle *btrfs_join_transaction_freeze(struct btrfs_root *root)
+struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root)
 {
-       return start_transaction(root, 0, TRANS_JOIN_FREEZE, 0);
+       return start_transaction(root, 0, TRANS_ATTACH, 0);
 }
 
 /* wait for a transaction commit to be fully complete */
                }
        }
 
-       if (lock)
+       if (trans->type < TRANS_JOIN_NOLOCK)
                sb_end_intwrite(root->fs_info->sb);
 
        WARN_ON(cur_trans != info->running_transaction);
        put_transaction(cur_trans);
        put_transaction(cur_trans);
 
-       sb_end_intwrite(root->fs_info->sb);
+       if (trans->type < TRANS_JOIN_NOLOCK)
+               sb_end_intwrite(root->fs_info->sb);
 
        trace_btrfs_transaction_commit(root);