1 Index: linux-2.4.19-pre1/include/linux/jbd.h
2 ===================================================================
3 --- linux-2.4.19-pre1.orig/include/linux/jbd.h 2003-11-21 03:00:11.000000000 +0300
4 +++ linux-2.4.19-pre1/include/linux/jbd.h 2003-11-21 03:04:47.000000000 +0300
9 +#define HAVE_JOURNAL_CALLBACK_STATUS
10 +struct journal_callback {
11 + struct list_head jcb_list;
12 + void (*jcb_func)(struct journal_callback *jcb, int error);
13 + /* user data goes here */
16 struct jbd_revoke_table_s;
18 /* The handle_t type represents a single atomic update being performed
23 + /* List of application registered callbacks for this handle.
24 + * The function(s) will be called after the transaction that
25 + * this handle is part of has been committed to disk.
27 + struct list_head h_jcb;
30 unsigned int h_sync: 1; /* sync-on-close */
31 unsigned int h_jdata: 1; /* force data journaling */
34 /* How many handles used this transaction? */
37 + /* List of registered callback functions for this transaction.
38 + * Called when the transaction is committed. */
39 + struct list_head t_jcb;
44 extern int journal_try_to_free_buffers(journal_t *, struct page *, int);
45 extern int journal_stop(handle_t *);
46 extern int journal_flush (journal_t *);
47 +extern void journal_callback_set(handle_t *handle,
48 + void (*fn)(struct journal_callback *,int),
49 + struct journal_callback *jcb);
51 extern void journal_lock_updates (journal_t *);
52 extern void journal_unlock_updates (journal_t *);
53 Index: linux-2.4.19-pre1/fs/jbd/checkpoint.c
54 ===================================================================
55 --- linux-2.4.19-pre1.orig/fs/jbd/checkpoint.c 2003-11-21 02:53:20.000000000 +0300
56 +++ linux-2.4.19-pre1/fs/jbd/checkpoint.c 2003-11-21 03:04:47.000000000 +0300
58 J_ASSERT (transaction->t_log_list == NULL);
59 J_ASSERT (transaction->t_checkpoint_list == NULL);
60 J_ASSERT (transaction->t_updates == 0);
62 + J_ASSERT (list_empty(&transaction->t_jcb));
64 J_ASSERT (transaction->t_journal->j_committing_transaction !=
67 Index: linux-2.4.19-pre1/fs/jbd/commit.c
68 ===================================================================
69 --- linux-2.4.19-pre1.orig/fs/jbd/commit.c 2003-11-21 02:53:20.000000000 +0300
70 +++ linux-2.4.19-pre1/fs/jbd/commit.c 2003-11-21 03:04:47.000000000 +0300
72 transaction's t_log_list queue, and metadata buffers are on
73 the t_iobuf_list queue.
75 - Wait for the transactions in reverse order. That way we are
76 + Wait for the buffers in reverse order. That way we are
77 less likely to be woken up until all IOs have completed, and
78 so we incur less scheduling load.
82 jbd_debug(3, "JBD: commit phase 6\n");
84 - if (is_journal_aborted(journal))
85 + if (is_journal_aborted(journal)) {
86 + unlock_journal(journal);
90 /* Done it all: now write the commit record. We should have
91 * cleaned up our previous buffers by now, so if we are in abort
93 descriptor = journal_get_descriptor_buffer(journal);
95 __journal_abort_hard(journal);
96 + unlock_journal(journal);
101 /* AKPM: buglet - add `i' to tmp! */
102 for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
103 journal_header_t *tmp =
104 @@ -605,14 +608,32 @@
105 put_bh(bh); /* One for getblk() */
106 journal_unlock_journal_head(descriptor);
108 - lock_journal(journal);
110 /* End of a transaction! Finally, we can do checkpoint
111 processing: any buffers committed as a result of this
112 transaction can be removed from any checkpoint list it was on
116 +skip_commit: /* The journal should be unlocked by now. */
118 + /* Call any callbacks that had been registered for handles in this
119 + * transaction. It is up to the callback to free any allocated
122 + if (!list_empty(&commit_transaction->t_jcb)) {
123 + struct list_head *p, *n;
124 + int error = is_journal_aborted(journal);
126 + list_for_each_safe(p, n, &commit_transaction->t_jcb) {
127 + struct journal_callback *jcb;
129 + jcb = list_entry(p, struct journal_callback, jcb_list);
131 + jcb->jcb_func(jcb, error);
135 + lock_journal(journal);
137 jbd_debug(3, "JBD: commit phase 7\n");
139 Index: linux-2.4.19-pre1/fs/jbd/journal.c
140 ===================================================================
141 --- linux-2.4.19-pre1.orig/fs/jbd/journal.c 2003-11-21 02:53:20.000000000 +0300
142 +++ linux-2.4.19-pre1/fs/jbd/journal.c 2003-11-21 03:04:47.000000000 +0300
145 EXPORT_SYMBOL(journal_flush);
146 EXPORT_SYMBOL(journal_revoke);
147 +EXPORT_SYMBOL(journal_callback_set);
149 EXPORT_SYMBOL(journal_init_dev);
150 EXPORT_SYMBOL(journal_init_inode);
151 Index: linux-2.4.19-pre1/fs/jbd/transaction.c
152 ===================================================================
153 --- linux-2.4.19-pre1.orig/fs/jbd/transaction.c 2003-11-21 02:53:20.000000000 +0300
154 +++ linux-2.4.19-pre1/fs/jbd/transaction.c 2003-11-21 03:05:14.000000000 +0300
156 transaction->t_state = T_RUNNING;
157 transaction->t_tid = journal->j_transaction_sequence++;
158 transaction->t_expires = jiffies + journal->j_commit_interval;
159 + INIT_LIST_HEAD(&transaction->t_jcb);
161 /* Set up the commit timer for the new transaction. */
162 J_ASSERT (!journal->j_commit_timer_active);
164 transaction_t *transaction;
166 int nblocks = handle->h_buffer_credits;
169 + if (nblocks > journal->j_max_transaction_buffers) {
170 + jbd_debug(1, "JBD: %s wants too many credits (%d > %d)\n",
171 + current->comm, nblocks,
172 + journal->j_max_transaction_buffers);
176 jbd_debug(3, "New handle %p going live.\n", handle);
183 +/* Allocate a new handle. This should probably be in a slab... */
184 +static handle_t *new_handle(int nblocks)
186 + handle_t *handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
189 + memset(handle, 0, sizeof (handle_t));
190 + handle->h_buffer_credits = nblocks;
192 + INIT_LIST_HEAD(&handle->h_jcb);
198 * Obtain a new handle.
200 @@ -222,14 +244,11 @@
205 - handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
207 + handle = new_handle(nblocks);
209 return ERR_PTR(-ENOMEM);
210 - memset (handle, 0, sizeof (handle_t));
212 - handle->h_buffer_credits = nblocks;
214 current->journal_info = handle;
216 err = start_this_handle(journal, handle);
217 @@ -328,14 +347,11 @@
219 if (is_journal_aborted(journal))
220 return ERR_PTR(-EIO);
222 - handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
224 + handle = new_handle(nblocks);
226 return ERR_PTR(-ENOMEM);
227 - memset (handle, 0, sizeof (handle_t));
229 - handle->h_buffer_credits = nblocks;
231 current->journal_info = handle;
233 err = try_start_this_handle(journal, handle);
234 @@ -1324,6 +1340,28 @@
238 + * Register a callback function for this handle. The function will be
239 + * called when the transaction that this handle is part of has been
240 + * committed to disk with the original callback data struct and the
241 + * error status of the journal as parameters. There is no guarantee of
242 + * ordering between handles within a single transaction, nor between
243 + * callbacks registered on the same handle.
245 + * The caller is responsible for allocating the journal_callback struct.
246 + * This is to allow the caller to add as much extra data to the callback
247 + * as needed, but reduce the overhead of multiple allocations. The caller
248 + * allocated struct must start with a struct journal_callback at offset 0,
249 + * and has the caller-specific data afterwards.
251 +void journal_callback_set(handle_t *handle,
252 + void (*func)(struct journal_callback *jcb, int error),
253 + struct journal_callback *jcb)
255 + list_add_tail(&jcb->jcb_list, &handle->h_jcb);
256 + jcb->jcb_func = func;
260 * All done for a particular handle.
262 * There is not much action needed here. We just return any remaining
263 @@ -1389,7 +1427,10 @@
264 wake_up(&journal->j_wait_transaction_locked);
268 + /* Move callbacks from the handle to the transaction. */
269 + list_splice(&handle->h_jcb, &transaction->t_jcb);
272 * If the handle is marked SYNC, we need to set another commit
273 * going! We also want to force a commit if the current
274 * transaction is occupying too much of the log, or if the