OSDN Git Service

Merge branch 'for-chris' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs...
authorChris Mason <chris.mason@oracle.com>
Fri, 17 Jun 2011 18:16:13 +0000 (14:16 -0400)
committerChris Mason <chris.mason@oracle.com>
Fri, 17 Jun 2011 18:16:13 +0000 (14:16 -0400)
Conflicts:
fs/btrfs/transaction.c

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

diff --combined fs/btrfs/transaction.c
@@@ -126,85 -126,28 +126,85 @@@ static noinline int join_transaction(st
   * to make sure the old root from before we joined the transaction is deleted
   * when the transaction commits
   */
 -int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
 +static int record_root_in_trans(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root)
  {
        if (root->ref_cows && root->last_trans < trans->transid) {
                WARN_ON(root == root->fs_info->extent_root);
                WARN_ON(root->commit_root != root->node);
  
 +              /*
 +               * see below for in_trans_setup usage rules
 +               * we have the reloc mutex held now, so there
 +               * is only one writer in this function
 +               */
 +              root->in_trans_setup = 1;
 +
 +              /* make sure readers find in_trans_setup before
 +               * they find our root->last_trans update
 +               */
 +              smp_wmb();
 +
                spin_lock(&root->fs_info->fs_roots_radix_lock);
                if (root->last_trans == trans->transid) {
                        spin_unlock(&root->fs_info->fs_roots_radix_lock);
                        return 0;
                }
 -              root->last_trans = trans->transid;
                radix_tree_tag_set(&root->fs_info->fs_roots_radix,
                           (unsigned long)root->root_key.objectid,
                           BTRFS_ROOT_TRANS_TAG);
                spin_unlock(&root->fs_info->fs_roots_radix_lock);
 +              root->last_trans = trans->transid;
 +
 +              /* this is pretty tricky.  We don't want to
 +               * take the relocation lock in btrfs_record_root_in_trans
 +               * unless we're really doing the first setup for this root in
 +               * this transaction.
 +               *
 +               * Normally we'd use root->last_trans as a flag to decide
 +               * if we want to take the expensive mutex.
 +               *
 +               * But, we have to set root->last_trans before we
 +               * init the relocation root, otherwise, we trip over warnings
 +               * in ctree.c.  The solution used here is to flag ourselves
 +               * with root->in_trans_setup.  When this is 1, we're still
 +               * fixing up the reloc trees and everyone must wait.
 +               *
 +               * When this is zero, they can trust root->last_trans and fly
 +               * through btrfs_record_root_in_trans without having to take the
 +               * lock.  smp_wmb() makes sure that all the writes above are
 +               * done before we pop in the zero below
 +               */
                btrfs_init_reloc_root(trans, root);
 +              smp_wmb();
 +              root->in_trans_setup = 0;
        }
        return 0;
  }
  
 +
 +int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
 +                             struct btrfs_root *root)
 +{
 +      if (!root->ref_cows)
 +              return 0;
 +
 +      /*
 +       * see record_root_in_trans for comments about in_trans_setup usage
 +       * and barriers
 +       */
 +      smp_rmb();
 +      if (root->last_trans == trans->transid &&
 +          !root->in_trans_setup)
 +              return 0;
 +
 +      mutex_lock(&root->fs_info->reloc_mutex);
 +      record_root_in_trans(trans, root);
 +      mutex_unlock(&root->fs_info->reloc_mutex);
 +
 +      return 0;
 +}
 +
  /* wait for commit against the current transaction to become unblocked
   * when this is done, it is safe to start a new transaction, but the current
   * transaction might not be fully on disk.
@@@ -939,7 -882,7 +939,7 @@@ static noinline int create_pending_snap
        parent = dget_parent(dentry);
        parent_inode = parent->d_inode;
        parent_root = BTRFS_I(parent_inode)->root;
 -      btrfs_record_root_in_trans(trans, parent_root);
 +      record_root_in_trans(trans, parent_root);
  
        /*
         * insert the directory item
        ret = btrfs_update_inode(trans, parent_root, parent_inode);
        BUG_ON(ret);
  
 -      btrfs_record_root_in_trans(trans, root);
 +      record_root_in_trans(trans, root);
        btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
        memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
        btrfs_check_and_init_root_item(new_root_item);
@@@ -1298,19 -1241,20 +1298,27 @@@ int btrfs_commit_transaction(struct btr
                        schedule_timeout(1);
  
                finish_wait(&cur_trans->writer_wait, &wait);
-               spin_lock(&root->fs_info->trans_lock);
-               root->fs_info->trans_no_join = 1;
-               spin_unlock(&root->fs_info->trans_lock);
        } while (atomic_read(&cur_trans->num_writers) > 1 ||
                 (should_grow && cur_trans->num_joined != joined));
  
        /*
+        * Ok now we need to make sure to block out any other joins while we
+        * commit the transaction.  We could have started a join before setting
+        * no_join so make sure to wait for num_writers to == 1 again.
+        */
+       spin_lock(&root->fs_info->trans_lock);
+       root->fs_info->trans_no_join = 1;
+       spin_unlock(&root->fs_info->trans_lock);
+       wait_event(cur_trans->writer_wait,
+                  atomic_read(&cur_trans->num_writers) == 1);
++      /*
 +       * the reloc mutex makes sure that we stop
 +       * the balancing code from coming in and moving
 +       * extents around in the middle of the commit
 +       */
 +      mutex_lock(&root->fs_info->reloc_mutex);
 +
        ret = create_pending_snapshots(trans, root->fs_info);
        BUG_ON(ret);
  
        root->fs_info->running_transaction = NULL;
        root->fs_info->trans_no_join = 0;
        spin_unlock(&root->fs_info->trans_lock);
 +      mutex_unlock(&root->fs_info->reloc_mutex);
  
        wake_up(&root->fs_info->transaction_wait);