1 This allows the jbd transaction commit callbacks to be registered.
2 The ext4 jbd2 code has a different commit callback (one per transaction)
3 that could be used to provide equivalent functionality. This would
4 require modifying the existing ext4 commit callback (used by mballoc
5 when freeing data blocks) to be mutiplexed so it will store 2 different
6 callback functions and 2 different lists of callback data.
8 Index: linux+rh+chaos/include/linux/jbd2.h
9 ===================================================================
10 --- linux+rh+chaos.orig/include/linux/jbd2.h
11 +++ linux+rh+chaos/include/linux/jbd2.h
12 @@ -415,6 +415,27 @@ struct jbd2_inode {
16 +#define HAVE_JOURNAL_CALLBACK_STATUS
18 + * struct journal_callback - Base structure for callback information.
19 + * @jcb_list: list information for other callbacks attached to the same handle.
20 + * @jcb_func: Function to call with this callback structure.
22 + * This struct is a 'seed' structure for a using with your own callback
23 + * structs. If you are using callbacks you must allocate one of these
24 + * or another struct of your own definition which has this struct
25 + * as it's first element and pass it to journal_callback_set().
27 + * This is used internally by jbd2 to maintain callback information.
29 + * See journal_callback_set for more information.
31 +struct journal_callback {
32 + struct list_head jcb_list; /* t_jcb_lock */
33 + void (*jcb_func)(struct journal_callback *jcb, int error);
34 + /* user data goes here */
37 struct jbd2_revoke_table_s;
40 @@ -423,6 +444,7 @@ struct jbd2_revoke_table_s;
41 * @h_transaction: Which compound transaction is this update a part of?
42 * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
43 * @h_ref: Reference count on this handle
44 + * @h_jcb: List of application registered callbacks for this handle.
45 * @h_err: Field for caller's use to track errors through large fs operations
46 * @h_sync: flag for sync-on-close
47 * @h_jdata: flag to force data journaling
48 @@ -448,6 +470,13 @@ struct handle_s
53 + * List of application registered callbacks for this handle. The
54 + * function(s) will be called after the transaction that this handle is
55 + * part of has been committed to disk. [t_jcb_lock]
57 + struct list_head h_jcb;
59 /* Flags [no locking] */
60 unsigned int h_sync: 1; /* sync-on-close */
61 unsigned int h_jdata: 1; /* force data journaling */
62 @@ -503,6 +532,8 @@ struct transaction_chp_stats_s {
64 * ->j_list_lock (journal_unmap_buffer)
71 @@ -659,6 +690,16 @@ struct transaction_s
72 * structures associated with the transaction
74 struct list_head t_private_list;
77 + * Protects the callback list
79 + spinlock_t t_jcb_lock;
81 + * List of registered callback functions for this transaction.
82 + * Called when the transaction is committed. [t_jcb_lock]
84 + struct list_head t_jcb;
87 struct transaction_run_stats_s {
88 @@ -1115,6 +1156,9 @@ extern int jbd2_journal_stop(handle_t *
89 extern int jbd2_journal_flush (journal_t *);
90 extern void jbd2_journal_lock_updates (journal_t *);
91 extern void jbd2_journal_unlock_updates (journal_t *);
92 +extern void jbd2_journal_callback_set(handle_t *handle,
93 + void (*fn)(struct journal_callback *,int),
94 + struct journal_callback *jcb);
96 extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
97 struct block_device *fs_dev,
98 Index: linux+rh+chaos/fs/jbd2/checkpoint.c
99 ===================================================================
100 --- linux+rh+chaos.orig/fs/jbd2/checkpoint.c
101 +++ linux+rh+chaos/fs/jbd2/checkpoint.c
102 @@ -759,6 +759,7 @@ void __jbd2_journal_drop_transaction(jou
103 J_ASSERT(transaction->t_checkpoint_list == NULL);
104 J_ASSERT(transaction->t_checkpoint_io_list == NULL);
105 J_ASSERT(transaction->t_updates == 0);
106 + J_ASSERT(list_empty(&transaction->t_jcb));
107 J_ASSERT(journal->j_committing_transaction != transaction);
108 J_ASSERT(journal->j_running_transaction != transaction);
110 Index: linux+rh+chaos/fs/jbd2/commit.c
111 ===================================================================
112 --- linux+rh+chaos.orig/fs/jbd2/commit.c
113 +++ linux+rh+chaos/fs/jbd2/commit.c
114 @@ -857,6 +857,30 @@ wait_for_iobuf:
115 transaction can be removed from any checkpoint list it was on
119 + * Call any callbacks that had been registered for handles in this
120 + * transaction. It is up to the callback to free any allocated
123 + * The spinlocking (t_jcb_lock) here is surely unnecessary...
125 + spin_lock(&commit_transaction->t_jcb_lock);
126 + if (!list_empty(&commit_transaction->t_jcb)) {
127 + struct list_head *p, *n;
128 + int error = is_journal_aborted(journal);
130 + list_for_each_safe(p, n, &commit_transaction->t_jcb) {
131 + struct journal_callback *jcb;
133 + jcb = list_entry(p, struct journal_callback, jcb_list);
135 + spin_unlock(&commit_transaction->t_jcb_lock);
136 + jcb->jcb_func(jcb, error);
137 + spin_lock(&commit_transaction->t_jcb_lock);
140 + spin_unlock(&commit_transaction->t_jcb_lock);
142 jbd_debug(3, "JBD: commit phase 6\n");
144 J_ASSERT(list_empty(&commit_transaction->t_inode_list));
145 Index: linux+rh+chaos/fs/jbd2/journal.c
146 ===================================================================
147 --- linux+rh+chaos.orig/fs/jbd2/journal.c
148 +++ linux+rh+chaos/fs/jbd2/journal.c
149 @@ -90,6 +90,8 @@ EXPORT_SYMBOL(jbd2_journal_file_inode);
150 EXPORT_SYMBOL(jbd2_journal_init_jbd_inode);
151 EXPORT_SYMBOL(jbd2_journal_release_jbd_inode);
152 EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
153 +EXPORT_SYMBOL(jbd2_journal_callback_set);
154 +EXPORT_SYMBOL(jbd2_journal_bmap);
156 static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
157 static void __journal_abort_soft (journal_t *journal, int errno);
158 Index: linux+rh+chaos/fs/jbd2/transaction.c
159 ===================================================================
160 --- linux+rh+chaos.orig/fs/jbd2/transaction.c
161 +++ linux+rh+chaos/fs/jbd2/transaction.c
162 @@ -52,7 +52,9 @@ jbd2_get_transaction(journal_t *journal,
163 transaction->t_start_time = ktime_get();
164 transaction->t_tid = journal->j_transaction_sequence++;
165 transaction->t_expires = jiffies + journal->j_commit_interval;
166 + INIT_LIST_HEAD(&transaction->t_jcb);
167 spin_lock_init(&transaction->t_handle_lock);
168 + spin_lock_init(&transaction->t_jcb_lock);
169 INIT_LIST_HEAD(&transaction->t_inode_list);
170 INIT_LIST_HEAD(&transaction->t_private_list);
172 @@ -257,6 +259,7 @@ static handle_t *new_handle(int nblocks)
173 memset(handle, 0, sizeof(*handle));
174 handle->h_buffer_credits = nblocks;
176 + INIT_LIST_HEAD(&handle->h_jcb);
178 lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle",
179 &jbd2_handle_key, 0);
180 @@ -1216,6 +1219,36 @@ drop:
184 + * void jbd2_journal_callback_set() - Register a callback function for this handle.
185 + * @handle: handle to attach the callback to.
186 + * @func: function to callback.
187 + * @jcb: structure with additional information required by func() , and
188 + * some space for jbd2 internal information.
190 + * The function will be
191 + * called when the transaction that this handle is part of has been
192 + * committed to disk with the original callback data struct and the
193 + * error status of the journal as parameters. There is no guarantee of
194 + * ordering between handles within a single transaction, nor between
195 + * callbacks registered on the same handle.
197 + * The caller is responsible for allocating the journal_callback struct.
198 + * This is to allow the caller to add as much extra data to the callback
199 + * as needed, but reduce the overhead of multiple allocations. The caller
200 + * allocated struct must start with a struct journal_callback at offset 0,
201 + * and has the caller-specific data afterwards.
203 +void jbd2_journal_callback_set(handle_t *handle,
204 + void (*func)(struct journal_callback *jcb, int error),
205 + struct journal_callback *jcb)
207 + spin_lock(&handle->h_transaction->t_jcb_lock);
208 + list_add_tail(&jcb->jcb_list, &handle->h_jcb);
209 + spin_unlock(&handle->h_transaction->t_jcb_lock);
210 + jcb->jcb_func = func;
214 * int jbd2_journal_stop() - complete a transaction
215 * @handle: tranaction to complete.
217 @@ -1321,6 +1354,11 @@ int jbd2_journal_stop(handle_t *handle)
218 wake_up(&journal->j_wait_transaction_locked);
221 + /* Move callbacks from the handle to the transaction. */
222 + spin_lock(&transaction->t_jcb_lock);
223 + list_splice(&handle->h_jcb, &transaction->t_jcb);
224 + spin_unlock(&transaction->t_jcb_lock);
227 * If the handle is marked SYNC, we need to set another commit
228 * going! We also want to force a commit if the current