Пример #1
0
void log_wait_for_space(journal_t *journal, int nblocks)
{
	while (log_space_left(journal) < nblocks) {
		if (journal->j_flags & JFS_ABORT)
			return;
		unlock_journal(journal);
		down(&journal->j_checkpoint_sem);
		lock_journal(journal);
		
		/* Test again, another process may have checkpointed
		 * while we were waiting for the checkpoint lock */
		if (log_space_left(journal) < nblocks) {
			log_do_checkpoint(journal, nblocks);
		}
		up(&journal->j_checkpoint_sem);
	}
}
Пример #2
0
int journal_extend (handle_t *handle, int nblocks)
{
	transaction_t *transaction = handle->h_transaction;
	journal_t *journal = transaction->t_journal;
	int result = 1;
	int wanted;
	
	lock_journal (journal);

	/* Don't extend a locked-down transaction! */
	if (handle->h_transaction->t_state != T_RUNNING) {
		jfs_debug(3, "denied handle %p %d blocks: "
			  "transaction not running\n", handle, nblocks);
		goto error_out;
	}
	
	wanted = transaction->t_outstanding_credits + nblocks;
	
	if (wanted > journal->j_max_transaction_buffers) {
		jfs_debug(3, "denied handle %p %d blocks: "
			  "transaction too large\n", handle, nblocks);
		goto error_out;
	}

	if (wanted > log_space_left(journal)) {
		jfs_debug(3, "denied handle %p %d blocks: "
			  "insufficient log space\n", handle, nblocks);
		goto error_out;
	}
	
	handle->h_buffer_credits += nblocks;
	transaction->t_outstanding_credits += nblocks;
	result = 0;

	jfs_debug(3, "extended handle %p by %d\n", handle, nblocks);
	
error_out:
	unlock_journal (journal);
	return result;
}
Пример #3
0
static int start_this_handle(journal_t *journal, handle_t *handle)
{
	transaction_t *transaction;
	int needed;
	int nblocks = handle->h_buffer_credits;
	
	jfs_debug(4, "New handle %p going live.\n", handle);

repeat:

	lock_journal(journal);

	if ((journal->j_flags & JFS_ABORT) ||
	    (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) {
		unlock_journal(journal);
		return -EROFS; 
	}

	/* Wait on the journal's transaction barrier if necessary */
	if (journal->j_barrier_count) {
		unlock_journal(journal);
		sleep_on(&journal->j_wait_transaction_locked);
		goto repeat;
	}
	
repeat_locked:
	if (!journal->j_running_transaction)
		get_transaction(journal);
	/* @@@ Error? */
	J_ASSERT(journal->j_running_transaction);
	
	transaction = journal->j_running_transaction;

	/* If the current transaction is locked down for commit, wait
	 * for the lock to be released. */

	if (transaction->t_state == T_LOCKED) {
		unlock_journal(journal);
		jfs_debug(3, "Handle %p stalling...\n", handle);
		sleep_on(&journal->j_wait_transaction_locked);
		goto repeat;
	}
	
	/* If there is not enough space left in the log to write all
	 * potential buffers requested by this operation, we need to
	 * stall pending a log checkpoint to free some more log
	 * space. */

	needed = transaction->t_outstanding_credits + nblocks;

	if (needed > journal->j_max_transaction_buffers) {
		/* If the current transaction is already too large, then
		 * start to commit it: we can then go back and attach
		 * this handle to a new transaction. */
		
		jfs_debug(2, "Handle %p starting new commit...\n", handle);
		log_start_commit(journal, transaction);
		unlock_journal(journal);
		sleep_on(&journal->j_wait_transaction_locked);
		lock_journal(journal);
		goto repeat_locked;
	}

	/* 
	 * The commit code assumes that it can get enough log space
	 * without forcing a checkpoint.  This is *critical* for
	 * correctness: a checkpoint of a buffer which is also
	 * associated with a committing transaction creates a deadlock,
	 * so commit simply cannot force through checkpoints.
	 *
	 * We must therefore ensure the necessary space in the journal
	 * *before* starting to dirty potentially checkpointed buffers
	 * in the new transaction. 
	 *
	 * The worst part is, any transaction currently committing can
	 * reduce the free space arbitrarily.  Be careful to account for
	 * those buffers when checkpointing.
	 */

	needed = journal->j_max_transaction_buffers;
	if (journal->j_committing_transaction) 
		needed += journal->j_committing_transaction->t_outstanding_credits;
	
	if (log_space_left(journal) < needed) {
		jfs_debug(2, "Handle %p waiting for checkpoint...\n", handle);
		log_wait_for_space(journal, needed);
		goto repeat_locked;
	}

	/* OK, account for the buffers that this operation expects to
	 * use and add the handle to the running transaction. */

	handle->h_transaction = transaction;
	transaction->t_outstanding_credits += nblocks;
	transaction->t_updates++;
	jfs_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
		  handle, nblocks, transaction->t_outstanding_credits,
		  log_space_left(journal));

	unlock_journal(journal);
	
	return 0;
}