jbd2: speedup jbd2_journal_dirty_metadata()
It is often the case that we mark buffer as having dirty metadata when the buffer is already in that state (frequent for bitmaps, inode table blocks, superblock). Thus it is unnecessary to contend on grabbing journal head reference and bh_state lock. Avoid that by checking whether any modification to the buffer is needed before grabbing any locks or references. [ Note: this is a fixed version of commit2143c1965a
, which was reverted inebeaa8ddb3
due to a false positive triggering of an assertion check. -- Ted ] Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
bc0195aad0
commit
6e06ae88ed
1 changed files with 32 additions and 6 deletions
|
@ -1280,8 +1280,6 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh,
|
||||||
triggers->t_abort(triggers, jh2bh(jh));
|
triggers->t_abort(triggers, jh2bh(jh));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata
|
* int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata
|
||||||
* @handle: transaction to add buffer to.
|
* @handle: transaction to add buffer to.
|
||||||
|
@ -1314,12 +1312,41 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||||||
|
|
||||||
if (is_handle_aborted(handle))
|
if (is_handle_aborted(handle))
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
journal = transaction->t_journal;
|
if (!buffer_jbd(bh)) {
|
||||||
jh = jbd2_journal_grab_journal_head(bh);
|
|
||||||
if (!jh) {
|
|
||||||
ret = -EUCLEAN;
|
ret = -EUCLEAN;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* We don't grab jh reference here since the buffer must be part
|
||||||
|
* of the running transaction.
|
||||||
|
*/
|
||||||
|
jh = bh2jh(bh);
|
||||||
|
/*
|
||||||
|
* This and the following assertions are unreliable since we may see jh
|
||||||
|
* in inconsistent state unless we grab bh_state lock. But this is
|
||||||
|
* crucial to catch bugs so let's do a reliable check until the
|
||||||
|
* lockless handling is fully proven.
|
||||||
|
*/
|
||||||
|
if (jh->b_transaction != transaction &&
|
||||||
|
jh->b_next_transaction != transaction) {
|
||||||
|
jbd_lock_bh_state(bh);
|
||||||
|
J_ASSERT_JH(jh, jh->b_transaction == transaction ||
|
||||||
|
jh->b_next_transaction == transaction);
|
||||||
|
jbd_unlock_bh_state(bh);
|
||||||
|
}
|
||||||
|
if (jh->b_modified == 1) {
|
||||||
|
/* If it's in our transaction it must be in BJ_Metadata list. */
|
||||||
|
if (jh->b_transaction == transaction &&
|
||||||
|
jh->b_jlist != BJ_Metadata) {
|
||||||
|
jbd_lock_bh_state(bh);
|
||||||
|
J_ASSERT_JH(jh, jh->b_transaction != transaction ||
|
||||||
|
jh->b_jlist == BJ_Metadata);
|
||||||
|
jbd_unlock_bh_state(bh);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
journal = transaction->t_journal;
|
||||||
jbd_debug(5, "journal_head %p\n", jh);
|
jbd_debug(5, "journal_head %p\n", jh);
|
||||||
JBUFFER_TRACE(jh, "entry");
|
JBUFFER_TRACE(jh, "entry");
|
||||||
|
|
||||||
|
@ -1410,7 +1437,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||||||
spin_unlock(&journal->j_list_lock);
|
spin_unlock(&journal->j_list_lock);
|
||||||
out_unlock_bh:
|
out_unlock_bh:
|
||||||
jbd_unlock_bh_state(bh);
|
jbd_unlock_bh_state(bh);
|
||||||
jbd2_journal_put_journal_head(jh);
|
|
||||||
out:
|
out:
|
||||||
JBUFFER_TRACE(jh, "exit");
|
JBUFFER_TRACE(jh, "exit");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue