Get rid of passing mangled flag to do_last()
[safe/jmp/linux-2.6] / fs / jbd2 / transaction.c
index 13dcbc9..a051270 100644 (file)
@@ -57,7 +57,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
        INIT_LIST_HEAD(&transaction->t_private_list);
 
        /* Set up the commit timer for the new transaction. */
-       journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
+       journal->j_commit_timer.expires = round_jiffies_up(transaction->t_expires);
        add_timer(&journal->j_commit_timer);
 
        J_ASSERT(journal->j_running_transaction == NULL);
@@ -238,6 +238,8 @@ repeat_locked:
                  __jbd2_log_space_left(journal));
        spin_unlock(&transaction->t_handle_lock);
        spin_unlock(&journal->j_state_lock);
+
+       lock_map_acquire(&handle->h_lockdep_map);
 out:
        if (unlikely(new_transaction))          /* It's usually NULL */
                kfree(new_transaction);
@@ -303,8 +305,6 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
                handle = ERR_PTR(err);
                goto out;
        }
-
-       lock_map_acquire(&handle->h_lockdep_map);
 out:
        return handle;
 }
@@ -426,6 +426,7 @@ int jbd2_journal_restart(handle_t *handle, int nblocks)
        __jbd2_log_start_commit(journal, transaction->t_tid);
        spin_unlock(&journal->j_state_lock);
 
+       lock_map_release(&handle->h_lockdep_map);
        handle->h_buffer_credits = nblocks;
        ret = start_this_handle(journal, handle);
        return ret;
@@ -499,34 +500,15 @@ void jbd2_journal_unlock_updates (journal_t *journal)
        wake_up(&journal->j_wait_transaction_locked);
 }
 
-/*
- * Report any unexpected dirty buffers which turn up.  Normally those
- * indicate an error, but they can occur if the user is running (say)
- * tune2fs to modify the live filesystem, so we need the option of
- * continuing as gracefully as possible.  #
- *
- * The caller should already hold the journal lock and
- * j_list_lock spinlock: most callers will need those anyway
- * in order to probe the buffer's journaling state safely.
- */
-static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+static void warn_dirty_buffer(struct buffer_head *bh)
 {
-       int jlist;
-
-       /* If this buffer is one which might reasonably be dirty
-        * --- ie. data, or not part of this journal --- then
-        * we're OK to leave it alone, but otherwise we need to
-        * move the dirty bit to the journal's own internal
-        * JBDDirty bit. */
-       jlist = jh->b_jlist;
+       char b[BDEVNAME_SIZE];
 
-       if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
-           jlist == BJ_Shadow || jlist == BJ_Forget) {
-               struct buffer_head *bh = jh2bh(jh);
-
-               if (test_clear_buffer_dirty(bh))
-                       set_buffer_jbddirty(bh);
-       }
+       printk(KERN_WARNING
+              "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+              "There's a risk of filesystem corruption in case of system "
+              "crash.\n",
+              bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
 }
 
 /*
@@ -593,14 +575,16 @@ repeat:
                        if (jh->b_next_transaction)
                                J_ASSERT_JH(jh, jh->b_next_transaction ==
                                                        transaction);
+                       warn_dirty_buffer(bh);
                }
                /*
                 * In any case we need to clean the dirty flag and we must
                 * do it under the buffer lock to be sure we don't race
                 * with running write-out.
                 */
-               JBUFFER_TRACE(jh, "Unexpected dirty buffer");
-               jbd_unexpected_dirty_buffer(jh);
+               JBUFFER_TRACE(jh, "Journalling dirty buffer");
+               clear_buffer_dirty(bh);
+               set_buffer_jbddirty(bh);
        }
 
        unlock_buffer(bh);
@@ -743,6 +727,12 @@ done:
                source = kmap_atomic(page, KM_USER0);
                memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
                kunmap_atomic(source, KM_USER0);
+
+               /*
+                * Now that the frozen data is saved off, we need to store
+                * any matching triggers.
+                */
+               jh->b_frozen_triggers = jh->b_triggers;
        }
        jbd_unlock_bh_state(bh);
 
@@ -837,6 +827,15 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
        J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
 
        if (jh->b_transaction == NULL) {
+               /*
+                * Previous jbd2_journal_forget() could have left the buffer
+                * with jbddirty bit set because it was being committed. When
+                * the commit finished, we've filed the buffer for
+                * checkpointing and marked it dirty. Now we are reallocating
+                * the buffer so the transaction freeing it must have
+                * committed and so it's safe to clear the dirty bit.
+                */
+               clear_buffer_dirty(jh2bh(jh));
                jh->b_transaction = transaction;
 
                /* first access by this transaction */
@@ -946,6 +945,47 @@ out:
 }
 
 /**
+ * void jbd2_journal_set_triggers() - Add triggers for commit writeout
+ * @bh: buffer to trigger on
+ * @type: struct jbd2_buffer_trigger_type containing the trigger(s).
+ *
+ * Set any triggers on this journal_head.  This is always safe, because
+ * triggers for a committing buffer will be saved off, and triggers for
+ * a running transaction will match the buffer in that transaction.
+ *
+ * Call with NULL to clear the triggers.
+ */
+void jbd2_journal_set_triggers(struct buffer_head *bh,
+                              struct jbd2_buffer_trigger_type *type)
+{
+       struct journal_head *jh = bh2jh(bh);
+
+       jh->b_triggers = type;
+}
+
+void jbd2_buffer_commit_trigger(struct journal_head *jh, void *mapped_data,
+                               struct jbd2_buffer_trigger_type *triggers)
+{
+       struct buffer_head *bh = jh2bh(jh);
+
+       if (!triggers || !triggers->t_commit)
+               return;
+
+       triggers->t_commit(triggers, bh, mapped_data, bh->b_size);
+}
+
+void jbd2_buffer_abort_trigger(struct journal_head *jh,
+                              struct jbd2_buffer_trigger_type *triggers)
+{
+       if (!triggers || !triggers->t_abort)
+               return;
+
+       triggers->t_abort(triggers, jh2bh(jh));
+}
+
+
+
+/**
  * int jbd2_journal_dirty_metadata() -  mark a buffer as containing dirty metadata
  * @handle: transaction to add buffer to.
  * @bh: buffer to mark
@@ -1255,8 +1295,10 @@ int jbd2_journal_stop(handle_t *handle)
                trans_time = ktime_to_ns(ktime_sub(ktime_get(),
                                                   transaction->t_start_time));
 
+               commit_time = max_t(u64, commit_time,
+                                   1000*journal->j_min_batch_time);
                commit_time = min_t(u64, commit_time,
-                                   1000*jiffies_to_usecs(1));
+                                   1000*journal->j_max_batch_time);
 
                if (trans_time < commit_time) {
                        ktime_t expires = ktime_add_ns(ktime_get(),
@@ -1266,6 +1308,8 @@ int jbd2_journal_stop(handle_t *handle)
                }
        }
 
+       if (handle->h_sync)
+               transaction->t_synchronous_commit = 1;
        current->journal_info = NULL;
        spin_lock(&journal->j_state_lock);
        spin_lock(&transaction->t_handle_lock);
@@ -1496,36 +1540,6 @@ out:
        return;
 }
 
-/*
- * jbd2_journal_try_to_free_buffers() could race with
- * jbd2_journal_commit_transaction(). The later might still hold the
- * reference count to the buffers when inspecting them on
- * t_syncdata_list or t_locked_list.
- *
- * jbd2_journal_try_to_free_buffers() will call this function to
- * wait for the current transaction to finish syncing data buffers, before
- * try to free that buffer.
- *
- * Called with journal->j_state_lock hold.
- */
-static void jbd2_journal_wait_for_transaction_sync_data(journal_t *journal)
-{
-       transaction_t *transaction;
-       tid_t tid;
-
-       spin_lock(&journal->j_state_lock);
-       transaction = journal->j_committing_transaction;
-
-       if (!transaction) {
-               spin_unlock(&journal->j_state_lock);
-               return;
-       }
-
-       tid = transaction->t_tid;
-       spin_unlock(&journal->j_state_lock);
-       jbd2_log_wait_commit(journal, tid);
-}
-
 /**
  * int jbd2_journal_try_to_free_buffers() - try to free page buffers.
  * @journal: journal for operation
@@ -1598,25 +1612,6 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
 
        ret = try_to_free_buffers(page);
 
-       /*
-        * There are a number of places where jbd2_journal_try_to_free_buffers()
-        * could race with jbd2_journal_commit_transaction(), the later still
-        * holds the reference to the buffers to free while processing them.
-        * try_to_free_buffers() failed to free those buffers. Some of the
-        * caller of releasepage() request page buffers to be dropped, otherwise
-        * treat the fail-to-free as errors (such as generic_file_direct_IO())
-        *
-        * So, if the caller of try_to_release_page() wants the synchronous
-        * behaviour(i.e make sure buffers are dropped upon return),
-        * let's wait for the current transaction to finish flush of
-        * dirty data buffers, then try to free those buffers again,
-        * with the journal locked.
-        */
-       if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) {
-               jbd2_journal_wait_for_transaction_sync_data(journal);
-               ret = try_to_free_buffers(page);
-       }
-
 busy:
        return ret;
 }
@@ -1642,8 +1637,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
 
        if (jh->b_cp_transaction) {
                JBUFFER_TRACE(jh, "on running+cp transaction");
+               /*
+                * We don't want to write the buffer anymore, clear the
+                * bit so that we don't confuse checks in
+                * __journal_file_buffer
+                */
+               clear_buffer_dirty(bh);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
-               clear_buffer_jbddirty(bh);
                may_free = 0;
        } else {
                JBUFFER_TRACE(jh, "on running transaction");
@@ -1894,12 +1894,17 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
        if (jh->b_transaction && jh->b_jlist == jlist)
                return;
 
-       /* The following list of buffer states needs to be consistent
-        * with __jbd_unexpected_dirty_buffer()'s handling of dirty
-        * state. */
-
        if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
            jlist == BJ_Shadow || jlist == BJ_Forget) {
+               /*
+                * For metadata buffers, we track dirty bit in buffer_jbddirty
+                * instead of buffer_dirty. We should not see a dirty bit set
+                * here because we clear it in do_get_write_access but e.g.
+                * tune2fs can modify the sb and set the dirty bit at any time
+                * so we try to gracefully handle that.
+                */
+               if (buffer_dirty(bh))
+                       warn_dirty_buffer(bh);
                if (test_clear_buffer_dirty(bh) ||
                    test_clear_buffer_jbddirty(bh))
                        was_dirty = 1;
@@ -2080,26 +2085,46 @@ done:
 }
 
 /*
- * This function must be called when inode is journaled in ordered mode
- * before truncation happens. It starts writeout of truncated part in
- * case it is in the committing transaction so that we stand to ordered
- * mode consistency guarantees.
+ * File truncate and transaction commit interact with each other in a
+ * non-trivial way.  If a transaction writing data block A is
+ * committing, we cannot discard the data by truncate until we have
+ * written them.  Otherwise if we crashed after the transaction with
+ * write has committed but before the transaction with truncate has
+ * committed, we could see stale data in block A.  This function is a
+ * helper to solve this problem.  It starts writeout of the truncated
+ * part in case it is in the committing transaction.
+ *
+ * Filesystem code must call this function when inode is journaled in
+ * ordered mode before truncation happens and after the inode has been
+ * placed on orphan list with the new inode size. The second condition
+ * avoids the race that someone writes new data and we start
+ * committing the transaction after this function has been called but
+ * before a transaction for truncate is started (and furthermore it
+ * allows us to optimize the case where the addition to orphan list
+ * happens in the same transaction as write --- we don't have to write
+ * any data in such case).
  */
-int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+int jbd2_journal_begin_ordered_truncate(journal_t *journal,
+                                       struct jbd2_inode *jinode,
                                        loff_t new_size)
 {
-       journal_t *journal;
-       transaction_t *commit_trans;
+       transaction_t *inode_trans, *commit_trans;
        int ret = 0;
 
-       if (!inode->i_transaction && !inode->i_next_transaction)
+       /* This is a quick check to avoid locking if not necessary */
+       if (!jinode->i_transaction)
                goto out;
-       journal = inode->i_transaction->t_journal;
+       /* Locks are here just to force reading of recent values, it is
+        * enough that the transaction was not committing before we started
+        * a transaction adding the inode to orphan list */
        spin_lock(&journal->j_state_lock);
        commit_trans = journal->j_committing_transaction;
        spin_unlock(&journal->j_state_lock);
-       if (inode->i_transaction == commit_trans) {
-               ret = filemap_fdatawrite_range(inode->i_vfs_inode->i_mapping,
+       spin_lock(&journal->j_list_lock);
+       inode_trans = jinode->i_transaction;
+       spin_unlock(&journal->j_list_lock);
+       if (inode_trans == commit_trans) {
+               ret = filemap_fdatawrite_range(jinode->i_vfs_inode->i_mapping,
                        new_size, LLONG_MAX);
                if (ret)
                        jbd2_journal_abort(journal, ret);