Message ID | 20080922140851.bc3f9319.akpm@linux-foundation.org |
---|---|
State | Accepted, archived |
Headers | show |
2008/9/22 Andrew Morton <akpm@linux-foundation.org>: > Guys, I have a note here that this might be needed in 2.6.27. > > I also have a note that Stephen had issues with it, but I > don't recall what they were. Stephen suggested that it would be better to sanity check the journal start/end pointers on mount, rather than catching the error later like this. I never quite convinced myself I'd worked out the right way to do that, sorry. Perhaps someone would like to confirm (or otherwise) whether or not the following is correct: In journal_reset (?) check that: journal->j_first == 1 (this seems to be the only valid value) and journal->j_last >= JFS_MIN_JOURNAL_BLOCKS Additionally, it should be possible to check the journal->j_last more precisely. For internal journals it seems straight-forward, we can just check that journal->j_last == inode->i_size >> inode->i_sb->s_blocksize_bits. For external journals we'd need to load the device's superblock and check journal->j_last == s_blocks_count. > Can we get this sorted out please? If the above is confirmed I'll send a patch to that effect for jdb, jdb2 and for e2fsprogs (fsck doesn't check j_first/j_last either). Regardless, I think the original patch may be a good idea. It improves robustness and matches the other locations where we call jbd2_log_do_checkpoint. They are all in loops that test that journal->j_checkpoint_transactions != NULL. Cheers, Duane.
On Tue, Sep 23, 2008 at 05:56:27PM +0100, Duane Griffin wrote: > Stephen suggested that it would be better to sanity check the journal > start/end pointers on mount, rather than catching the error later like > this. I never quite convinced myself I'd worked out the right way to > do that, sorry. Perhaps someone would like to confirm (or otherwise) > whether or not the following is correct: > > In journal_reset (?) check that: > > journal->j_first == 1 (this seems to be the only valid value) > > and > > journal->j_last >= JFS_MIN_JOURNAL_BLOCKS Yes, for all existing currently created, j_first will be 1. I can't think of a good reason for why we might want to reserve some space at the beginning of the journal, but the safest check would be: (journal->j_last - journal->j_first +1) >= JFS_MIN_JOURNAL_BLOCKS > Additionally, it should be possible to check the journal->j_last more > precisely. For internal journals it seems straight-forward, we can > just check that journal->j_last == inode->i_size >> > inode->i_sb->s_blocksize_bits. For external journals we'd need to load > the device's superblock and check journal->j_last == s_blocks_count. Yep, agreed. > Regardless, I think the original patch may be a good idea. It improves > robustness and matches the other locations where we call > jbd2_log_do_checkpoint. They are all in loops that test that > journal->j_checkpoint_transactions != NULL. Agreed. I've included it in the ext4 patch queue, and will be soon putting out a new ext4 patchset consisting of the patches I plan to push during the next merge window. - Ted -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff -puN fs/jbd2/checkpoint.c~jbd2-abort-instead-of-waiting-for-nonexistent-transactions fs/jbd2/checkpoint.c --- a/fs/jbd2/checkpoint.c~jbd2-abort-instead-of-waiting-for-nonexistent-transactions +++ a/fs/jbd2/checkpoint.c @@ -126,14 +126,29 @@ void __jbd2_log_wait_for_space(journal_t /* * Test again, another process may have checkpointed while we - * were waiting for the checkpoint lock + * were waiting for the checkpoint lock. If there are no + * outstanding transactions there is nothing to checkpoint and + * we can't make progress. Abort the journal in this case. */ spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); nblocks = jbd_space_needed(journal); if (__jbd2_log_space_left(journal) < nblocks) { + int chkpt = journal->j_checkpoint_transactions != NULL; + + spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_state_lock); - jbd2_log_do_checkpoint(journal); + if (chkpt) { + jbd2_log_do_checkpoint(journal); + } else { + printk(KERN_ERR "%s: no transactions\n", + __func__); + jbd2_journal_abort(journal, 0); + } + spin_lock(&journal->j_state_lock); + } else { + spin_unlock(&journal->j_list_lock); } mutex_unlock(&journal->j_checkpoint_mutex); }