--- /dev/null
+Index: linux-2.6.18-128.1.6/include/linux/jbd2.h
+===================================================================
+--- linux-2.6.18-128.1.6.orig/include/linux/jbd2.h 2009-04-15 08:35:28.000000000 +0530
++++ linux-2.6.18-128.1.6/include/linux/jbd2.h 2009-05-28 15:10:18.000000000 +0530
+@@ -381,6 +381,27 @@
+ bit_spin_unlock(BH_JournalHead, &bh->b_state);
+ }
+
++#define HAVE_JOURNAL_CALLBACK_STATUS
++/**
++ * struct journal_callback - Base structure for callback information.
++ * @jcb_list: list information for other callbacks attached to the same handle.
++ * @jcb_func: Function to call with this callback structure.
++ *
++ * This struct is a 'seed' structure for a using with your own callback
++ * structs. If you are using callbacks you must allocate one of these
++ * or another struct of your own definition which has this struct
++ * as it's first element and pass it to journal_callback_set().
++ *
++ * This is used internally by jbd2 to maintain callback information.
++ *
++ * See journal_callback_set for more information.
++ **/
++struct journal_callback {
++ struct list_head jcb_list; /* t_jcb_lock */
++ void (*jcb_func)(struct journal_callback *jcb, int error);
++ /* user data goes here */
++};
++
+ struct jbd2_revoke_table_s;
+
+ /**
+@@ -389,6 +410,7 @@
+ * @h_transaction: Which compound transaction is this update a part of?
+ * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+ * @h_ref: Reference count on this handle
++ * @h_jcb: List of application registered callbacks for this handle.
+ * @h_err: Field for caller's use to track errors through large fs operations
+ * @h_sync: flag for sync-on-close
+ * @h_jdata: flag to force data journaling
+@@ -414,6 +436,13 @@
+ /* operations */
+ int h_err;
+
++ /*
++ * List of application registered callbacks for this handle. The
++ * function(s) will be called after the transaction that this handle is
++ * part of has been committed to disk. [t_jcb_lock]
++ */
++ struct list_head h_jcb;
++
+ /* Flags [no locking] */
+ unsigned int h_sync: 1; /* sync-on-close */
+ unsigned int h_jdata: 1; /* force data journaling */
+@@ -469,6 +498,8 @@
+ * j_state_lock
+ * ->j_list_lock (journal_unmap_buffer)
+ *
++ * t_handle_lock
++ * ->t_jcb_lock
+ */
+
+ struct transaction_s
+@@ -615,6 +646,15 @@
+ */
+ int t_handle_count;
+
++ /*
++ * Protects the callback list
++ */
++ spinlock_t t_jcb_lock;
++ /*
++ * List of registered callback functions for this transaction.
++ * Called when the transaction is committed. [t_jcb_lock]
++ */
++ struct list_head t_jcb;
+ };
+
+ struct transaction_run_stats_s {
+@@ -1018,6 +1058,9 @@
+ extern int jbd2_journal_flush (journal_t *);
+ extern void jbd2_journal_lock_updates (journal_t *);
+ extern void jbd2_journal_unlock_updates (journal_t *);
++extern void jbd2_journal_callback_set(handle_t *handle,
++ void (*fn)(struct journal_callback *,int),
++ struct journal_callback *jcb);
+
+ extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ struct block_device *fs_dev,
+Index: linux-2.6.18-128.1.6/fs/jbd2/checkpoint.c
+===================================================================
+--- linux-2.6.18-128.1.6.orig/fs/jbd2/checkpoint.c 2009-04-15 08:35:28.000000000 +0530
++++ linux-2.6.18-128.1.6/fs/jbd2/checkpoint.c 2009-05-28 15:10:18.000000000 +0530
+@@ -695,6 +695,7 @@
+ J_ASSERT(transaction->t_checkpoint_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ J_ASSERT(transaction->t_updates == 0);
++ J_ASSERT(list_empty(&transaction->t_jcb));
+ J_ASSERT(journal->j_committing_transaction != transaction);
+ J_ASSERT(journal->j_running_transaction != transaction);
+
+Index: linux-2.6.18-128.1.6/fs/jbd2/commit.c
+===================================================================
+--- linux-2.6.18-128.1.6.orig/fs/jbd2/commit.c 2009-04-15 08:35:28.000000000 +0530
++++ linux-2.6.18-128.1.6/fs/jbd2/commit.c 2009-05-28 15:12:45.000000000 +0530
+@@ -898,6 +898,30 @@
+ transaction can be removed from any checkpoint list it was on
+ before. */
+
++ /*
++ * Call any callbacks that had been registered for handles in this
++ * transaction. It is up to the callback to free any allocated
++ * memory.
++ *
++ * The spinlocking (t_jcb_lock) here is surely unnecessary...
++ */
++ spin_lock(&commit_transaction->t_jcb_lock);
++ if (!list_empty(&commit_transaction->t_jcb)) {
++ struct list_head *p, *n;
++ int error = is_journal_aborted(journal);
++
++ list_for_each_safe(p, n, &commit_transaction->t_jcb) {
++ struct journal_callback *jcb;
++
++ jcb = list_entry(p, struct journal_callback, jcb_list);
++ list_del(p);
++ spin_unlock(&commit_transaction->t_jcb_lock);
++ jcb->jcb_func(jcb, error);
++ spin_lock(&commit_transaction->t_jcb_lock);
++ }
++ }
++ spin_unlock(&commit_transaction->t_jcb_lock);
++
+ jbd_debug(3, "JBD: commit phase 7\n");
+
+ J_ASSERT(commit_transaction->t_sync_datalist == NULL);
+Index: linux-2.6.18-128.1.6/fs/jbd2/journal.c
+===================================================================
+--- linux-2.6.18-128.1.6.orig/fs/jbd2/journal.c 2009-04-15 08:35:28.000000000 +0530
++++ linux-2.6.18-128.1.6/fs/jbd2/journal.c 2009-05-28 17:13:35.000000000 +0530
+@@ -80,6 +80,9 @@
+ EXPORT_SYMBOL(jbd2_journal_invalidatepage);
+ EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
+ EXPORT_SYMBOL(jbd2_journal_force_commit);
++EXPORT_SYMBOL(jbd2_journal_callback_set);
++EXPORT_SYMBOL(jbd2_journal_bmap);
++EXPORT_SYMBOL(jbd2_log_start_commit);
+
+ static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+ static void __journal_abort_soft (journal_t *journal, int errno);
+Index: linux-2.6.18-128.1.6/fs/jbd2/transaction.c
+===================================================================
+--- linux-2.6.18-128.1.6.orig/fs/jbd2/transaction.c 2009-04-15 08:35:28.000000000 +0530
++++ linux-2.6.18-128.1.6/fs/jbd2/transaction.c 2009-05-28 15:11:28.000000000 +0530
+@@ -51,6 +51,9 @@
+ 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_jcb);
++ spin_lock_init(&transaction->t_jcb_lock);
++
+
+ /* Set up the commit timer for the new transaction. */
+ journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
+@@ -251,6 +254,7 @@
+ memset(handle, 0, sizeof(*handle));
+ handle->h_buffer_credits = nblocks;
+ handle->h_ref = 1;
++ INIT_LIST_HEAD(&handle->h_jcb);
+
+ lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle",
+ &jbd2_handle_key, 0);
+@@ -1349,6 +1353,36 @@
+ }
+
+ /**
++ * void jbd2_journal_callback_set() - Register a callback function for this handle.
++ * @handle: handle to attach the callback to.
++ * @func: function to callback.
++ * @jcb: structure with additional information required by func() , and
++ * some space for jbd2 internal information.
++ *
++ * The function will be
++ * called when the transaction that this handle is part of has been
++ * committed to disk with the original callback data struct and the
++ * error status of the journal as parameters. There is no guarantee of
++ * ordering between handles within a single transaction, nor between
++ * callbacks registered on the same handle.
++ *
++ * The caller is responsible for allocating the journal_callback struct.
++ * This is to allow the caller to add as much extra data to the callback
++ * as needed, but reduce the overhead of multiple allocations. The caller
++ * allocated struct must start with a struct journal_callback at offset 0,
++ * and has the caller-specific data afterwards.
++ */
++void jbd2_journal_callback_set(handle_t *handle,
++ void (*func)(struct journal_callback *jcb, int error),
++ struct journal_callback *jcb)
++{
++ spin_lock(&handle->h_transaction->t_jcb_lock);
++ list_add_tail(&jcb->jcb_list, &handle->h_jcb);
++ spin_unlock(&handle->h_transaction->t_jcb_lock);
++ jcb->jcb_func = func;
++}
++
++/**
+ * int jbd2_journal_stop() - complete a transaction
+ * @handle: tranaction to complete.
+ *
+@@ -1422,6 +1456,11 @@
+ wake_up(&journal->j_wait_transaction_locked);
+ }
+
++ /* Move callbacks from the handle to the transaction. */
++ spin_lock(&transaction->t_jcb_lock);
++ list_splice(&handle->h_jcb, &transaction->t_jcb);
++ spin_unlock(&transaction->t_jcb_lock);
++
+ /*
+ * If the handle is marked SYNC, we need to set another commit
+ * going! We also want to force a commit if the current