void journal_unfile_buffer(struct buffer_head *buf) { struct buffer_head **list = 0; transaction_t * transaction; transaction = buf->b_transaction; #ifdef __SMP__ J_ASSERT (current->lock_depth >= 0); #endif J_ASSERT (transaction->t_journal->j_locked); J_ASSERT (buf->b_jlist < BJ_Types); if (buf->b_jlist != BJ_None) J_ASSERT (transaction != 0); switch (buf->b_jlist) { case BJ_None: return; case BJ_Data: list = &transaction->t_datalist; break; case BJ_Metadata: transaction->t_nr_buffers--; J_ASSERT(transaction->t_nr_buffers >= 0); list = &transaction->t_buffers; break; case BJ_Forget: list = &transaction->t_forget; break; case BJ_IO: list = &transaction->t_iobuf_list; break; case BJ_Shadow: list = &transaction->t_shadow_list; break; case BJ_LogCtl: list = &transaction->t_log_list; break; case BJ_Reserved: list = &transaction->t_reserved_list; break; } blist_del_buffer(list, buf); buf->b_jlist = BJ_None; if (buffer_jdirty(buf)) { set_bit(BH_Dirty, &buf->b_state); clear_bit(BH_JDirty, &buf->b_state); } }
void journal_release_buffer (handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; lock_journal(journal); /* If the buffer is reserved but not modified by this * transaction, then it is safe to release it. In all other * cases, just leave the buffer as it is. */ if (bh->b_jlist == BJ_Reserved && bh->b_transaction == transaction && !buffer_jdirty(bh)) { handle->h_buffer_credits++; journal_refile_buffer(bh); } unlock_journal(journal); }
/* * journal_insert_checkpoint: put a committed buffer onto a checkpoint * list so that we know when it is safe to clean the transaction out of * the log. * * Called with the journal locked. * Called with journal_datalist_lock held. */ void __journal_insert_checkpoint(struct journal_head *jh, transaction_t *transaction) { JBUFFER_TRACE(jh, "entry"); J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jdirty(jh2bh(jh))); J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); assert_spin_locked(&journal_datalist_lock); jh->b_cp_transaction = transaction; if (!transaction->t_checkpoint_list) { jh->b_cpnext = jh->b_cpprev = jh; } else { jh->b_cpnext = transaction->t_checkpoint_list; jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev; jh->b_cpprev->b_cpnext = jh; jh->b_cpnext->b_cpprev = jh; } transaction->t_checkpoint_list = jh; }
/* * Clean up a transaction's checkpoint list. * * We wait for any pending IO to complete and make sure any clean * buffers are removed from the transaction. * * Return 1 if we performed any actions which might have destroyed the * checkpoint. (journal_remove_checkpoint() deletes the transaction when * the last checkpoint buffer is cleansed) * * Called with the journal locked. * Called with journal_datalist_lock held. */ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) { struct journal_head *jh, *next_jh, *last_jh; struct buffer_head *bh; int ret = 0; assert_spin_locked(&journal_datalist_lock); jh = transaction->t_checkpoint_list; if (!jh) return 0; last_jh = jh->b_cpprev; next_jh = jh; do { jh = next_jh; bh = jh2bh(jh); if (buffer_locked(bh)) { atomic_inc(&bh->b_count); spin_unlock(&journal_datalist_lock); unlock_journal(journal); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); __brelse(bh); goto out_return_1; } if (jh->b_transaction != NULL) { transaction_t *transaction = jh->b_transaction; tid_t tid = transaction->t_tid; spin_unlock(&journal_datalist_lock); log_start_commit(journal, transaction); unlock_journal(journal); log_wait_commit(journal, tid); goto out_return_1; } /* * We used to test for (jh->b_list != BUF_CLEAN) here. * But unmap_underlying_metadata() can place buffer onto * BUF_CLEAN. Since refile_buffer() no longer takes buffers * off checkpoint lists, we cope with it here */ /* * AKPM: I think the buffer_jdirty test is redundant - it * shouldn't have NULL b_transaction? */ next_jh = jh->b_cpnext; if (!buffer_dirty(bh) && !buffer_jdirty(bh)) { BUFFER_TRACE(bh, "remove from checkpoint"); __journal_remove_checkpoint(jh); __journal_remove_journal_head(bh); refile_buffer(bh); __brelse(bh); ret = 1; } jh = next_jh; } while (jh != last_jh); return ret; out_return_1: lock_journal(journal); spin_lock(&journal_datalist_lock); return 1; }