Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 155436
b: refs/heads/master
c: f91d1d0
h: refs/heads/master
v: v3
  • Loading branch information
Jan Kara authored and Theodore Ts'o committed Jul 13, 2009
1 parent ad8ff7a commit ba2b55e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 34 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3e03f9ca6a2599db1823bb0ea24e0845219a0e69
refs/heads/master: f91d1d04171026e56c7e343ee3cdcc801dd85cfb
68 changes: 35 additions & 33 deletions trunk/fs/jbd2/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,34 +499,15 @@ void jbd2_journal_unlock_updates (journal_t *journal)
wake_up(&journal->j_wait_transaction_locked);
}

/*
* Report any unexpected dirty buffers which turn up. Normally those
* indicate an error, but they can occur if the user is running (say)
* tune2fs to modify the live filesystem, so we need the option of
* continuing as gracefully as possible. #
*
* The caller should already hold the journal lock and
* j_list_lock spinlock: most callers will need those anyway
* in order to probe the buffer's journaling state safely.
*/
static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
static void warn_dirty_buffer(struct buffer_head *bh)
{
int jlist;

/* If this buffer is one which might reasonably be dirty
* --- ie. data, or not part of this journal --- then
* we're OK to leave it alone, but otherwise we need to
* move the dirty bit to the journal's own internal
* JBDDirty bit. */
jlist = jh->b_jlist;
char b[BDEVNAME_SIZE];

if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
jlist == BJ_Shadow || jlist == BJ_Forget) {
struct buffer_head *bh = jh2bh(jh);

if (test_clear_buffer_dirty(bh))
set_buffer_jbddirty(bh);
}
printk(KERN_WARNING
"JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
"There's a risk of filesystem corruption in case of system "
"crash.\n",
bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
}

/*
Expand Down Expand Up @@ -593,14 +574,16 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
if (jh->b_next_transaction)
J_ASSERT_JH(jh, jh->b_next_transaction ==
transaction);
warn_dirty_buffer(bh);
}
/*
* In any case we need to clean the dirty flag and we must
* do it under the buffer lock to be sure we don't race
* with running write-out.
*/
JBUFFER_TRACE(jh, "Unexpected dirty buffer");
jbd_unexpected_dirty_buffer(jh);
JBUFFER_TRACE(jh, "Journalling dirty buffer");
clear_buffer_dirty(bh);
set_buffer_jbddirty(bh);
}

unlock_buffer(bh);
Expand Down Expand Up @@ -843,6 +826,15 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));

if (jh->b_transaction == NULL) {
/*
* Previous jbd2_journal_forget() could have left the buffer
* with jbddirty bit set because it was being committed. When
* the commit finished, we've filed the buffer for
* checkpointing and marked it dirty. Now we are reallocating
* the buffer so the transaction freeing it must have
* committed and so it's safe to clear the dirty bit.
*/
clear_buffer_dirty(jh2bh(jh));
jh->b_transaction = transaction;

/* first access by this transaction */
Expand Down Expand Up @@ -1644,8 +1636,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)

if (jh->b_cp_transaction) {
JBUFFER_TRACE(jh, "on running+cp transaction");
/*
* We don't want to write the buffer anymore, clear the
* bit so that we don't confuse checks in
* __journal_file_buffer
*/
clear_buffer_dirty(bh);
__jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
clear_buffer_jbddirty(bh);
may_free = 0;
} else {
JBUFFER_TRACE(jh, "on running transaction");
Expand Down Expand Up @@ -1896,12 +1893,17 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
if (jh->b_transaction && jh->b_jlist == jlist)
return;

/* The following list of buffer states needs to be consistent
* with __jbd_unexpected_dirty_buffer()'s handling of dirty
* state. */

if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
jlist == BJ_Shadow || jlist == BJ_Forget) {
/*
* For metadata buffers, we track dirty bit in buffer_jbddirty
* instead of buffer_dirty. We should not see a dirty bit set
* here because we clear it in do_get_write_access but e.g.
* tune2fs can modify the sb and set the dirty bit at any time
* so we try to gracefully handle that.
*/
if (buffer_dirty(bh))
warn_dirty_buffer(bh);
if (test_clear_buffer_dirty(bh) ||
test_clear_buffer_jbddirty(bh))
was_dirty = 1;
Expand Down

0 comments on commit ba2b55e

Please sign in to comment.