Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / jbd-jcberr-2.6.18-vanilla.patch
1 Implement a JBD per-transaction commit callback.  Users can attach arbitrary
2 callbacks to a journal handle, which are propagated to the transaction at
3 journal handle stop time.  The commit callbacks are run when the transaction
4 is finished commit, and will be passed a non-zero error code if there was
5 a commit error.
6
7 Signed-off-by: Andreas Dilger <adilger@sun.com>
8
9
10 Index: linux-2.6/include/linux/jbd.h
11 ===================================================================
12 --- linux-2.6.orig/include/linux/jbd.h  2006-07-15 16:08:35.000000000 +0800
13 +++ linux-2.6/include/linux/jbd.h       2006-07-15 16:13:01.000000000 +0800
14 @@ -356,6 +356,27 @@ static inline void jbd_unlock_bh_journal
15         bit_spin_unlock(BH_JournalHead, &bh->b_state);
16  }
17  
18 +#define HAVE_JOURNAL_CALLBACK_STATUS
19 +/**
20 + * struct journal_callback - Base structure for callback information
21 + * @jcb_list: list information for other callbacks attached to the same handle
22 + * @jcb_func: Function to call with this callback structure
23 + *
24 + * This struct is a 'seed' structure for a using with your own callback
25 + * structs. If you are using callbacks you must allocate one of these
26 + * or another struct of your own definition which has this struct 
27 + * as it's first element and pass it to journal_callback_set().
28 + *
29 + * This is used internally by jbd to maintain callback information.
30 + *
31 + * See journal_callback_set for more information.
32 + **/
33 +struct journal_callback {
34 +       struct list_head jcb_list;              /* t_jcb_lock */
35 +       void (*jcb_func)(struct journal_callback *jcb, int error);
36 +       /* caller data goes here */
37 +};
38 +
39  struct jbd_revoke_table_s;
40  
41  /**
42 @@ -364,6 +385,7 @@ struct jbd_revoke_table_s;
43   * @h_transaction: Which compound transaction is this update a part of?
44   * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
45   * @h_ref: Reference count on this handle
46 + * @h_jcb: List of application registered callbacks for this handle.
47   * @h_err: Field for caller's use to track errors through large fs operations
48   * @h_sync: flag for sync-on-close
49   * @h_jdata: flag to force data journaling
50 @@ -389,6 +411,13 @@ struct handle_s 
51         /* operations */
52         int                     h_err;
53  
54 +       /*
55 +        * List of application registered callbacks for this handle. The
56 +        * function(s) will be called after the transaction that this handle is
57 +        * part of has been committed to disk. [t_jcb_lock]
58 +        */
59 +       struct list_head        h_jcb;
60 +
61         /* Flags [no locking] */
62         unsigned int    h_sync:         1;      /* sync-on-close */
63         unsigned int    h_jdata:        1;      /* force data journaling */
64 @@ -430,6 +459,8 @@ struct handle_s 
65   *    j_state_lock
66   *    ->j_list_lock                    (journal_unmap_buffer)
67   *
68 + *    t_handle_lock
69 + *    ->t_jcb_lock
70   */
71  
72  struct transaction_s 
73 @@ -559,6 +590,15 @@ struct transaction_s 
74          */
75         int t_handle_count;
76  
77 +       /*
78 +        * Protects the callback list
79 +        */
80 +       spinlock_t              t_jcb_lock;
81 +       /*
82 +        * List of registered callback functions for this transaction.
83 +        * Called when the transaction is committed. [t_jcb_lock]
84 +        */
85 +       struct list_head        t_jcb;
86  };
87  
88  /**
89 @@ -906,6 +946,10 @@ extern void         journal_invalidatepage(jour
90  extern int      journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
91  extern int      journal_stop(handle_t *);
92  extern int      journal_flush (journal_t *);
93 +extern void     journal_callback_set(handle_t *handle,
94 +                                     void (*fn)(struct journal_callback *,int),
95 +                                     struct journal_callback *jcb);
96 +
97  extern void     journal_lock_updates (journal_t *);
98  extern void     journal_unlock_updates (journal_t *);
99  
100 Index: linux-2.6/fs/jbd/checkpoint.c
101 ===================================================================
102 --- linux-2.6.orig/fs/jbd/checkpoint.c  2006-07-15 16:08:36.000000000 +0800
103 +++ linux-2.6/fs/jbd/checkpoint.c       2006-07-15 16:13:01.000000000 +0800
104 @@ -688,6 +688,7 @@ void __journal_drop_transaction(journal_
105         J_ASSERT(transaction->t_checkpoint_list == NULL);
106         J_ASSERT(transaction->t_checkpoint_io_list == NULL);
107         J_ASSERT(transaction->t_updates == 0);
108 +       J_ASSERT(list_empty(&transaction->t_jcb));
109         J_ASSERT(journal->j_committing_transaction != transaction);
110         J_ASSERT(journal->j_running_transaction != transaction);
111  
112 Index: linux-2.6/fs/jbd/commit.c
113 ===================================================================
114 --- linux-2.6.orig/fs/jbd/commit.c      2006-07-15 16:08:36.000000000 +0800
115 +++ linux-2.6/fs/jbd/commit.c   2006-07-15 16:13:01.000000000 +0800
116 @@ -708,6 +708,32 @@ wait_for_iobuf:
117             transaction can be removed from any checkpoint list it was on
118             before. */
119  
120 +       /*
121 +        * Call any callbacks that had been registered for handles in this
122 +        * transaction.  It is up to the callback to free any allocated
123 +        * memory.
124 +        *
125 +        * Locking not strictly required, since this is the only process
126 +        * touching this transaction anymore, but is done to keep code
127 +        * checkers happy and has no contention in any case.
128 +        */
129 +       spin_lock(&commit_transaction->t_jcb_lock);
130 +       if (!list_empty(&commit_transaction->t_jcb)) {
131 +               struct list_head *p, *n;
132 +               int error = is_journal_aborted(journal);
133 +
134 +               list_for_each_safe(p, n, &commit_transaction->t_jcb) {
135 +                       struct journal_callback *jcb;
136 +
137 +                       jcb = list_entry(p, struct journal_callback, jcb_list);
138 +                       list_del_init(p);
139 +                       spin_unlock(&commit_transaction->t_jcb_lock);
140 +                       jcb->jcb_func(jcb, error);
141 +                       spin_lock(&commit_transaction->t_jcb_lock);
142 +               }
143 +       }
144 +       spin_unlock(&commit_transaction->t_jcb_lock);
145 +
146         jbd_debug(3, "JBD: commit phase 7\n");
147  
148         J_ASSERT(commit_transaction->t_sync_datalist == NULL);
149 Index: linux-2.6/fs/jbd/journal.c
150 ===================================================================
151 --- linux-2.6.orig/fs/jbd/journal.c     2006-07-15 16:08:36.000000000 +0800
152 +++ linux-2.6/fs/jbd/journal.c  2006-07-15 16:13:01.000000000 +0800
153 @@ -58,6 +58,7 @@ EXPORT_SYMBOL(journal_sync_buffer);
154  #endif
155  EXPORT_SYMBOL(journal_flush);
156  EXPORT_SYMBOL(journal_revoke);
157 +EXPORT_SYMBOL(journal_callback_set);
158  
159  EXPORT_SYMBOL(journal_init_dev);
160  EXPORT_SYMBOL(journal_init_inode);
161 @@ -80,6 +81,7 @@ EXPORT_SYMBOL(journal_wipe);
162  EXPORT_SYMBOL(journal_blocks_per_page);
163  EXPORT_SYMBOL(journal_invalidatepage);
164  EXPORT_SYMBOL(journal_try_to_free_buffers);
165 +EXPORT_SYMBOL(journal_bmap);
166  EXPORT_SYMBOL(journal_force_commit);
167  
168  static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
169 Index: linux-2.6/fs/jbd/transaction.c
170 ===================================================================
171 --- linux-2.6.orig/fs/jbd/transaction.c 2006-07-15 16:08:35.000000000 +0800
172 +++ linux-2.6/fs/jbd/transaction.c      2006-07-15 16:13:01.000000000 +0800
173 @@ -50,7 +50,9 @@ get_transaction(journal_t *journal, tran
174         transaction->t_state = T_RUNNING;
175         transaction->t_tid = journal->j_transaction_sequence++;
176         transaction->t_expires = jiffies + journal->j_commit_interval;
177 +       INIT_LIST_HEAD(&transaction->t_jcb);
178         spin_lock_init(&transaction->t_handle_lock);
179 +       spin_lock_init(&transaction->t_jcb_lock);
180  
181         /* Set up the commit timer for the new transaction. */
182         journal->j_commit_timer.expires = transaction->t_expires;
183 @@ -241,6 +243,7 @@ static handle_t *new_handle(int nblocks)
184         memset(handle, 0, sizeof(*handle));
185         handle->h_buffer_credits = nblocks;
186         handle->h_ref = 1;
187 +       INIT_LIST_HEAD(&handle->h_jcb);
188  
189         return handle;
190  }
191 @@ -1291,6 +1294,35 @@ drop:
192  }
193  
194  /**
195 + * void journal_callback_set() -  Register a callback function for this handle.
196 + * @handle: handle to attach the callback to.
197 + * @func: function to callback.
198 + * @jcb:  structure with additional information required by func() , and
199 + *        some space for jbd internal information.
200 + * 
201 + * The function will be called when the transaction that this handle is
202 + * part of has been committed to disk with the original callback data
203 + * struct and the error status of the journal as parameters.  There is no
204 + * guarantee of ordering between handles within a single transaction, nor
205 + * between callbacks registered on the same handle.
206 + *
207 + * The caller is responsible for allocating the journal_callback struct.
208 + * This is to allow the caller to add as much extra data to the callback
209 + * as needed, but reduce the overhead of multiple allocations.  The caller
210 + * allocated struct must start with a struct journal_callback at offset 0,
211 + * and has the caller-specific data afterwards.
212 + */
213 +void journal_callback_set(handle_t *handle,
214 +                       void (*func)(struct journal_callback *jcb, int error),
215 +                       struct journal_callback *jcb)
216 +{
217 +       jcb->jcb_func = func;
218 +       spin_lock(&handle->h_transaction->t_jcb_lock);
219 +       list_add_tail(&jcb->jcb_list, &handle->h_jcb);
220 +       spin_unlock(&handle->h_transaction->t_jcb_lock);
221 +}
222 +
223 +/**
224   * int journal_stop() - complete a transaction
225   * @handle: tranaction to complete.
226   * 
227 @@ -1363,6 +1396,11 @@ int journal_stop(handle_t *handle)
228                         wake_up(&journal->j_wait_transaction_locked);
229         }
230  
231 +       /* Move callbacks from the handle to the transaction. */
232 +       spin_lock(&transaction->t_jcb_lock);
233 +       list_splice(&handle->h_jcb, &transaction->t_jcb);
234 +       spin_unlock(&transaction->t_jcb_lock);
235 +
236         /*
237          * If the handle is marked SYNC, we need to set another commit
238          * going!  We also want to force a commit if the current