1 fix against credits leak in journal_release_buffer()
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.
7 Signed-off-by: Alex Tomas <alex@clusterfs.com>
9 Index: linux-2.6.10/fs/ext3/ialloc.c
10 ===================================================================
11 --- linux-2.6.10.orig/fs/ext3/ialloc.c 2004-12-25 05:34:45.000000000 +0800
12 +++ linux-2.6.10/fs/ext3/ialloc.c 2005-03-31 18:11:10.672236448 +0800
14 ino = ext3_find_next_zero_bit((unsigned long *)
15 bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino);
16 if (ino < EXT3_INODES_PER_GROUP(sb)) {
19 BUFFER_TRACE(bitmap_bh, "get_write_access");
20 - err = ext3_journal_get_write_access_credits(handle,
21 - bitmap_bh, &credits);
22 + err = ext3_journal_get_write_access(handle, bitmap_bh);
30 - journal_release_buffer(handle, bitmap_bh, credits);
31 + journal_release_buffer(handle, bitmap_bh);
33 if (++ino < EXT3_INODES_PER_GROUP(sb))
34 goto repeat_in_this_group;
35 Index: linux-2.6.10/fs/ext3/xattr.c
36 ===================================================================
37 --- linux-2.6.10.orig/fs/ext3/xattr.c 2005-03-31 15:35:26.000000000 +0800
38 +++ linux-2.6.10/fs/ext3/xattr.c 2005-03-31 18:11:10.675235992 +0800
40 goto skip_get_write_access;
41 /* ext3_journal_get_write_access() requires an unlocked bh,
42 which complicates things here. */
43 - error = ext3_journal_get_write_access_credits(handle, bh,
45 + error = ext3_journal_get_write_access(handle, bh);
48 ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev,
51 mb_cache_entry_release(ce);
53 - journal_release_buffer(handle, bh, credits);
54 + journal_release_buffer(handle, bh);
55 skip_get_write_access:
56 ea_bdebug(bh, "cloning");
57 header = kmalloc(bh->b_size, GFP_KERNEL);
60 if (DQUOT_ALLOC_BLOCK(inode, 1)) {
61 unlock_buffer(new_bh);
62 - journal_release_buffer(handle, new_bh,
64 + journal_release_buffer(handle, new_bh);
67 HDR(new_bh)->h_refcount = cpu_to_le32(1 +
69 ext3_error(inode->i_sb, "ext3_xattr_cache_find",
70 "inode %ld: block %ld read error",
71 inode->i_ino, (unsigned long) ce->e_block);
72 - } else if (ext3_journal_get_write_access_credits(
73 - handle, bh, credits) == 0) {
74 + } else if (ext3_journal_get_write_access(handle, bh) == 0) {
75 /* ext3_journal_get_write_access() requires an unlocked
76 * bh, which complicates things here. */
82 - journal_release_buffer(handle, bh, *credits);
83 + journal_release_buffer(handle, bh);
87 Index: linux-2.6.10/fs/ext3/balloc.c
88 ===================================================================
89 --- linux-2.6.10.orig/fs/ext3/balloc.c 2004-12-25 05:33:50.000000000 +0800
90 +++ linux-2.6.10/fs/ext3/balloc.c 2005-03-31 18:14:05.705627328 +0800
93 /* @@@ check errors */
94 BUFFER_TRACE(bitmap_bh, "getting undo access");
95 - err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
96 + err = ext3_journal_get_undo_access(handle, bitmap_bh);
101 unsigned long group_first_block;
109 * if the buffer is in BJ_Forget state in the committing transaction.
111 BUFFER_TRACE(bitmap_bh, "get undo access for new block");
112 - fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
113 + fatal = ext3_journal_get_undo_access(handle, bitmap_bh);
117 @@ -1087,7 +1086,7 @@
120 BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
121 - ext3_journal_release_buffer(handle, bitmap_bh, credits);
122 + ext3_journal_release_buffer(handle, bitmap_bh);
126 Index: linux-2.6.10/fs/jbd/commit.c
127 ===================================================================
128 --- linux-2.6.10.orig/fs/jbd/commit.c 2004-12-25 05:35:27.000000000 +0800
129 +++ linux-2.6.10/fs/jbd/commit.c 2005-03-31 18:11:10.668237056 +0800
134 + * First, drop modified flag: all accesses to the buffers
135 + * will be tracked for a new trasaction only -bzzz
137 + if (commit_transaction->t_buffers) {
138 + new_jh = jh = commit_transaction->t_buffers->b_tnext;
140 + J_ASSERT_JH(new_jh, new_jh->b_modified == 1);
141 + new_jh->b_modified = 0;
142 + new_jh = new_jh->b_tnext;
143 + } while (new_jh != jh);
147 * Now try to drop any written-back buffers from the journal's
148 * checkpoint lists. We do this *before* commit because it potentially
150 Index: linux-2.6.10/fs/jbd/transaction.c
151 ===================================================================
152 --- linux-2.6.10.orig/fs/jbd/transaction.c 2005-03-31 15:35:26.000000000 +0800
153 +++ linux-2.6.10/fs/jbd/transaction.c 2005-03-31 18:11:10.666237360 +0800
157 do_get_write_access(handle_t *handle, struct journal_head *jh,
158 - int force_copy, int *credits)
161 struct buffer_head *bh;
162 transaction_t *transaction;
164 JBUFFER_TRACE(jh, "has frozen data");
165 J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
166 jh->b_next_transaction = transaction;
168 - J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
169 - handle->h_buffer_credits--;
176 jh->b_next_transaction = transaction;
179 - J_ASSERT(handle->h_buffer_credits > 0);
180 - handle->h_buffer_credits--;
185 * Finally, if the buffer is not journaled right now, we need to make
187 * because we're write()ing a buffer which is also part of a shared mapping.
190 -int journal_get_write_access(handle_t *handle,
191 - struct buffer_head *bh, int *credits)
192 +int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
194 struct journal_head *jh = journal_add_journal_head(bh);
197 /* We do not want to get caught playing with fields which the
198 * log thread also manipulates. Make sure that the buffer
199 * completes any outstanding IO before proceeding. */
200 - rc = do_get_write_access(handle, jh, 0, credits);
201 + rc = do_get_write_access(handle, jh, 0);
202 journal_put_journal_head(jh);
206 J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
207 J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
209 - J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
210 - handle->h_buffer_credits--;
212 if (jh->b_transaction == NULL) {
213 jh->b_transaction = transaction;
214 JBUFFER_TRACE(jh, "file as BJ_Reserved");
217 * Returns error number or 0 on success.
219 -int journal_get_undo_access(handle_t *handle, struct buffer_head *bh,
221 +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
224 struct journal_head *jh = journal_add_journal_head(bh);
226 * make sure that obtaining the committed_data is done
227 * atomically wrt. completion of any outstanding commits.
229 - err = do_get_write_access(handle, jh, 1, credits);
230 + err = do_get_write_access(handle, jh, 1);
234 @@ -1111,6 +1097,17 @@
236 jbd_lock_bh_state(bh);
238 + if (jh->b_modified == 0) {
240 + * This buffer's got modified and becoming part
241 + * of the transaction. This needs to be done
242 + * once a transaction -bzzz
244 + jh->b_modified = 1;
245 + J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
246 + handle->h_buffer_credits--;
250 * fastpath, to avoid expensive locking. If this buffer is already
251 * on the running transaction's metadata list there is nothing to do.
252 @@ -1161,24 +1158,11 @@
253 * journal_release_buffer: undo a get_write_access without any buffer
254 * updates, if the update decided in the end that it didn't need access.
256 - * The caller passes in the number of credits which should be put back for
257 - * this buffer (zero or one).
259 - * We leave the buffer attached to t_reserved_list because even though this
260 - * handle doesn't want it, some other concurrent handle may want to journal
261 - * this buffer. If that handle is curently in between get_write_access() and
262 - * journal_dirty_metadata() then it expects the buffer to be reserved. If
263 - * we were to rip it off t_reserved_list here, the other handle will explode
264 - * when journal_dirty_metadata is presented with a non-reserved buffer.
266 - * If nobody really wants to journal this buffer then it will be thrown
267 - * away at the start of commit.
270 -journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
271 +journal_release_buffer(handle_t *handle, struct buffer_head *bh)
273 BUFFER_TRACE(bh, "entry");
274 - handle->h_buffer_credits += credits;
278 @@ -1222,6 +1206,12 @@
283 + * The buffer's going from the transaction, we must drop
284 + * all references -bzzz
286 + jh->b_modified = 0;
288 if (jh->b_transaction == handle->h_transaction) {
289 J_ASSERT_JH(jh, !jh->b_frozen_data);
291 @@ -2015,7 +2005,10 @@
292 __journal_unfile_buffer(jh);
293 jh->b_transaction = jh->b_next_transaction;
294 jh->b_next_transaction = NULL;
295 - __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
296 + if (jh->b_modified == 1)
297 + __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
299 + __journal_file_buffer(jh, jh->b_transaction, BJ_Reserved);
300 J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
303 Index: linux-2.6.10/include/linux/journal-head.h
304 ===================================================================
305 --- linux-2.6.10.orig/include/linux/journal-head.h 2004-12-25 05:35:28.000000000 +0800
306 +++ linux-2.6.10/include/linux/journal-head.h 2005-03-31 18:11:10.658238576 +0800
311 + * This flag signals the buffer has been modified by
312 + * the currently running transaction
313 + * [jbd_lock_bh_state()]
315 + unsigned b_modified;
318 * Copy of the buffer data frozen for writing to the log.
319 * [jbd_lock_bh_state()]
321 Index: linux-2.6.10/include/linux/jbd.h
322 ===================================================================
323 --- linux-2.6.10.orig/include/linux/jbd.h 2005-03-31 15:35:26.000000000 +0800
324 +++ linux-2.6.10/include/linux/jbd.h 2005-03-31 18:12:52.504755552 +0800
325 @@ -867,15 +867,12 @@
326 extern handle_t *journal_start(journal_t *, int nblocks);
327 extern int journal_restart (handle_t *, int nblocks);
328 extern int journal_extend (handle_t *, int nblocks);
329 -extern int journal_get_write_access(handle_t *, struct buffer_head *,
331 +extern int journal_get_write_access(handle_t *, struct buffer_head *);
332 extern int journal_get_create_access (handle_t *, struct buffer_head *);
333 -extern int journal_get_undo_access(handle_t *, struct buffer_head *,
335 +extern int journal_get_undo_access(handle_t *, struct buffer_head *);
336 extern int journal_dirty_data (handle_t *, struct buffer_head *);
337 extern int journal_dirty_metadata (handle_t *, struct buffer_head *);
338 -extern void journal_release_buffer (handle_t *, struct buffer_head *,
340 +extern void journal_release_buffer (handle_t *, struct buffer_head *);
341 extern int journal_forget (handle_t *, struct buffer_head *);
342 extern void journal_sync_buffer (struct buffer_head *);
343 extern int journal_invalidatepage(journal_t *,
344 Index: linux-2.6.10/include/linux/ext3_jbd.h
345 ===================================================================
346 --- linux-2.6.10.orig/include/linux/ext3_jbd.h 2005-03-31 15:35:26.000000000 +0800
347 +++ linux-2.6.10/include/linux/ext3_jbd.h 2005-03-31 18:11:10.660238272 +0800
351 __ext3_journal_get_undo_access(const char *where, handle_t *handle,
352 - struct buffer_head *bh, int *credits)
353 + struct buffer_head *bh)
355 - int err = journal_get_undo_access(handle, bh, credits);
356 + int err = journal_get_undo_access(handle, bh);
358 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
360 @@ -123,19 +123,18 @@
363 __ext3_journal_get_write_access(const char *where, handle_t *handle,
364 - struct buffer_head *bh, int *credits)
365 + struct buffer_head *bh)
367 - int err = journal_get_write_access(handle, bh, credits);
368 + int err = journal_get_write_access(handle, bh);
370 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
375 -ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh,
377 +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
379 - journal_release_buffer(handle, bh, credits);
380 + journal_release_buffer(handle, bh);
384 @@ -178,12 +177,10 @@
388 -#define ext3_journal_get_undo_access(handle, bh, credits) \
389 - __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits))
390 +#define ext3_journal_get_undo_access(handle, bh) \
391 + __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
392 #define ext3_journal_get_write_access(handle, bh) \
393 - __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL)
394 -#define ext3_journal_get_write_access_credits(handle, bh, credits) \
395 - __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits))
396 + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
397 #define ext3_journal_revoke(handle, blocknr, bh) \
398 __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
399 #define ext3_journal_get_create_access(handle, bh) \