fuse: nfs export special lookups
[safe/jmp/linux-2.6] / fs / jbd2 / transaction.c
index 3a87001..4f7cadb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/transaction.c
+ * linux/fs/jbd2/transaction.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
  *
@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 
@@ -42,7 +41,6 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
  *     new transaction and we can't block without protecting against other
  *     processes trying to touch the journal while it is in transition.
  *
- * Called under j_state_lock
  */
 
 static transaction_t *
@@ -53,13 +51,16 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
        transaction->t_tid = journal->j_transaction_sequence++;
        transaction->t_expires = jiffies + journal->j_commit_interval;
        spin_lock_init(&transaction->t_handle_lock);
+       INIT_LIST_HEAD(&transaction->t_inode_list);
 
        /* Set up the commit timer for the new transaction. */
-       journal->j_commit_timer.expires = transaction->t_expires;
+       journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
        add_timer(&journal->j_commit_timer);
 
        J_ASSERT(journal->j_running_transaction == NULL);
        journal->j_running_transaction = transaction;
+       transaction->t_max_wait = 0;
+       transaction->t_start = jiffies;
 
        return transaction;
 }
@@ -86,6 +87,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle)
        int nblocks = handle->h_buffer_credits;
        transaction_t *new_transaction = NULL;
        int ret = 0;
+       unsigned long ts = jiffies;
 
        if (nblocks > journal->j_max_transaction_buffers) {
                printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
@@ -97,13 +99,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle)
 
 alloc_transaction:
        if (!journal->j_running_transaction) {
-               new_transaction = jbd_kmalloc(sizeof(*new_transaction),
-                                               GFP_NOFS);
+               new_transaction = kzalloc(sizeof(*new_transaction),
+                                               GFP_NOFS|__GFP_NOFAIL);
                if (!new_transaction) {
                        ret = -ENOMEM;
                        goto out;
                }
-               memset(new_transaction, 0, sizeof(*new_transaction));
        }
 
        jbd_debug(3, "New handle %p going live.\n", handle);
@@ -219,6 +220,12 @@ repeat_locked:
        /* OK, account for the buffers that this operation expects to
         * use and add the handle to the running transaction. */
 
+       if (time_after(transaction->t_start, ts)) {
+               ts = jbd2_time_diff(ts, transaction->t_start);
+               if (ts > transaction->t_max_wait)
+                       transaction->t_max_wait = ts;
+       }
+
        handle->h_transaction = transaction;
        transaction->t_outstanding_credits += nblocks;
        transaction->t_updates++;
@@ -234,16 +241,21 @@ out:
        return ret;
 }
 
+static struct lock_class_key jbd2_handle_key;
+
 /* Allocate a new handle.  This should probably be in a slab... */
 static handle_t *new_handle(int nblocks)
 {
-       handle_t *handle = jbd_alloc_handle(GFP_NOFS);
+       handle_t *handle = jbd2_alloc_handle(GFP_NOFS);
        if (!handle)
                return NULL;
        memset(handle, 0, sizeof(*handle));
        handle->h_buffer_credits = nblocks;
        handle->h_ref = 1;
 
+       lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle",
+                                               &jbd2_handle_key, 0);
+
        return handle;
 }
 
@@ -283,10 +295,14 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
 
        err = start_this_handle(journal, handle);
        if (err < 0) {
-               jbd_free_handle(handle);
+               jbd2_free_handle(handle);
                current->journal_info = NULL;
                handle = ERR_PTR(err);
+               goto out;
        }
+
+       lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_);
+out:
        return handle;
 }
 
@@ -602,6 +618,12 @@ repeat:
                goto done;
 
        /*
+        * this is the first time this transaction is touching this buffer,
+        * reset the modified flag
+        */
+       jh->b_modified = 0;
+
+       /*
         * If there is already a copy-out version of this buffer, then we don't
         * need to make another one
         */
@@ -669,12 +691,12 @@ repeat:
                                JBUFFER_TRACE(jh, "allocate memory for buffer");
                                jbd_unlock_bh_state(bh);
                                frozen_buffer =
-                                       jbd2_slab_alloc(jh2bh(jh)->b_size,
+                                       jbd2_alloc(jh2bh(jh)->b_size,
                                                         GFP_NOFS);
                                if (!frozen_buffer) {
                                        printk(KERN_EMERG
                                               "%s: OOM for frozen_buffer\n",
-                                              __FUNCTION__);
+                                              __func__);
                                        JBUFFER_TRACE(jh, "oom!");
                                        error = -ENOMEM;
                                        jbd_lock_bh_state(bh);
@@ -729,7 +751,7 @@ done:
 
 out:
        if (unlikely(frozen_buffer))    /* It's usually NULL */
-               jbd2_slab_free(frozen_buffer, bh->b_size);
+               jbd2_free(frozen_buffer, bh->b_size);
 
        JBUFFER_TRACE(jh, "exit");
        return error;
@@ -813,9 +835,16 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
 
        if (jh->b_transaction == NULL) {
                jh->b_transaction = transaction;
+
+               /* first access by this transaction */
+               jh->b_modified = 0;
+
                JBUFFER_TRACE(jh, "file as BJ_Reserved");
                __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
        } else if (jh->b_transaction == journal->j_committing_transaction) {
+               /* first access by this transaction */
+               jh->b_modified = 0;
+
                JBUFFER_TRACE(jh, "set next transaction");
                jh->b_next_transaction = transaction;
        }
@@ -882,10 +911,10 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
 
 repeat:
        if (!jh->b_committed_data) {
-               committed_data = jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS);
+               committed_data = jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS);
                if (!committed_data) {
                        printk(KERN_EMERG "%s: No memory for committed data\n",
-                               __FUNCTION__);
+                               __func__);
                        err = -ENOMEM;
                        goto out;
                }
@@ -909,188 +938,11 @@ repeat:
 out:
        jbd2_journal_put_journal_head(jh);
        if (unlikely(committed_data))
-               jbd2_slab_free(committed_data, bh->b_size);
+               jbd2_free(committed_data, bh->b_size);
        return err;
 }
 
 /**
- * int jbd2_journal_dirty_data() -  mark a buffer as containing dirty data which
- *                             needs to be flushed before we can commit the
- *                             current transaction.
- * @handle: transaction
- * @bh: bufferhead to mark
- *
- * The buffer is placed on the transaction's data list and is marked as
- * belonging to the transaction.
- *
- * Returns error number or 0 on success.
- *
- * jbd2_journal_dirty_data() can be called via page_launder->ext3_writepage
- * by kswapd.
- */
-int jbd2_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
-{
-       journal_t *journal = handle->h_transaction->t_journal;
-       int need_brelse = 0;
-       struct journal_head *jh;
-
-       if (is_handle_aborted(handle))
-               return 0;
-
-       jh = jbd2_journal_add_journal_head(bh);
-       JBUFFER_TRACE(jh, "entry");
-
-       /*
-        * The buffer could *already* be dirty.  Writeout can start
-        * at any time.
-        */
-       jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid);
-
-       /*
-        * What if the buffer is already part of a running transaction?
-        *
-        * There are two cases:
-        * 1) It is part of the current running transaction.  Refile it,
-        *    just in case we have allocated it as metadata, deallocated
-        *    it, then reallocated it as data.
-        * 2) It is part of the previous, still-committing transaction.
-        *    If all we want to do is to guarantee that the buffer will be
-        *    written to disk before this new transaction commits, then
-        *    being sure that the *previous* transaction has this same
-        *    property is sufficient for us!  Just leave it on its old
-        *    transaction.
-        *
-        * In case (2), the buffer must not already exist as metadata
-        * --- that would violate write ordering (a transaction is free
-        * to write its data at any point, even before the previous
-        * committing transaction has committed).  The caller must
-        * never, ever allow this to happen: there's nothing we can do
-        * about it in this layer.
-        */
-       jbd_lock_bh_state(bh);
-       spin_lock(&journal->j_list_lock);
-
-       /* Now that we have bh_state locked, are we really still mapped? */
-       if (!buffer_mapped(bh)) {
-               JBUFFER_TRACE(jh, "unmapped buffer, bailing out");
-               goto no_journal;
-       }
-
-       if (jh->b_transaction) {
-               JBUFFER_TRACE(jh, "has transaction");
-               if (jh->b_transaction != handle->h_transaction) {
-                       JBUFFER_TRACE(jh, "belongs to older transaction");
-                       J_ASSERT_JH(jh, jh->b_transaction ==
-                                       journal->j_committing_transaction);
-
-                       /* @@@ IS THIS TRUE  ? */
-                       /*
-                        * Not any more.  Scenario: someone does a write()
-                        * in data=journal mode.  The buffer's transaction has
-                        * moved into commit.  Then someone does another
-                        * write() to the file.  We do the frozen data copyout
-                        * and set b_next_transaction to point to j_running_t.
-                        * And while we're in that state, someone does a
-                        * writepage() in an attempt to pageout the same area
-                        * of the file via a shared mapping.  At present that
-                        * calls jbd2_journal_dirty_data(), and we get right here.
-                        * It may be too late to journal the data.  Simply
-                        * falling through to the next test will suffice: the
-                        * data will be dirty and wil be checkpointed.  The
-                        * ordering comments in the next comment block still
-                        * apply.
-                        */
-                       //J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
-
-                       /*
-                        * If we're journalling data, and this buffer was
-                        * subject to a write(), it could be metadata, forget
-                        * or shadow against the committing transaction.  Now,
-                        * someone has dirtied the same darn page via a mapping
-                        * and it is being writepage()'d.
-                        * We *could* just steal the page from commit, with some
-                        * fancy locking there.  Instead, we just skip it -
-                        * don't tie the page's buffers to the new transaction
-                        * at all.
-                        * Implication: if we crash before the writepage() data
-                        * is written into the filesystem, recovery will replay
-                        * the write() data.
-                        */
-                       if (jh->b_jlist != BJ_None &&
-                                       jh->b_jlist != BJ_SyncData &&
-                                       jh->b_jlist != BJ_Locked) {
-                               JBUFFER_TRACE(jh, "Not stealing");
-                               goto no_journal;
-                       }
-
-                       /*
-                        * This buffer may be undergoing writeout in commit.  We
-                        * can't return from here and let the caller dirty it
-                        * again because that can cause the write-out loop in
-                        * commit to never terminate.
-                        */
-                       if (buffer_dirty(bh)) {
-                               get_bh(bh);
-                               spin_unlock(&journal->j_list_lock);
-                               jbd_unlock_bh_state(bh);
-                               need_brelse = 1;
-                               sync_dirty_buffer(bh);
-                               jbd_lock_bh_state(bh);
-                               spin_lock(&journal->j_list_lock);
-                               /* Since we dropped the lock... */
-                               if (!buffer_mapped(bh)) {
-                                       JBUFFER_TRACE(jh, "buffer got unmapped");
-                                       goto no_journal;
-                               }
-                               /* The buffer may become locked again at any
-                                  time if it is redirtied */
-                       }
-
-                       /* journal_clean_data_list() may have got there first */
-                       if (jh->b_transaction != NULL) {
-                               JBUFFER_TRACE(jh, "unfile from commit");
-                               __jbd2_journal_temp_unlink_buffer(jh);
-                               /* It still points to the committing
-                                * transaction; move it to this one so
-                                * that the refile assert checks are
-                                * happy. */
-                               jh->b_transaction = handle->h_transaction;
-                       }
-                       /* The buffer will be refiled below */
-
-               }
-               /*
-                * Special case --- the buffer might actually have been
-                * allocated and then immediately deallocated in the previous,
-                * committing transaction, so might still be left on that
-                * transaction's metadata lists.
-                */
-               if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
-                       JBUFFER_TRACE(jh, "not on correct data list: unfile");
-                       J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
-                       __jbd2_journal_temp_unlink_buffer(jh);
-                       jh->b_transaction = handle->h_transaction;
-                       JBUFFER_TRACE(jh, "file as data");
-                       __jbd2_journal_file_buffer(jh, handle->h_transaction,
-                                               BJ_SyncData);
-               }
-       } else {
-               JBUFFER_TRACE(jh, "not on a transaction");
-               __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_SyncData);
-       }
-no_journal:
-       spin_unlock(&journal->j_list_lock);
-       jbd_unlock_bh_state(bh);
-       if (need_brelse) {
-               BUFFER_TRACE(bh, "brelse");
-               __brelse(bh);
-       }
-       JBUFFER_TRACE(jh, "exit");
-       jbd2_journal_put_journal_head(jh);
-       return 0;
-}
-
-/**
  * int jbd2_journal_dirty_metadata() -  mark a buffer as containing dirty metadata
  * @handle: transaction to add buffer to.
  * @bh: buffer to mark
@@ -1166,7 +1018,7 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
        }
 
        /* That test should have eliminated the following case: */
-       J_ASSERT_JH(jh, jh->b_frozen_data == 0);
+       J_ASSERT_JH(jh, jh->b_frozen_data == NULL);
 
        JBUFFER_TRACE(jh, "file as BJ_Metadata");
        spin_lock(&journal->j_list_lock);
@@ -1214,6 +1066,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
        struct journal_head *jh;
        int drop_reserve = 0;
        int err = 0;
+       int was_modified = 0;
 
        BUFFER_TRACE(bh, "entry");
 
@@ -1232,6 +1085,9 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
                goto not_jbd;
        }
 
+       /* keep track of wether or not this transaction modified us */
+       was_modified = jh->b_modified;
+
        /*
         * The buffer's going from the transaction, we must drop
         * all references -bzzz
@@ -1249,7 +1105,12 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
 
                JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
 
-               drop_reserve = 1;
+               /*
+                * we only want to drop a reference if this transaction
+                * modified the buffer
+                */
+               if (was_modified)
+                       drop_reserve = 1;
 
                /*
                 * We are no longer going to journal this buffer.
@@ -1289,7 +1150,13 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
                if (jh->b_next_transaction) {
                        J_ASSERT(jh->b_next_transaction == transaction);
                        jh->b_next_transaction = NULL;
-                       drop_reserve = 1;
+
+                       /*
+                        * only drop a reference if this transaction modified
+                        * the buffer
+                        */
+                       if (was_modified)
+                               drop_reserve = 1;
                }
        }
 
@@ -1412,11 +1279,14 @@ int jbd2_journal_stop(handle_t *handle)
                spin_unlock(&journal->j_state_lock);
        }
 
-       jbd_free_handle(handle);
+       lock_release(&handle->h_lockdep_map, 1, _THIS_IP_);
+
+       jbd2_free_handle(handle);
        return err;
 }
 
-/**int jbd2_journal_force_commit() - force any uncommitted transactions
+/**
+ * int jbd2_journal_force_commit() - force any uncommitted transactions
  * @journal: journal to force
  *
  * For synchronous operations: force any uncommitted transactions
@@ -1494,10 +1364,10 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh)
  * Remove a buffer from the appropriate transaction list.
  *
  * Note that this function can *change* the value of
- * bh->b_transaction->t_sync_datalist, t_buffers, t_forget,
- * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list.  If the caller
- * is holding onto a copy of one of thee pointers, it could go bad.
- * Generally the caller needs to re-read the pointer from the transaction_t.
+ * bh->b_transaction->t_buffers, t_forget, t_iobuf_list, t_shadow_list,
+ * t_log_list or t_reserved_list.  If the caller is holding onto a copy of one
+ * of these pointers, it could go bad.  Generally the caller needs to re-read
+ * the pointer from the transaction_t.
  *
  * Called under j_list_lock.  The journal may not be locked.
  */
@@ -1514,14 +1384,11 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
 
        J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
        if (jh->b_jlist != BJ_None)
-               J_ASSERT_JH(jh, transaction != 0);
+               J_ASSERT_JH(jh, transaction != NULL);
 
        switch (jh->b_jlist) {
        case BJ_None:
                return;
-       case BJ_SyncData:
-               list = &transaction->t_sync_datalist;
-               break;
        case BJ_Metadata:
                transaction->t_nr_buffers--;
                J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0);
@@ -1542,9 +1409,6 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
        case BJ_Reserved:
                list = &transaction->t_reserved_list;
                break;
-       case BJ_Locked:
-               list = &transaction->t_locked_list;
-               break;
        }
 
        __blist_del_buffer(list, jh);
@@ -1583,19 +1447,11 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
        if (buffer_locked(bh) || buffer_dirty(bh))
                goto out;
 
-       if (jh->b_next_transaction != 0)
+       if (jh->b_next_transaction != NULL)
                goto out;
 
        spin_lock(&journal->j_list_lock);
-       if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) {
-               if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) {
-                       /* A written-back ordered data buffer */
-                       JBUFFER_TRACE(jh, "release data");
-                       __jbd2_journal_unfile_buffer(jh);
-                       jbd2_journal_remove_journal_head(bh);
-                       __brelse(bh);
-               }
-       } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) {
+       if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) {
                /* written-back checkpointed metadata buffer */
                if (jh->b_jlist == BJ_None) {
                        JBUFFER_TRACE(jh, "remove from checkpoint list");
@@ -1609,12 +1465,43 @@ 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
  * @page: to try and free
- * @unused_gfp_mask: unused
+ * @gfp_mask: we use the mask to detect how hard should we try to release
+ * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to
+ * release the buffers.
  *
  *
  * For all the buffers on this page,
@@ -1643,9 +1530,11 @@ out:
  * journal_try_to_free_buffer() is changing its state.  But that
  * cannot happen because we never reallocate freed data as metadata
  * while the data is part of a transaction.  Yes?
+ *
+ * Return 0 on failure, 1 on success
  */
 int jbd2_journal_try_to_free_buffers(journal_t *journal,
-                               struct page *page, gfp_t unused_gfp_mask)
+                               struct page *page, gfp_t gfp_mask)
 {
        struct buffer_head *head;
        struct buffer_head *bh;
@@ -1661,7 +1550,8 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
                /*
                 * We take our own ref against the journal_head here to avoid
                 * having to add tons of locking around each instance of
-                * jbd2_journal_remove_journal_head() and jbd2_journal_put_journal_head().
+                * jbd2_journal_remove_journal_head() and
+                * jbd2_journal_put_journal_head().
                 */
                jh = jbd2_journal_grab_journal_head(bh);
                if (!jh)
@@ -1674,7 +1564,28 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
                if (buffer_jbd(bh))
                        goto busy;
        } while ((bh = bh->b_this_page) != head);
+
        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;
 }
@@ -1776,6 +1687,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
        if (!buffer_jbd(bh))
                goto zap_buffer_unlocked;
 
+       /* OK, we have data buffer in journaled mode */
        spin_lock(&journal->j_state_lock);
        jbd_lock_bh_state(bh);
        spin_lock(&journal->j_list_lock);
@@ -1839,15 +1751,6 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
                }
        } else if (transaction == journal->j_committing_transaction) {
                JBUFFER_TRACE(jh, "on committing transaction");
-               if (jh->b_jlist == BJ_Locked) {
-                       /*
-                        * The buffer is on the committing transaction's locked
-                        * list.  We have the buffer locked, so I/O has
-                        * completed.  So we can nail the buffer now.
-                        */
-                       may_free = __dispose_buffer(jh, transaction);
-                       goto zap_buffer;
-               }
                /*
                 * If it is committing, we simply cannot touch it.  We
                 * can remove it's next_transaction pointer from the
@@ -1955,7 +1858,7 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
 
        J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
        J_ASSERT_JH(jh, jh->b_transaction == transaction ||
-                               jh->b_transaction == 0);
+                               jh->b_transaction == NULL);
 
        if (jh->b_transaction && jh->b_jlist == jlist)
                return;
@@ -1980,9 +1883,6 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
                J_ASSERT_JH(jh, !jh->b_committed_data);
                J_ASSERT_JH(jh, !jh->b_frozen_data);
                return;
-       case BJ_SyncData:
-               list = &transaction->t_sync_datalist;
-               break;
        case BJ_Metadata:
                transaction->t_nr_buffers++;
                list = &transaction->t_buffers;
@@ -2002,9 +1902,6 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
        case BJ_Reserved:
                list = &transaction->t_reserved_list;
                break;
-       case BJ_Locked:
-               list =  &transaction->t_locked_list;
-               break;
        }
 
        __blist_add_buffer(list, jh);
@@ -2059,7 +1956,7 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
        jh->b_transaction = jh->b_next_transaction;
        jh->b_next_transaction = NULL;
        __jbd2_journal_file_buffer(jh, jh->b_transaction,
-                               was_dirty ? BJ_Metadata : BJ_Reserved);
+                               jh->b_modified ? BJ_Metadata : BJ_Reserved);
        J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
 
        if (was_dirty)
@@ -2094,3 +1991,88 @@ void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
        spin_unlock(&journal->j_list_lock);
        __brelse(bh);
 }
+
+/*
+ * File inode in the inode list of the handle's transaction
+ */
+int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
+{
+       transaction_t *transaction = handle->h_transaction;
+       journal_t *journal = transaction->t_journal;
+
+       if (is_handle_aborted(handle))
+               return -EIO;
+
+       jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino,
+                       transaction->t_tid);
+
+       /*
+        * First check whether inode isn't already on the transaction's
+        * lists without taking the lock. Note that this check is safe
+        * without the lock as we cannot race with somebody removing inode
+        * from the transaction. The reason is that we remove inode from the
+        * transaction only in journal_release_jbd_inode() and when we commit
+        * the transaction. We are guarded from the first case by holding
+        * a reference to the inode. We are safe against the second case
+        * because if jinode->i_transaction == transaction, commit code
+        * cannot touch the transaction because we hold reference to it,
+        * and if jinode->i_next_transaction == transaction, commit code
+        * will only file the inode where we want it.
+        */
+       if (jinode->i_transaction == transaction ||
+           jinode->i_next_transaction == transaction)
+               return 0;
+
+       spin_lock(&journal->j_list_lock);
+
+       if (jinode->i_transaction == transaction ||
+           jinode->i_next_transaction == transaction)
+               goto done;
+
+       /* On some different transaction's list - should be
+        * the committing one */
+       if (jinode->i_transaction) {
+               J_ASSERT(jinode->i_next_transaction == NULL);
+               J_ASSERT(jinode->i_transaction ==
+                                       journal->j_committing_transaction);
+               jinode->i_next_transaction = transaction;
+               goto done;
+       }
+       /* Not on any transaction list... */
+       J_ASSERT(!jinode->i_next_transaction);
+       jinode->i_transaction = transaction;
+       list_add(&jinode->i_list, &transaction->t_inode_list);
+done:
+       spin_unlock(&journal->j_list_lock);
+
+       return 0;
+}
+
+/*
+ * 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.
+ */
+int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+                                       loff_t new_size)
+{
+       journal_t *journal;
+       transaction_t *commit_trans;
+       int ret = 0;
+
+       if (!inode->i_transaction && !inode->i_next_transaction)
+               goto out;
+       journal = inode->i_transaction->t_journal;
+       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,
+                       new_size, LLONG_MAX);
+               if (ret)
+                       jbd2_journal_abort(journal, ret);
+       }
+out:
+       return ret;
+}