if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
OUT_BYTE(0x00, IDE_FEATURE_REG);
+--- lum/include/linux/jbd.h.orig Tue Apr 16 14:27:25 2002
++++ lum/include/linux/jbd.h Wed Apr 24 05:19:00 2002
+@@ -249,6 +249,12 @@
+ return bh->b_private;
+ }
+
++struct journal_callback {
++ struct list_head jcb_list;
++ void (*jcb_func)(void *);
++ /* user data goes here */
++};
++
+ struct jbd_revoke_table_s;
+
+ /* The handle_t type represents a single atomic update being performed
+@@ -279,6 +285,12 @@
+ 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.
++ */
++ struct list_head h_jcb;
++
+ /* Flags */
+ unsigned int h_sync: 1; /* sync-on-close */
+ unsigned int h_jdata: 1; /* force data journaling */
+@@ -398,6 +410,10 @@
+
+ /* How many handles used this transaction? */
+ int t_handle_count;
++
++ /* List of registered callback functions for this transaction.
++ * Called when the transaction is committed. */
++ struct list_head t_jcb;
+ };
+
+
+@@ -547,7 +563,7 @@
+ #define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */
+ #define JFS_LOADED 0x010 /* The journal superblock has been loaded */
+
+-/*
++/*
+ * Function declarations for the journaling transaction and buffer
+ * management
+ */
+@@ -646,6 +662,8 @@
+ extern int journal_try_to_free_buffers(journal_t *, struct page *, int);
+ extern int journal_stop(handle_t *);
+ extern int journal_flush (journal_t *);
++extern void journal_callback_set(handle_t *handle, void (*func)(void *),
++ void *cb_data);
+
+ extern void journal_lock_updates (journal_t *);
+ extern void journal_unlock_updates (journal_t *);
+--- lum/fs/jbd/commit.c.orig Fri Apr 12 10:27:52 2002
++++ lum/fs/jbd/commit.c Wed Apr 24 05:18:07 2002
+@@ -475,7 +475,7 @@
+ transaction's t_log_list queue, and metadata buffers are on
+ the t_iobuf_list queue.
+
+- Wait for the transactions in reverse order. That way we are
++ Wait for the buffers in reverse order. That way we are
+ less likely to be woken up until all IOs have completed, and
+ so we incur less scheduling load.
+ */
+@@ -602,6 +602,21 @@
+ }
+ lock_journal(journal);
+
++ /* Call any callbacks that had been registered for handles in this
++ * transaction. It is up to the callback to free any allocated
++ * memory.
++ */
++ {
++ struct list_head *p, *n;
++ 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);
++ jcb->jcb_func(jcb);
++ }
++ }
++
+ /* End of a transaction! Finally, we can do checkpoint
+ processing: any buffers committed as a result of this
+ transaction can be removed from any checkpoint list it was on
+--- lum/fs/jbd/journal.c.orig Fri Apr 12 10:27:52 2002
++++ lum/fs/jbd/journal.c Wed Apr 24 05:18:49 2002
+@@ -58,6 +58,7 @@
+ #endif
+ EXPORT_SYMBOL(journal_flush);
+ EXPORT_SYMBOL(journal_revoke);
++EXPORT_SYMBOL(journal_callback_set);
+
+ EXPORT_SYMBOL(journal_init_dev);
+ EXPORT_SYMBOL(journal_init_inode);
+--- lum/fs/jbd/transaction.c.orig Fri Apr 12 10:27:52 2002
++++ lum/fs/jbd/transaction.c Wed Apr 24 05:31:14 2002
+@@ -57,6 +57,7 @@
+ transaction->t_state = T_RUNNING;
+ transaction->t_tid = journal->j_transaction_sequence++;
+ transaction->t_expires = jiffies + journal->j_commit_interval;
++ INIT_LIST_HEAD(&transaction->t_jcb);
+
+ /* Set up the commit timer for the new transaction. */
+ J_ASSERT (!journal->j_commit_timer_active);
+@@ -201,6 +202,20 @@
+ return 0;
+ }
+
++/* Allocate a new handle. This should probably be in a slab... */
++static handle_t *get_handle(int nblocks)
++{
++ handle_t *handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
++ if (!handle)
++ return NULL;
++ memset(handle, 0, sizeof (handle_t));
++ handle->h_buffer_credits = nblocks;
++ handle->h_ref = 1;
++ INIT_LIST_HEAD(&handle->h_jcb);
++
++ return handle;
++}
++
+ /*
+ * Obtain a new handle.
+ *
+@@ -227,14 +242,11 @@
+ handle->h_ref++;
+ return handle;
+ }
+-
+- handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
++
++ handle = get_handle(nblocks);
+ if (!handle)
+ return ERR_PTR(-ENOMEM);
+- memset (handle, 0, sizeof (handle_t));
+
+- handle->h_buffer_credits = nblocks;
+- handle->h_ref = 1;
+ current->journal_info = handle;
+
+ err = start_this_handle(journal, handle);
+@@ -333,14 +345,11 @@
+
+ if (is_journal_aborted(journal))
+ return ERR_PTR(-EIO);
+-
+- handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
++
++ handle = get_handle(nblocks);
+ if (!handle)
+ return ERR_PTR(-ENOMEM);
+- memset (handle, 0, sizeof (handle_t));
+
+- handle->h_buffer_credits = nblocks;
+- handle->h_ref = 1;
+ current->journal_info = handle;
+
+ err = try_start_this_handle(journal, handle);
+@@ -1328,6 +1337,27 @@
+ #endif
+
+ /*
++ * Register a callback function for this handle. The function will be
++ * called when the transaction that this handle is part of has been
++ * committed to disk. 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
++ * should use the journal_callback_size() function to reserve enough space
++ * for the JBD-private part of the callback struct.
++ */
++void journal_callback_set(handle_t *handle, void (*func)(void *), void *cb_data)
++{
++ struct journal_callback *jcb = cb_data;
++
++ list_add(&jcb->jcb_list, &handle->h_jcb);
++ jcb->jcb_func = func;
++}
++
++/*
+ * All done for a particular handle.
+ *
+ * There is not much action needed here. We just return any remaining
+@@ -1393,7 +1423,11 @@
+ wake_up(&journal->j_wait_transaction_locked);
+ }
+
+- /*
++ /* Move callbacks from the handle to the transaction. */
++ list_splice(&handle->h_jcb, &transaction->t_jcb);
++ INIT_LIST_HEAD(&handle->h_jcb);
++
++ /*
+ * If the handle is marked SYNC, we need to set another commit
+ * going! We also want to force a commit if the current
+ * transaction is occupying too much of the log, or if the