On Mon, 2008-04-28 at 20:09 +0200, Jan Kara wrote:
Thanks, yes I noticed that after you pointing this out.
But __journal_try_to_free_buffer() only unfile the buffer from
t_sync_datalist or t_locked list, the journal head is not removed in
journal_remove_journal_head() there, at that time,
journal_remove_journal_head() just check if counter b_jcount is 0. But
before calling __journal_try_to_free_buffer(), since
journal_try_to_free_buffers() already increase the b_jcount in
journal_grab_journal_head(), so the journal head is not removed in
__journal_try_to_free_buffer-> journal_remove_journal_head()
Looking at the code, it seems the it's the journal_put_journal_head(jh)
who remove the journal head and decrease the bh
journal_try_to_free_buffers()
{
...
jh = journal_grab_journal_head(bh);
if (!jh)
continue;
jbd_lock_bh_state(bh);
__journal_try_to_free_buffer(journal, bh);
journal_put_journal_head(jh);
jbd_unlock_bh_state(bh);
...
}
so when journal_put_journal_head()-> __journal_remove_journal_head(),
now the b_jcount is zero, but is
jh->b_transaction is NULL? So it seems possible that bh ref count is non
zero when exit from journal_put_journal_head() if jh_b_transaction is
not cleared.
I miss where jh->b_transaction is clear to NULL?
void journal_put_journal_head(struct journal_head *jh)
{
struct buffer_head *bh = jh2bh(jh);
jbd_lock_bh_journal_head(bh);
J_ASSERT_JH(jh, jh->b_jcount > 0);
--jh->b_jcount;
if (!jh->b_jcount && !jh->b_transaction) {
__journal_remove_journal_head(bh);
__brelse(bh);
}
jbd_unlock_bh_journal_head(bh);
}
Mingming
--