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.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
17 + * This flag signals the buffer has been modified by
18 + * the currently running transaction
19 + * [jbd_lock_bh_state()]
21 + unsigned b_modified;
24 * Copy of the buffer data frozen for writing to the log.
25 * [jbd_lock_bh_state()]
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
34 __ext3_journal_get_undo_access(const char *where, handle_t *handle,
35 - struct buffer_head *bh, int *credits)
36 + struct buffer_head *bh)
38 - int err = journal_get_undo_access(handle, bh, credits);
39 + int err = journal_get_undo_access(handle, bh);
41 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
46 __ext3_journal_get_write_access(const char *where, handle_t *handle,
47 - struct buffer_head *bh, int *credits)
48 + struct buffer_head *bh)
50 - int err = journal_get_write_access(handle, bh, credits);
51 + int err = journal_get_write_access(handle, bh);
53 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
58 -ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh,
60 +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
62 - journal_release_buffer(handle, bh, credits);
63 + journal_release_buffer(handle, bh);
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
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 *,
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 *,
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 *,
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
113 do_get_write_access(handle_t *handle, struct journal_head *jh,
114 - int force_copy, int *credits)
117 struct buffer_head *bh;
118 transaction_t *transaction;
120 JBUFFER_TRACE(jh, "has frozen data");
121 J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
122 jh->b_next_transaction = transaction;
124 - J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
125 - handle->h_buffer_credits--;
132 jh->b_next_transaction = transaction;
135 - J_ASSERT(handle->h_buffer_credits > 0);
136 - handle->h_buffer_credits--;
141 * Finally, if the buffer is not journaled right now, we need to make
143 * because we're write()ing a buffer which is also part of a shared mapping.
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)
150 struct journal_head *jh = journal_add_journal_head(bh);
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);
162 J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
163 J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
165 - J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
166 - handle->h_buffer_credits--;
168 if (jh->b_transaction == NULL) {
169 jh->b_transaction = transaction;
170 JBUFFER_TRACE(jh, "file as BJ_Reserved");
173 * Returns error number or 0 on success.
175 -int journal_get_undo_access(handle_t *handle, struct buffer_head *bh,
177 +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
180 struct journal_head *jh = journal_add_journal_head(bh);
182 * make sure that obtaining the committed_data is done
183 * atomically wrt. completion of any outstanding commits.
185 - err = do_get_write_access(handle, jh, 1, credits);
186 + err = do_get_write_access(handle, jh, 1);
190 @@ -1112,6 +1098,17 @@
192 jbd_lock_bh_state(bh);
194 + if (jh->b_modified == 0) {
196 + * This buffer's got modified and becoming part
197 + * of the transaction. This needs to be done
198 + * once a transaction -bzzz
200 + jh->b_modified = 1;
201 + J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
202 + handle->h_buffer_credits--;
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.
212 - * The caller passes in the number of credits which should be put back for
213 - * this buffer (zero or one).
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.
222 - * If nobody really wants to journal this buffer then it will be thrown
223 - * away at the start of commit.
226 -journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
227 +journal_release_buffer(handle_t *handle, struct buffer_head *bh)
229 BUFFER_TRACE(bh, "entry");
230 - handle->h_buffer_credits += credits;
234 @@ -1214,6 +1198,12 @@
239 + * The buffer's going from the transaction, we must drop
240 + * all references -bzzz
242 + jh->b_modified = 0;
244 if (jh->b_transaction == handle->h_transaction) {
245 J_ASSERT_JH(jh, !jh->b_frozen_data);
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);
255 + __journal_file_buffer(jh, jh->b_transaction, BJ_Reserved);
256 J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
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
267 + * First, drop modified flag: all accesses to the buffers
268 + * will be tracked for a new trasaction only -bzzz
270 + if (commit_transaction->t_buffers) {
271 + new_jh = jh = commit_transaction->t_buffers->b_tnext;
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);
280 * Now try to drop any written-back buffers from the journal's
281 * checkpoint lists. We do this *before* commit because it potentially
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
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);
305 * if the buffer is in BJ_Forget state in the committing transaction.
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);
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);
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
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)) {
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);
343 - journal_release_buffer(handle, bitmap_bh, credits);
344 + journal_release_buffer(handle, bitmap_bh);
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
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,
358 + error = ext3_journal_get_write_access(handle, 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);
373 if (DQUOT_ALLOC_BLOCK(inode, 1)) {
374 unlock_buffer(new_bh);
375 - journal_release_buffer(handle, new_bh,
377 + journal_release_buffer(handle, new_bh);
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. */
391 @@ -1074,7 +1071,7 @@
395 - journal_release_buffer(handle, bh, *credits);
396 + journal_release_buffer(handle, bh);