Whamcloud - gitweb
Branch: HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / jbd-buffer-release-2.6.7.patch
1 fix against credits leak in journal_release_buffer()
2
3 The idea is to charge a buffer at a time of modification (journal_dirty_metadata()),
4 not at a time of access (journal_get_*_access()). Each buffer has flag first call
5 journal_dirty_metadata() sets on the buffer.
6
7 Signed-off-by: Alex Tomas <alex@clusterfs.com>
8
9 Index: linux-2.6.7/include/linux/journal-head.h
10 ===================================================================
11 --- linux-2.6.7.orig/include/linux/journal-head.h       2003-06-24 18:05:26.000000000 +0400
12 +++ linux-2.6.7/include/linux/journal-head.h    2005-03-08 11:55:04.000000000 +0300
13 @@ -32,6 +32,13 @@
14         unsigned b_jlist;
15  
16         /*
17 +        * This flag signals the buffer has been modified by
18 +        * the currently running transaction
19 +        * [jbd_lock_bh_state()]
20 +        */
21 +       unsigned b_modified;
22 +
23 +       /*
24          * Copy of the buffer data frozen for writing to the log.
25          * [jbd_lock_bh_state()]
26          */
27 Index: linux-2.6.7/include/linux/ext3_jbd.h
28 ===================================================================
29 --- linux-2.6.7.orig/include/linux/ext3_jbd.h   2004-08-26 17:12:16.000000000 +0400
30 +++ linux-2.6.7/include/linux/ext3_jbd.h        2005-03-08 11:55:04.000000000 +0300
31 @@ -113,9 +113,9 @@
32  
33  static inline int
34  __ext3_journal_get_undo_access(const char *where, handle_t *handle,
35 -                               struct buffer_head *bh, int *credits)
36 +                               struct buffer_head *bh)
37  {
38 -       int err = journal_get_undo_access(handle, bh, credits);
39 +       int err = journal_get_undo_access(handle, bh);
40         if (err)
41                 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
42         return err;
43 @@ -123,19 +123,18 @@
44  
45  static inline int
46  __ext3_journal_get_write_access(const char *where, handle_t *handle,
47 -                               struct buffer_head *bh, int *credits)
48 +                               struct buffer_head *bh)
49  {
50 -       int err = journal_get_write_access(handle, bh, credits);
51 +       int err = journal_get_write_access(handle, bh);
52         if (err)
53                 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
54         return err;
55  }
56  
57  static inline void
58 -ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh,
59 -                               int credits)
60 +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
61  {
62 -       journal_release_buffer(handle, bh, credits);
63 +       journal_release_buffer(handle, bh);
64  }
65  
66  static inline void
67 @@ -175,12 +174,10 @@
68  }
69  
70  
71 -#define ext3_journal_get_undo_access(handle, bh, credits) \
72 -       __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits))
73 +#define ext3_journal_get_undo_access(handle, bh) \
74 +       __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
75  #define ext3_journal_get_write_access(handle, bh) \
76 -       __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL)
77 -#define ext3_journal_get_write_access_credits(handle, bh, credits) \
78 -       __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits))
79 +       __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
80  #define ext3_journal_revoke(handle, blocknr, bh) \
81         __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
82  #define ext3_journal_get_create_access(handle, bh) \
83 Index: linux-2.6.7/include/linux/jbd.h
84 ===================================================================
85 --- linux-2.6.7.orig/include/linux/jbd.h        2004-08-26 17:12:16.000000000 +0400
86 +++ linux-2.6.7/include/linux/jbd.h     2005-03-08 11:55:04.000000000 +0300
87 @@ -903,15 +903,12 @@
88  extern handle_t *journal_start(journal_t *, int nblocks);
89  extern int      journal_restart (handle_t *, int nblocks);
90  extern int      journal_extend (handle_t *, int nblocks);
91 -extern int      journal_get_write_access(handle_t *, struct buffer_head *,
92 -                                               int *credits);
93 +extern int      journal_get_write_access(handle_t *, struct buffer_head *);
94  extern int      journal_get_create_access (handle_t *, struct buffer_head *);
95 -extern int      journal_get_undo_access(handle_t *, struct buffer_head *,
96 -                                               int *credits);
97 +extern int      journal_get_undo_access(handle_t *, struct buffer_head *);
98  extern int      journal_dirty_data (handle_t *, struct buffer_head *);
99  extern int      journal_dirty_metadata (handle_t *, struct buffer_head *);
100 -extern void     journal_release_buffer (handle_t *, struct buffer_head *,
101 -                                               int credits);
102 +extern void     journal_release_buffer (handle_t *, struct buffer_head *);
103  extern void     journal_forget (handle_t *, struct buffer_head *);
104  extern void     journal_sync_buffer (struct buffer_head *);
105  extern int      journal_invalidatepage(journal_t *,
106 Index: linux-2.6.7/fs/jbd/transaction.c
107 ===================================================================
108 --- linux-2.6.7.orig/fs/jbd/transaction.c       2004-08-26 17:12:40.000000000 +0400
109 +++ linux-2.6.7/fs/jbd/transaction.c    2005-03-11 00:04:54.000000000 +0300
110 @@ -524,7 +524,7 @@
111   */
112  static int
113  do_get_write_access(handle_t *handle, struct journal_head *jh,
114 -                       int force_copy, int *credits) 
115 +                       int force_copy) 
116  {
117         struct buffer_head *bh;
118         transaction_t *transaction;
119 @@ -606,11 +606,6 @@
120                 JBUFFER_TRACE(jh, "has frozen data");
121                 J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
122                 jh->b_next_transaction = transaction;
123 -
124 -               J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
125 -               handle->h_buffer_credits--;
126 -               if (credits)
127 -                       (*credits)++;
128                 goto done;
129         }
130  
131 @@ -689,10 +684,6 @@
132                 jh->b_next_transaction = transaction;
133         }
134  
135 -       J_ASSERT(handle->h_buffer_credits > 0);
136 -       handle->h_buffer_credits--;
137 -       if (credits)
138 -               (*credits)++;
139  
140         /*
141          * Finally, if the buffer is not journaled right now, we need to make
142 @@ -750,8 +741,7 @@
143   * because we're write()ing a buffer which is also part of a shared mapping.
144   */
145  
146 -int journal_get_write_access(handle_t *handle,
147 -                       struct buffer_head *bh, int *credits)
148 +int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
149  {
150         struct journal_head *jh = journal_add_journal_head(bh);
151         int rc;
152 @@ -759,7 +749,7 @@
153         /* We do not want to get caught playing with fields which the
154          * log thread also manipulates.  Make sure that the buffer
155          * completes any outstanding IO before proceeding. */
156 -       rc = do_get_write_access(handle, jh, 0, credits);
157 +       rc = do_get_write_access(handle, jh, 0);
158         journal_put_journal_head(jh);
159         return rc;
160  }
161 @@ -815,9 +805,6 @@
162         J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
163         J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
164  
165 -       J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
166 -       handle->h_buffer_credits--;
167 -
168         if (jh->b_transaction == NULL) {
169                 jh->b_transaction = transaction;
170                 JBUFFER_TRACE(jh, "file as BJ_Reserved");
171 @@ -870,8 +857,7 @@
172   *
173   * Returns error number or 0 on success.
174   */
175 -int journal_get_undo_access(handle_t *handle, struct buffer_head *bh,
176 -                               int *credits)
177 +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
178  {
179         int err;
180         struct journal_head *jh = journal_add_journal_head(bh);
181 @@ -884,7 +870,7 @@
182          * make sure that obtaining the committed_data is done
183          * atomically wrt. completion of any outstanding commits.
184          */
185 -       err = do_get_write_access(handle, jh, 1, credits);
186 +       err = do_get_write_access(handle, jh, 1);
187         if (err)
188                 goto out;
189  
190 @@ -1112,6 +1098,17 @@
191  
192         jbd_lock_bh_state(bh);
193  
194 +       if (jh->b_modified == 0) {
195 +               /*
196 +                * This buffer's got modified and becoming part
197 +                * of the transaction. This needs to be done
198 +                * once a transaction -bzzz
199 +                */
200 +               jh->b_modified = 1;
201 +               J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
202 +               handle->h_buffer_credits--;
203 +       }
204 +
205         /*
206          * fastpath, to avoid expensive locking.  If this buffer is already
207          * on the running transaction's metadata list there is nothing to do.
208 @@ -1162,24 +1159,11 @@
209   * journal_release_buffer: undo a get_write_access without any buffer
210   * updates, if the update decided in the end that it didn't need access.
211   *
212 - * The caller passes in the number of credits which should be put back for
213 - * this buffer (zero or one).
214 - *
215 - * We leave the buffer attached to t_reserved_list because even though this
216 - * handle doesn't want it, some other concurrent handle may want to journal
217 - * this buffer.  If that handle is curently in between get_write_access() and
218 - * journal_dirty_metadata() then it expects the buffer to be reserved.  If
219 - * we were to rip it off t_reserved_list here, the other handle will explode
220 - * when journal_dirty_metadata is presented with a non-reserved buffer.
221 - *
222 - * If nobody really wants to journal this buffer then it will be thrown
223 - * away at the start of commit.
224   */
225  void
226 -journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
227 +journal_release_buffer(handle_t *handle, struct buffer_head *bh)
228  {
229         BUFFER_TRACE(bh, "entry");
230 -       handle->h_buffer_credits += credits;
231  }
232  
233  /** 
234 @@ -1214,6 +1198,12 @@
235                 goto not_jbd;
236         jh = bh2jh(bh);
237  
238 +       /*
239 +        * The buffer's going from the transaction, we must drop
240 +        * all references -bzzz
241 +        */
242 +       jh->b_modified = 0;
243 +
244         if (jh->b_transaction == handle->h_transaction) {
245                 J_ASSERT_JH(jh, !jh->b_frozen_data);
246  
247 @@ -2042,7 +2032,10 @@
248         __journal_unfile_buffer(jh);
249         jh->b_transaction = jh->b_next_transaction;
250         jh->b_next_transaction = NULL;
251 -       __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
252 +       if (jh->b_modified == 1)
253 +               __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
254 +       else
255 +               __journal_file_buffer(jh, jh->b_transaction, BJ_Reserved);
256         J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
257  
258         if (was_dirty)
259 Index: linux-2.6.7/fs/jbd/commit.c
260 ===================================================================
261 --- linux-2.6.7.orig/fs/jbd/commit.c    2004-08-26 17:12:40.000000000 +0400
262 +++ linux-2.6.7/fs/jbd/commit.c 2005-03-11 00:46:54.000000000 +0300
263 @@ -204,6 +204,19 @@
264         }
265  
266         /*
267 +        * First, drop modified flag: all accesses to the buffers
268 +        * will be tracked for a new trasaction only -bzzz
269 +        */
270 +       if (commit_transaction->t_buffers) {
271 +               new_jh = jh = commit_transaction->t_buffers->b_tnext;
272 +               do {
273 +                       J_ASSERT_JH(new_jh, new_jh->b_modified == 1);
274 +                       new_jh->b_modified = 0;
275 +                       new_jh = new_jh->b_tnext;
276 +               } while (new_jh != jh);
277 +       }
278 +
279 +       /*
280          * Now try to drop any written-back buffers from the journal's
281          * checkpoint lists.  We do this *before* commit because it potentially
282          * frees some memory
283 Index: linux-2.6.7/fs/ext3/balloc.c
284 ===================================================================
285 --- linux-2.6.7.orig/fs/ext3/balloc.c   2004-08-26 17:11:16.000000000 +0400
286 +++ linux-2.6.7/fs/ext3/balloc.c        2005-03-08 11:55:04.000000000 +0300
287 @@ -171,7 +171,7 @@
288          */
289         /* @@@ check errors */
290         BUFFER_TRACE(bitmap_bh, "getting undo access");
291 -       err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
292 +       err = ext3_journal_get_undo_access(handle, bitmap_bh);
293         if (err)
294                 goto error_return;
295  
296 @@ -411,7 +411,6 @@
297  {
298         int i;
299         int fatal;
300 -       int credits = 0;
301  
302         *errp = 0;
303  
304 @@ -421,7 +420,7 @@
305          * if the buffer is in BJ_Forget state in the committing transaction.
306          */
307         BUFFER_TRACE(bitmap_bh, "get undo access for new block");
308 -       fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
309 +       fatal = ext3_journal_get_undo_access(handle, bitmap_bh);
310         if (fatal) {
311                 *errp = fatal;
312                 goto fail;
313 @@ -460,7 +459,7 @@
314  
315  fail_access:
316         BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
317 -       ext3_journal_release_buffer(handle, bitmap_bh, credits);
318 +       ext3_journal_release_buffer(handle, bitmap_bh);
319  fail:
320         return -1;
321  }
322 Index: linux-2.6.7/fs/ext3/ialloc.c
323 ===================================================================
324 --- linux-2.6.7.orig/fs/ext3/ialloc.c   2004-08-26 17:11:31.000000000 +0400
325 +++ linux-2.6.7/fs/ext3/ialloc.c        2005-03-08 11:55:04.000000000 +0300
326 @@ -475,11 +475,9 @@
327                 ino = ext3_find_next_zero_bit((unsigned long *)
328                                 bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino);
329                 if (ino < EXT3_INODES_PER_GROUP(sb)) {
330 -                       int credits = 0;
331  
332                         BUFFER_TRACE(bitmap_bh, "get_write_access");
333 -                       err = ext3_journal_get_write_access_credits(handle,
334 -                                                       bitmap_bh, &credits);
335 +                       err = ext3_journal_get_write_access(handle, bitmap_bh);
336                         if (err)
337                                 goto fail;
338  
339 @@ -495,7 +493,7 @@
340                                 goto got;
341                         }
342                         /* we lost it */
343 -                       journal_release_buffer(handle, bitmap_bh, credits);
344 +                       journal_release_buffer(handle, bitmap_bh);
345  
346                         if (++ino < EXT3_INODES_PER_GROUP(sb))
347                                 goto repeat_in_this_group;
348 Index: linux-2.6.7/fs/ext3/xattr.c
349 ===================================================================
350 --- linux-2.6.7.orig/fs/ext3/xattr.c    2004-08-26 17:10:37.000000000 +0400
351 +++ linux-2.6.7/fs/ext3/xattr.c 2005-03-08 11:55:04.000000000 +0300
352 @@ -607,8 +607,7 @@
353                         goto skip_get_write_access;
354                 /* ext3_journal_get_write_access() requires an unlocked bh,
355                    which complicates things here. */
356 -               error = ext3_journal_get_write_access_credits(handle, bh,
357 -                                                             &credits);
358 +               error = ext3_journal_get_write_access(handle, bh);
359                 if (error)
360                         goto cleanup;
361                 lock_buffer(bh);
362 @@ -620,7 +619,7 @@
363                         int offset;
364  
365                         unlock_buffer(bh);
366 -                       journal_release_buffer(handle, bh, credits);
367 +                       journal_release_buffer(handle, bh);
368                 skip_get_write_access:
369                         ea_bdebug(bh, "cloning");
370                         header = kmalloc(bh->b_size, GFP_KERNEL);
371 @@ -764,8 +763,7 @@
372                                 error = -EDQUOT;
373                                 if (DQUOT_ALLOC_BLOCK(inode, 1)) {
374                                         unlock_buffer(new_bh);
375 -                                       journal_release_buffer(handle, new_bh,
376 -                                                              credits);
377 +                                       journal_release_buffer(handle, new_bh);
378                                         goto cleanup;
379                                 }
380                                 HDR(new_bh)->h_refcount = cpu_to_le32(1 +
381 @@ -1057,8 +1055,7 @@
382                         ext3_error(inode->i_sb, "ext3_xattr_cache_find",
383                                 "inode %ld: block %ld read error",
384                                 inode->i_ino, (unsigned long) ce->e_block);
385 -               } else if (ext3_journal_get_write_access_credits(
386 -                               handle, bh, credits) == 0) {
387 +               } else if (ext3_journal_get_write_access(handle, bh) == 0) {
388                         /* ext3_journal_get_write_access() requires an unlocked
389                          * bh, which complicates things here. */
390                         lock_buffer(bh);
391 @@ -1074,7 +1071,7 @@
392                                 return bh;
393                         }
394                         unlock_buffer(bh);
395 -                       journal_release_buffer(handle, bh, *credits);
396 +                       journal_release_buffer(handle, bh);
397                         *credits = 0;
398                         brelse(bh);
399                 }