Ejemplo n.º 1
0
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);
	}
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/*
 * 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;
}
Ejemplo n.º 4
0
/*
 * 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;
}