jbd2: Add function jbd2_trans_will_send_data_barrier()
[deliverable/linux.git] / fs / jbd2 / journal.c
index 90407b8fece7475b9d733e51047464fa94f209fd..9a78269903041934f0896148e1999e8467fd0872 100644 (file)
@@ -479,9 +479,12 @@ int __jbd2_log_space_left(journal_t *journal)
 int __jbd2_log_start_commit(journal_t *journal, tid_t target)
 {
        /*
-        * Are we already doing a recent enough commit?
+        * The only transaction we can possibly wait upon is the
+        * currently running transaction (if it exists).  Otherwise,
+        * the target tid must be an old one.
         */
-       if (!tid_geq(journal->j_commit_request, target)) {
+       if (journal->j_running_transaction &&
+           journal->j_running_transaction->t_tid == target) {
                /*
                 * We want a new commit: OK, mark the request and wakeup the
                 * commit thread.  We do _not_ do the commit ourselves.
@@ -493,7 +496,15 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t target)
                          journal->j_commit_sequence);
                wake_up(&journal->j_wait_commit);
                return 1;
-       }
+       } else if (!tid_geq(journal->j_commit_request, target))
+               /* This should never happen, but if it does, preserve
+                  the evidence before kjournald goes into a loop and
+                  increments j_commit_sequence beyond all recognition. */
+               WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
+                         journal->j_commit_request,
+                         journal->j_commit_sequence,
+                         target, journal->j_running_transaction ? 
+                         journal->j_running_transaction->t_tid : 0);
        return 0;
 }
 
@@ -576,6 +587,47 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
        return ret;
 }
 
+/*
+ * Return 1 if a given transaction has not yet sent barrier request
+ * connected with a transaction commit. If 0 is returned, transaction
+ * may or may not have sent the barrier. Used to avoid sending barrier
+ * twice in common cases.
+ */
+int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid)
+{
+       int ret = 0;
+       transaction_t *commit_trans;
+
+       if (!(journal->j_flags & JBD2_BARRIER))
+               return 0;
+       read_lock(&journal->j_state_lock);
+       /* Transaction already committed? */
+       if (tid_geq(journal->j_commit_sequence, tid))
+               goto out;
+       commit_trans = journal->j_committing_transaction;
+       if (!commit_trans || commit_trans->t_tid != tid) {
+               ret = 1;
+               goto out;
+       }
+       /*
+        * Transaction is being committed and we already proceeded to
+        * submitting a flush to fs partition?
+        */
+       if (journal->j_fs_dev != journal->j_dev) {
+               if (!commit_trans->t_need_data_flush ||
+                   commit_trans->t_state >= T_COMMIT_DFLUSH)
+                       goto out;
+       } else {
+               if (commit_trans->t_state >= T_COMMIT_JFLUSH)
+                       goto out;
+       }
+       ret = 1;
+out:
+       read_unlock(&journal->j_state_lock);
+       return ret;
+}
+EXPORT_SYMBOL(jbd2_trans_will_send_data_barrier);
+
 /*
  * Wait for a specified commit to complete.
  * The caller may not hold the journal lock.
@@ -917,7 +969,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
        journal->j_wbufsize = n;
        journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
        if (!journal->j_wbuf) {
-               printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+               printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n",
                        __func__);
                goto out_err;
        }
@@ -983,7 +1035,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
        journal->j_wbufsize = n;
        journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
        if (!journal->j_wbuf) {
-               printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+               printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n",
                        __func__);
                goto out_err;
        }
@@ -2413,10 +2465,12 @@ const char *jbd2_dev_to_name(dev_t device)
        new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
        if (!new_dev)
                return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
+       bd = bdget(device);
        spin_lock(&devname_cache_lock);
        if (devcache[i]) {
                if (devcache[i]->device == device) {
                        kfree(new_dev);
+                       bdput(bd);
                        ret = devcache[i]->devname;
                        spin_unlock(&devname_cache_lock);
                        return ret;
@@ -2425,7 +2479,6 @@ const char *jbd2_dev_to_name(dev_t device)
        }
        devcache[i] = new_dev;
        devcache[i]->device = device;
-       bd = bdget(device);
        if (bd) {
                bdevname(bd, devcache[i]->devname);
                bdput(bd);
This page took 0.027137 seconds and 5 git commands to generate.