]>
Commit | Line | Data |
---|---|---|
23b17db7 JR |
1 | Index: fs/buffer.c |
2 | =================================================================== | |
3 | RCS file: /cvsroot/gkernel/ext3/fs/buffer.c,v | |
4 | retrieving revision 1.8.2.16.2.11 | |
5 | retrieving revision 1.36.2.22 | |
6 | diff -u -r1.8.2.16.2.11 -r1.36.2.22 | |
7 | --- fs/buffer.c 9 May 2002 15:54:51 -0000 1.8.2.16.2.11 | |
8 | +++ fs/buffer.c 9 May 2002 16:10:09 -0000 1.36.2.22 | |
9 | @@ -1746,9 +1746,14 @@ | |
10 | } | |
11 | ||
12 | /* Stage 3: start the IO */ | |
13 | - for (i = 0; i < nr; i++) | |
14 | - submit_bh(READ, arr[i]); | |
15 | - | |
16 | + for (i = 0; i < nr; i++) { | |
17 | + struct buffer_head * bh = arr[i]; | |
18 | + if (buffer_uptodate(bh)) | |
19 | + end_buffer_io_async(bh, 1); | |
20 | + else | |
21 | + submit_bh(READ, bh); | |
22 | + } | |
23 | + | |
24 | return 0; | |
25 | } | |
26 | ||
27 | Index: fs/ext3/file.c | |
28 | =================================================================== | |
29 | RCS file: /cvsroot/gkernel/ext3/fs/ext3/file.c,v | |
30 | retrieving revision 1.11.2.3 | |
31 | retrieving revision 1.27.2.3 | |
32 | diff -u -r1.11.2.3 -r1.27.2.3 | |
33 | --- fs/ext3/file.c 16 Nov 2001 14:35:14 -0000 1.11.2.3 | |
34 | +++ fs/ext3/file.c 14 May 2002 15:14:27 -0000 1.27.2.3 | |
35 | @@ -61,19 +61,53 @@ | |
36 | static ssize_t | |
37 | ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) | |
38 | { | |
39 | + int ret, err; | |
40 | struct inode *inode = file->f_dentry->d_inode; | |
41 | + extern kdev_t TRACE_DEV; | |
42 | ||
43 | - /* | |
44 | - * Nasty: if the file is subject to synchronous writes then we need | |
45 | - * to force generic_osync_inode() to call ext3_write_inode(). | |
46 | - * We do that by marking the inode dirty. This adds much more | |
47 | - * computational expense than we need, but we're going to sync | |
48 | - * anyway. | |
49 | - */ | |
50 | - if (IS_SYNC(inode) || (file->f_flags & O_SYNC)) | |
51 | - mark_inode_dirty(inode); | |
52 | + ret = generic_file_write(file, buf, count, ppos); | |
53 | ||
54 | - return generic_file_write(file, buf, count, ppos); | |
55 | + /* Skip file flushing code if there was an error, or if nothing | |
56 | + was written. */ | |
57 | + if (ret <= 0) | |
58 | + return ret; | |
59 | + | |
60 | + /* If the inode is IS_SYNC, or is O_SYNC and we are doing | |
61 | + data-journaling, then we need to make sure that we force the | |
62 | + transaction to disk to keep all metadata uptodate | |
63 | + synchronously. */ | |
64 | + | |
65 | + if (file->f_flags & O_SYNC) { | |
66 | + /* If we are non-data-journaled, then the dirty data has | |
67 | + already been flushed to backing store by | |
68 | + generic_osync_inode, and the inode has been flushed | |
69 | + too if there have been any modifications other than | |
70 | + mere timestamp updates. | |
71 | + | |
72 | + Open question --- do we care about flushing | |
73 | + timestamps too if the inode is IS_SYNC? */ | |
74 | + if (!ext3_should_journal_data(inode)) | |
75 | + return ret; | |
76 | + | |
77 | + goto force_commit; | |
78 | + } | |
79 | + | |
80 | + /* So we know that there has been no forced data flush. If the | |
81 | + inode is marked IS_SYNC, we need to force one ourselves. */ | |
82 | + if (!IS_SYNC(inode)) | |
83 | + return ret; | |
84 | + | |
85 | + /* Open question #2 --- should we force data to disk here too? | |
86 | + If we don't, the only impact is that data=writeback | |
87 | + filesystems won't flush data to disk automatically on | |
88 | + IS_SYNC, only metadata (but historically, that is what ext2 | |
89 | + has done.) */ | |
90 | + | |
91 | +force_commit: | |
92 | + err = ext3_force_commit(inode->i_sb); | |
93 | + if (err) | |
94 | + return err; | |
95 | + return ret; | |
96 | } | |
97 | ||
98 | struct file_operations ext3_file_operations = { | |
99 | Index: fs/ext3/fsync.c | |
100 | =================================================================== | |
101 | RCS file: /cvsroot/gkernel/ext3/fs/ext3/fsync.c,v | |
102 | retrieving revision 1.2.2.3 | |
103 | retrieving revision 1.7.2.2 | |
104 | diff -u -r1.2.2.3 -r1.7.2.2 | |
105 | --- fs/ext3/fsync.c 21 Nov 2001 07:49:08 -0000 1.2.2.3 | |
106 | +++ fs/ext3/fsync.c 10 Apr 2002 17:00:50 -0000 1.7.2.2 | |
107 | @@ -62,7 +62,12 @@ | |
108 | * we'll end up waiting on them in commit. | |
109 | */ | |
110 | ret = fsync_inode_buffers(inode); | |
111 | - ret |= fsync_inode_data_buffers(inode); | |
112 | + | |
113 | + /* In writeback node, we need to force out data buffers too. In | |
114 | + * the other modes, ext3_force_commit takes care of forcing out | |
115 | + * just the right data blocks. */ | |
116 | + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) | |
117 | + ret |= fsync_inode_data_buffers(inode); | |
118 | ||
119 | ext3_force_commit(inode->i_sb); | |
120 | ||
121 | Index: fs/ext3/ialloc.c | |
122 | =================================================================== | |
123 | RCS file: /cvsroot/gkernel/ext3/fs/ext3/ialloc.c,v | |
124 | retrieving revision 1.5.2.4 | |
125 | retrieving revision 1.19.4.5 | |
126 | diff -u -r1.5.2.4 -r1.19.4.5 | |
127 | --- fs/ext3/ialloc.c 13 Mar 2002 11:53:43 -0000 1.5.2.4 | |
128 | +++ fs/ext3/ialloc.c 10 Apr 2002 17:02:19 -0000 1.19.4.5 | |
129 | @@ -392,7 +392,7 @@ | |
130 | ||
131 | err = -ENOSPC; | |
132 | if (!gdp) | |
133 | - goto fail; | |
134 | + goto out; | |
135 | ||
136 | err = -EIO; | |
137 | bitmap_nr = load_inode_bitmap (sb, i); | |
138 | @@ -523,9 +523,10 @@ | |
139 | return inode; | |
140 | ||
141 | fail: | |
142 | + ext3_std_error(sb, err); | |
143 | +out: | |
144 | unlock_super(sb); | |
145 | iput(inode); | |
146 | - ext3_std_error(sb, err); | |
147 | return ERR_PTR(err); | |
148 | } | |
149 | ||
150 | Index: fs/ext3/inode.c | |
151 | =================================================================== | |
152 | RCS file: /cvsroot/gkernel/ext3/fs/ext3/inode.c,v | |
153 | retrieving revision 1.12.2.6 | |
154 | retrieving revision 1.64.2.22 | |
155 | diff -u -r1.12.2.6 -r1.64.2.22 | |
156 | --- fs/ext3/inode.c 9 May 2002 15:54:51 -0000 1.12.2.6 | |
157 | +++ fs/ext3/inode.c 13 May 2002 17:10:02 -0000 1.64.2.22 | |
158 | @@ -412,6 +412,7 @@ | |
159 | return NULL; | |
160 | ||
161 | changed: | |
162 | + brelse(bh); | |
163 | *err = -EAGAIN; | |
164 | goto no_block; | |
165 | failure: | |
166 | @@ -948,11 +949,13 @@ | |
167 | } | |
168 | ||
169 | static int walk_page_buffers( handle_t *handle, | |
170 | + struct inode *inode, | |
171 | struct buffer_head *head, | |
172 | unsigned from, | |
173 | unsigned to, | |
174 | int *partial, | |
175 | int (*fn)( handle_t *handle, | |
176 | + struct inode *inode, | |
177 | struct buffer_head *bh)) | |
178 | { | |
179 | struct buffer_head *bh; | |
180 | @@ -970,7 +973,7 @@ | |
181 | *partial = 1; | |
182 | continue; | |
183 | } | |
184 | - err = (*fn)(handle, bh); | |
185 | + err = (*fn)(handle, inode, bh); | |
186 | if (!ret) | |
187 | ret = err; | |
188 | } | |
189 | @@ -1003,7 +1006,7 @@ | |
190 | * write. | |
191 | */ | |
192 | ||
193 | -static int do_journal_get_write_access(handle_t *handle, | |
194 | +static int do_journal_get_write_access(handle_t *handle, struct inode *inode, | |
195 | struct buffer_head *bh) | |
196 | { | |
197 | return ext3_journal_get_write_access(handle, bh); | |
198 | @@ -1029,7 +1032,7 @@ | |
199 | goto prepare_write_failed; | |
200 | ||
201 | if (ext3_should_journal_data(inode)) { | |
202 | - ret = walk_page_buffers(handle, page->buffers, | |
203 | + ret = walk_page_buffers(handle, inode, page->buffers, | |
204 | from, to, NULL, do_journal_get_write_access); | |
205 | if (ret) { | |
206 | /* | |
207 | @@ -1050,24 +1053,32 @@ | |
208 | return ret; | |
209 | } | |
210 | ||
211 | -static int journal_dirty_sync_data(handle_t *handle, struct buffer_head *bh) | |
212 | +static int journal_dirty_sync_data(handle_t *handle, struct inode *inode, | |
213 | + struct buffer_head *bh) | |
214 | { | |
215 | - return ext3_journal_dirty_data(handle, bh, 0); | |
216 | + int ret = ext3_journal_dirty_data(handle, bh, 0); | |
217 | + if (bh->b_inode != inode) | |
218 | + buffer_insert_inode_data_queue(bh, inode); | |
219 | + return ret; | |
220 | } | |
221 | ||
222 | /* | |
223 | * For ext3_writepage(). We also brelse() the buffer to account for | |
224 | * the bget() which ext3_writepage() performs. | |
225 | */ | |
226 | -static int journal_dirty_async_data(handle_t *handle, struct buffer_head *bh) | |
227 | +static int journal_dirty_async_data(handle_t *handle, struct inode *inode, | |
228 | + struct buffer_head *bh) | |
229 | { | |
230 | int ret = ext3_journal_dirty_data(handle, bh, 1); | |
231 | + if (bh->b_inode != inode) | |
232 | + buffer_insert_inode_data_queue(bh, inode); | |
233 | __brelse(bh); | |
234 | return ret; | |
235 | } | |
236 | ||
237 | /* For commit_write() in data=journal mode */ | |
238 | -static int commit_write_fn(handle_t *handle, struct buffer_head *bh) | |
239 | +static int commit_write_fn(handle_t *handle, struct inode *inode, | |
240 | + struct buffer_head *bh) | |
241 | { | |
242 | set_bit(BH_Uptodate, &bh->b_state); | |
243 | return ext3_journal_dirty_metadata(handle, bh); | |
244 | @@ -1102,7 +1113,7 @@ | |
245 | int partial = 0; | |
246 | loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | |
247 | ||
248 | - ret = walk_page_buffers(handle, page->buffers, | |
249 | + ret = walk_page_buffers(handle, inode, page->buffers, | |
250 | from, to, &partial, commit_write_fn); | |
251 | if (!partial) | |
252 | SetPageUptodate(page); | |
253 | @@ -1112,7 +1123,7 @@ | |
254 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; | |
255 | } else { | |
256 | if (ext3_should_order_data(inode)) { | |
257 | - ret = walk_page_buffers(handle, page->buffers, | |
258 | + ret = walk_page_buffers(handle, inode, page->buffers, | |
259 | from, to, NULL, journal_dirty_sync_data); | |
260 | } | |
261 | /* Be careful here if generic_commit_write becomes a | |
262 | @@ -1194,7 +1205,8 @@ | |
263 | return generic_block_bmap(mapping,block,ext3_get_block); | |
264 | } | |
265 | ||
266 | -static int bget_one(handle_t *handle, struct buffer_head *bh) | |
267 | +static int bget_one(handle_t *handle, struct inode *inode, | |
268 | + struct buffer_head *bh) | |
269 | { | |
270 | atomic_inc(&bh->b_count); | |
271 | return 0; | |
272 | @@ -1293,7 +1305,7 @@ | |
273 | create_empty_buffers(page, | |
274 | inode->i_dev, inode->i_sb->s_blocksize); | |
275 | page_buffers = page->buffers; | |
276 | - walk_page_buffers(handle, page_buffers, 0, | |
277 | + walk_page_buffers(handle, inode, page_buffers, 0, | |
278 | PAGE_CACHE_SIZE, NULL, bget_one); | |
279 | } | |
280 | ||
281 | @@ -1311,7 +1323,7 @@ | |
282 | ||
283 | /* And attach them to the current transaction */ | |
284 | if (order_data) { | |
285 | - err = walk_page_buffers(handle, page_buffers, | |
286 | + err = walk_page_buffers(handle, inode, page_buffers, | |
287 | 0, PAGE_CACHE_SIZE, NULL, journal_dirty_async_data); | |
288 | if (!ret) | |
289 | ret = err; | |
290 | Index: fs/ext3/super.c | |
291 | =================================================================== | |
292 | RCS file: /cvsroot/gkernel/ext3/fs/ext3/super.c,v | |
293 | retrieving revision 1.12.2.5 | |
294 | retrieving revision 1.34.2.21 | |
295 | diff -u -r1.12.2.5 -r1.34.2.21 | |
296 | --- fs/ext3/super.c 13 Mar 2002 11:53:43 -0000 1.12.2.5 | |
297 | +++ fs/ext3/super.c 15 Apr 2002 20:34:54 -0000 1.34.2.21 | |
298 | @@ -1589,8 +1589,10 @@ | |
299 | journal_t *journal = EXT3_SB(sb)->s_journal; | |
300 | ||
301 | /* Now we set up the journal barrier. */ | |
302 | + unlock_super(sb); | |
303 | journal_lock_updates(journal); | |
304 | journal_flush(journal); | |
305 | + lock_super(sb); | |
306 | ||
307 | /* Journal blocked and flushed, clear needs_recovery flag. */ | |
308 | EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); | |
309 | Index: fs/jbd/journal.c | |
310 | =================================================================== | |
311 | RCS file: /cvsroot/gkernel/ext3/fs/jbd/journal.c,v | |
312 | retrieving revision 1.11.2.5 | |
313 | retrieving revision 1.49.2.11 | |
314 | diff -u -r1.11.2.5 -r1.49.2.11 | |
315 | --- fs/jbd/journal.c 9 Apr 2002 17:30:41 -0000 1.11.2.5 | |
316 | +++ fs/jbd/journal.c 9 May 2002 15:05:59 -0000 1.49.2.11 | |
317 | @@ -1488,6 +1488,49 @@ | |
318 | unlock_journal(journal); | |
319 | } | |
320 | ||
321 | + | |
322 | +/* | |
323 | + * Report any unexpected dirty buffers which turn up. Normally those | |
324 | + * indicate an error, but they can occur if the user is running (say) | |
325 | + * tune2fs to modify the live filesystem, so we need the option of | |
326 | + * continuing as gracefully as possible. # | |
327 | + * | |
328 | + * The caller should already hold the journal lock and | |
329 | + * journal_datalist_lock spinlock: most callers will need those anyway | |
330 | + * in order to probe the buffer's journaling state safely. | |
331 | + */ | |
332 | +void __jbd_unexpected_dirty_buffer(char *function, int line, | |
333 | + struct journal_head *jh) | |
334 | +{ | |
335 | + struct buffer_head *bh = jh2bh(jh); | |
336 | + int jlist; | |
337 | + | |
338 | + if (buffer_dirty(bh)) { | |
339 | + printk ("%sUnexpected dirty buffer encountered at " | |
340 | + "%s:%d (%s blocknr %lu)\n", | |
341 | + KERN_WARNING, function, line, | |
342 | + kdevname(bh->b_dev), bh->b_blocknr); | |
343 | +#ifdef JBD_PARANOID_WRITES | |
344 | + J_ASSERT (!buffer_dirty(bh)); | |
345 | +#endif | |
346 | + | |
347 | + /* If this buffer is one which might reasonably be dirty | |
348 | + * --- ie. data, or not part of this journal --- then | |
349 | + * we're OK to leave it alone, but otherwise we need to | |
350 | + * move the dirty bit to the journal's own internal | |
351 | + * JBDDirty bit. */ | |
352 | + jlist = jh->b_jlist; | |
353 | + | |
354 | + if (jlist == BJ_Metadata || jlist == BJ_Reserved || | |
355 | + jlist == BJ_Shadow || jlist == BJ_Forget) { | |
356 | + if (atomic_set_buffer_clean(jh2bh(jh))) { | |
357 | + set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); | |
358 | + } | |
359 | + } | |
360 | + } | |
361 | +} | |
362 | + | |
363 | + | |
364 | int journal_blocks_per_page(struct inode *inode) | |
365 | { | |
366 | return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); | |
367 | Index: fs/jbd/transaction.c | |
368 | =================================================================== | |
369 | RCS file: /cvsroot/gkernel/ext3/fs/jbd/transaction.c,v | |
370 | retrieving revision 1.14.2.4 | |
371 | retrieving revision 1.64.2.9 | |
372 | diff -u -r1.14.2.4 -r1.64.2.9 | |
373 | --- fs/jbd/transaction.c 23 Jan 2002 07:26:47 -0000 1.14.2.4 | |
374 | +++ fs/jbd/transaction.c 9 May 2002 15:16:34 -0000 1.64.2.9 | |
375 | @@ -539,76 +539,67 @@ | |
376 | static int | |
377 | do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) | |
378 | { | |
379 | + struct buffer_head *bh; | |
380 | transaction_t *transaction = handle->h_transaction; | |
381 | journal_t *journal = transaction->t_journal; | |
382 | int error; | |
383 | char *frozen_buffer = NULL; | |
384 | int need_copy = 0; | |
385 | - | |
386 | + int locked; | |
387 | + | |
388 | jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); | |
389 | ||
390 | JBUFFER_TRACE(jh, "entry"); | |
391 | repeat: | |
392 | + bh = jh2bh(jh); | |
393 | + | |
394 | /* @@@ Need to check for errors here at some point. */ | |
395 | ||
396 | /* | |
397 | - * AKPM: neither bdflush nor kupdate run with the BKL. There's | |
398 | - * nothing we can do to prevent them from starting writeout of a | |
399 | - * BUF_DIRTY buffer at any time. And checkpointing buffers are on | |
400 | - * BUF_DIRTY. So. We no longer assert that the buffer is unlocked. | |
401 | - * | |
402 | - * However. It is very wrong for us to allow ext3 to start directly | |
403 | - * altering the ->b_data of buffers which may at that very time be | |
404 | - * undergoing writeout to the client filesystem. This can leave | |
405 | - * the filesystem in an inconsistent, transient state if we crash. | |
406 | - * So what we do is to steal the buffer if it is in checkpoint | |
407 | - * mode and dirty. The journal lock will keep out checkpoint-mode | |
408 | - * state transitions within journal_remove_checkpoint() and the buffer | |
409 | - * is locked to keep bdflush/kupdate/whoever away from it as well. | |
410 | - * | |
411 | * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a | |
412 | * simple lock_journal(). This code here will care for locked buffers. | |
413 | */ | |
414 | - /* | |
415 | - * The buffer_locked() || buffer_dirty() tests here are simply an | |
416 | - * optimisation tweak. If anyone else in the system decides to | |
417 | - * lock this buffer later on, we'll blow up. There doesn't seem | |
418 | - * to be a good reason why they should do this. | |
419 | - */ | |
420 | - if (jh->b_cp_transaction && | |
421 | - (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) { | |
422 | + locked = test_and_set_bit(BH_Lock, &bh->b_state); | |
423 | + if (locked) { | |
424 | + /* We can't reliably test the buffer state if we found | |
425 | + * it already locked, so just wait for the lock and | |
426 | + * retry. */ | |
427 | unlock_journal(journal); | |
428 | - lock_buffer(jh2bh(jh)); | |
429 | - spin_lock(&journal_datalist_lock); | |
430 | - if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) { | |
431 | - /* OK, we need to steal it */ | |
432 | - JBUFFER_TRACE(jh, "stealing from checkpoint mode"); | |
433 | - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); | |
434 | - J_ASSERT_JH(jh, jh->b_frozen_data == NULL); | |
435 | - | |
436 | - J_ASSERT(handle->h_buffer_credits > 0); | |
437 | - handle->h_buffer_credits--; | |
438 | - | |
439 | - /* This will clear BH_Dirty and set BH_JBDDirty. */ | |
440 | - JBUFFER_TRACE(jh, "file as BJ_Reserved"); | |
441 | - __journal_file_buffer(jh, transaction, BJ_Reserved); | |
442 | - | |
443 | - /* And pull it off BUF_DIRTY, onto BUF_CLEAN */ | |
444 | - refile_buffer(jh2bh(jh)); | |
445 | + __wait_on_buffer(bh); | |
446 | + lock_journal(journal); | |
447 | + goto repeat; | |
448 | + } | |
449 | + | |
450 | + /* We now hold the buffer lock so it is safe to query the buffer | |
451 | + * state. Is the buffer dirty? | |
452 | + * | |
453 | + * If so, there are two possibilities. The buffer may be | |
454 | + * non-journaled, and undergoing a quite legitimate writeback. | |
455 | + * Otherwise, it is journaled, and we don't expect dirty buffers | |
456 | + * in that state (the buffers should be marked JBD_Dirty | |
457 | + * instead.) So either the IO is being done under our own | |
458 | + * control and this is a bug, or it's a third party IO such as | |
459 | + * dump(8) (which may leave the buffer scheduled for read --- | |
460 | + * ie. locked but not dirty) or tune2fs (which may actually have | |
461 | + * the buffer dirtied, ugh.) */ | |
462 | ||
463 | - /* | |
464 | - * The buffer is now hidden from bdflush. It is | |
465 | - * metadata against the current transaction. | |
466 | - */ | |
467 | - JBUFFER_TRACE(jh, "steal from cp mode is complete"); | |
468 | + if (buffer_dirty(bh)) { | |
469 | + spin_lock(&journal_datalist_lock); | |
470 | + /* First question: is this buffer already part of the | |
471 | + * current transaction or the existing committing | |
472 | + * transaction? */ | |
473 | + if (jh->b_transaction) { | |
474 | + J_ASSERT_JH(jh, jh->b_transaction == transaction || | |
475 | + jh->b_transaction == journal->j_committing_transaction); | |
476 | + if (jh->b_next_transaction) | |
477 | + J_ASSERT_JH(jh, jh->b_next_transaction == transaction); | |
478 | + JBUFFER_TRACE(jh, "Unexpected dirty buffer"); | |
479 | + jbd_unexpected_dirty_buffer(jh); | |
480 | } | |
481 | spin_unlock(&journal_datalist_lock); | |
482 | - unlock_buffer(jh2bh(jh)); | |
483 | - lock_journal(journal); | |
484 | - goto repeat; | |
485 | } | |
486 | ||
487 | - J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh))); | |
488 | + unlock_buffer(bh); | |
489 | ||
490 | error = -EROFS; | |
491 | if (is_handle_aborted(handle)) | |
492 | @@ -1926,6 +1917,7 @@ | |
493 | transaction_t *transaction, int jlist) | |
494 | { | |
495 | struct journal_head **list = 0; | |
496 | + int was_dirty = 0; | |
497 | ||
498 | assert_spin_locked(&journal_datalist_lock); | |
499 | ||
500 | @@ -1936,13 +1928,24 @@ | |
501 | J_ASSERT_JH(jh, jh->b_transaction == transaction || | |
502 | jh->b_transaction == 0); | |
503 | ||
504 | - if (jh->b_transaction) { | |
505 | - if (jh->b_jlist == jlist) | |
506 | - return; | |
507 | + if (jh->b_transaction && jh->b_jlist == jlist) | |
508 | + return; | |
509 | + | |
510 | + /* The following list of buffer states needs to be consistent | |
511 | + * with __jbd_unexpected_dirty_buffer()'s handling of dirty | |
512 | + * state. */ | |
513 | + | |
514 | + if (jlist == BJ_Metadata || jlist == BJ_Reserved || | |
515 | + jlist == BJ_Shadow || jlist == BJ_Forget) { | |
516 | + if (atomic_set_buffer_clean(jh2bh(jh)) || | |
517 | + test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) | |
518 | + was_dirty = 1; | |
519 | + } | |
520 | + | |
521 | + if (jh->b_transaction) | |
522 | __journal_unfile_buffer(jh); | |
523 | - } else { | |
524 | + else | |
525 | jh->b_transaction = transaction; | |
526 | - } | |
527 | ||
528 | switch (jlist) { | |
529 | case BJ_None: | |
530 | @@ -1979,12 +1982,8 @@ | |
531 | __blist_add_buffer(list, jh); | |
532 | jh->b_jlist = jlist; | |
533 | ||
534 | - if (jlist == BJ_Metadata || jlist == BJ_Reserved || | |
535 | - jlist == BJ_Shadow || jlist == BJ_Forget) { | |
536 | - if (atomic_set_buffer_clean(jh2bh(jh))) { | |
537 | - set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); | |
538 | - } | |
539 | - } | |
540 | + if (was_dirty) | |
541 | + set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); | |
542 | } | |
543 | ||
544 | void journal_file_buffer(struct journal_head *jh, | |
545 | Index: include/linux/ext3_fs.h | |
546 | =================================================================== | |
547 | RCS file: /cvsroot/gkernel/ext3/include/linux/ext3_fs.h,v | |
548 | retrieving revision 1.22.2.3 | |
549 | retrieving revision 1.20.2.17 | |
550 | diff -u -r1.22.2.3 -r1.20.2.17 | |
551 | --- include/linux/ext3_fs.h 23 Jan 2002 07:26:47 -0000 1.22.2.3 | |
552 | +++ include/linux/ext3_fs.h 14 May 2002 15:24:16 -0000 1.20.2.17 | |
553 | @@ -36,8 +36,8 @@ | |
554 | /* | |
555 | * The second extended file system version | |
556 | */ | |
557 | -#define EXT3FS_DATE "10 Jan 2002" | |
558 | -#define EXT3FS_VERSION "2.4-0.9.17" | |
559 | +#define EXT3FS_DATE "14 May 2002" | |
560 | +#define EXT3FS_VERSION "2.4-0.9.18" | |
561 | ||
562 | /* | |
563 | * Debug code | |
564 | Index: include/linux/jbd.h | |
565 | =================================================================== | |
566 | RCS file: /cvsroot/gkernel/ext3/include/linux/jbd.h,v | |
567 | retrieving revision 1.38.2.5 | |
568 | diff -u -r1.38.2.5 jbd.h | |
569 | --- include/linux/jbd.h 13 Mar 2002 11:53:44 -0000 1.38.2.5 | |
570 | +++ include/linux/jbd.h 14 May 2002 15:31:34 -0000 | |
571 | @@ -32,6 +32,14 @@ | |
572 | ||
573 | #define journal_oom_retry 1 | |
574 | ||
575 | +/* | |
576 | + * Define JBD_PARANOID_WRITES to cause a kernel BUG() check if ext3 | |
577 | + * finds a buffer unexpectedly dirty. This is useful for debugging, but | |
578 | + * can cause spurious kernel panics if there are applications such as | |
579 | + * tune2fs modifying our buffer_heads behind our backs. | |
580 | + */ | |
581 | +#undef JBD_PARANOID_WRITES | |
582 | + | |
583 | #ifdef CONFIG_JBD_DEBUG | |
584 | /* | |
585 | * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal | |
586 | @@ -730,6 +738,10 @@ | |
587 | schedule(); \ | |
588 | } while (1) | |
589 | ||
590 | +extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *); | |
591 | +#define jbd_unexpected_dirty_buffer(jh) \ | |
592 | + __jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh)) | |
593 | + | |
594 | /* | |
595 | * is_journal_abort | |
596 | * |