⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 checkpoint.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (!retry && lock_need_resched(&journal->j_list_lock)){				spin_unlock(&journal->j_list_lock);				retry = 1;				break;			}		}		if (batch_count) {			if (!retry) {				spin_unlock(&journal->j_list_lock);				retry = 1;			}			__flush_batch(journal, bhs, &batch_count);		}		if (retry) {			spin_lock(&journal->j_list_lock);			goto restart;		}		/*		 * Now we have cleaned up the first transaction's checkpoint		 * list. Let's clean up the second one		 */		__wait_cp_io(journal, transaction);	}out:	spin_unlock(&journal->j_list_lock);	result = jbd2_cleanup_journal_tail(journal);	if (result < 0)		return result;	return 0;}/* * Check the list of checkpoint transactions for the journal to see if * we have already got rid of any since the last update of the log tail * in the journal superblock.  If so, we can instantly roll the * superblock forward to remove those transactions from the log. * * Return <0 on error, 0 on success, 1 if there was nothing to clean up. * * Called with the journal lock held. * * This is the only part of the journaling code which really needs to be * aware of transaction aborts.  Checkpointing involves writing to the * main filesystem area rather than to the journal, so it can proceed * even in abort state, but we must not update the journal superblock if * we have an abort error outstanding. */int jbd2_cleanup_journal_tail(journal_t *journal){	transaction_t * transaction;	tid_t		first_tid;	unsigned long	blocknr, freed;	/* OK, work out the oldest transaction remaining in the log, and	 * the log block it starts at.	 *	 * If the log is now empty, we need to work out which is the	 * next transaction ID we will write, and where it will	 * start. */	spin_lock(&journal->j_state_lock);	spin_lock(&journal->j_list_lock);	transaction = journal->j_checkpoint_transactions;	if (transaction) {		first_tid = transaction->t_tid;		blocknr = transaction->t_log_start;	} else if ((transaction = journal->j_committing_transaction) != NULL) {		first_tid = transaction->t_tid;		blocknr = transaction->t_log_start;	} else if ((transaction = journal->j_running_transaction) != NULL) {		first_tid = transaction->t_tid;		blocknr = journal->j_head;	} else {		first_tid = journal->j_transaction_sequence;		blocknr = journal->j_head;	}	spin_unlock(&journal->j_list_lock);	J_ASSERT(blocknr != 0);	/* If the oldest pinned transaction is at the tail of the log           already then there's not much we can do right now. */	if (journal->j_tail_sequence == first_tid) {		spin_unlock(&journal->j_state_lock);		return 1;	}	/* OK, update the superblock to recover the freed space.	 * Physical blocks come first: have we wrapped beyond the end of	 * the log?  */	freed = blocknr - journal->j_tail;	if (blocknr < journal->j_tail)		freed = freed + journal->j_last - journal->j_first;	jbd_debug(1,		  "Cleaning journal tail from %d to %d (offset %lu), "		  "freeing %lu\n",		  journal->j_tail_sequence, first_tid, blocknr, freed);	journal->j_free += freed;	journal->j_tail_sequence = first_tid;	journal->j_tail = blocknr;	spin_unlock(&journal->j_state_lock);	if (!(journal->j_flags & JBD2_ABORT))		jbd2_journal_update_superblock(journal, 1);	return 0;}/* Checkpoint list management *//* * journal_clean_one_cp_list * * Find all the written-back checkpoint buffers in the given list and release them. * * Called with the journal locked. * Called with j_list_lock held. * Returns number of bufers reaped (for debug) */static int journal_clean_one_cp_list(struct journal_head *jh, int *released){	struct journal_head *last_jh;	struct journal_head *next_jh = jh;	int ret, freed = 0;	*released = 0;	if (!jh)		return 0;	last_jh = jh->b_cpprev;	do {		jh = next_jh;		next_jh = jh->b_cpnext;		/* Use trylock because of the ranking */		if (jbd_trylock_bh_state(jh2bh(jh))) {			ret = __try_to_free_cp_buf(jh);			if (ret) {				freed++;				if (ret == 2) {					*released = 1;					return freed;				}			}		}		/*		 * This function only frees up some memory		 * if possible so we dont have an obligation		 * to finish processing. Bail out if preemption		 * requested:		 */		if (need_resched())			return freed;	} while (jh != last_jh);	return freed;}/* * journal_clean_checkpoint_list * * Find all the written-back checkpoint buffers in the journal and release them. * * Called with the journal locked. * Called with j_list_lock held. * Returns number of buffers reaped (for debug) */int __jbd2_journal_clean_checkpoint_list(journal_t *journal){	transaction_t *transaction, *last_transaction, *next_transaction;	int ret = 0;	int released;	transaction = journal->j_checkpoint_transactions;	if (!transaction)		goto out;	last_transaction = transaction->t_cpprev;	next_transaction = transaction;	do {		transaction = next_transaction;		next_transaction = transaction->t_cpnext;		ret += journal_clean_one_cp_list(transaction->				t_checkpoint_list, &released);		/*		 * This function only frees up some memory if possible so we		 * dont have an obligation to finish processing. Bail out if		 * preemption requested:		 */		if (need_resched())			goto out;		if (released)			continue;		/*		 * It is essential that we are as careful as in the case of		 * t_checkpoint_list with removing the buffer from the list as		 * we can possibly see not yet submitted buffers on io_list		 */		ret += journal_clean_one_cp_list(transaction->				t_checkpoint_io_list, &released);		if (need_resched())			goto out;	} while (transaction != last_transaction);out:	return ret;}/* * journal_remove_checkpoint: called after a buffer has been committed * to disk (either by being write-back flushed to disk, or being * committed to the log). * * We cannot safely clean a transaction out of the log until all of the * buffer updates committed in that transaction have safely been stored * elsewhere on disk.  To achieve this, all of the buffers in a * transaction need to be maintained on the transaction's checkpoint * lists until they have been rewritten, at which point this function is * called to remove the buffer from the existing transaction's * checkpoint lists. * * The function returns 1 if it frees the transaction, 0 otherwise. * * This function is called with the journal locked. * This function is called with j_list_lock held. * This function is called with jbd_lock_bh_state(jh2bh(jh)) */int __jbd2_journal_remove_checkpoint(struct journal_head *jh){	transaction_t *transaction;	journal_t *journal;	int ret = 0;	JBUFFER_TRACE(jh, "entry");	if ((transaction = jh->b_cp_transaction) == NULL) {		JBUFFER_TRACE(jh, "not on transaction");		goto out;	}	journal = transaction->t_journal;	__buffer_unlink(jh);	jh->b_cp_transaction = NULL;	if (transaction->t_checkpoint_list != NULL ||	    transaction->t_checkpoint_io_list != NULL)		goto out;	JBUFFER_TRACE(jh, "transaction has no more buffers");	/*	 * There is one special case to worry about: if we have just pulled the	 * buffer off a committing transaction's forget list, then even if the	 * checkpoint list is empty, the transaction obviously cannot be	 * dropped!	 *	 * The locking here around j_committing_transaction is a bit sleazy.	 * See the comment at the end of jbd2_journal_commit_transaction().	 */	if (transaction == journal->j_committing_transaction) {		JBUFFER_TRACE(jh, "belongs to committing transaction");		goto out;	}	/* OK, that was the last buffer for the transaction: we can now	   safely remove this transaction from the log */	__jbd2_journal_drop_transaction(journal, transaction);	/* Just in case anybody was waiting for more transactions to be           checkpointed... */	wake_up(&journal->j_wait_logspace);	ret = 1;out:	JBUFFER_TRACE(jh, "exit");	return ret;}/* * 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 j_list_lock held. */void __jbd2_journal_insert_checkpoint(struct journal_head *jh,			       transaction_t *transaction){	JBUFFER_TRACE(jh, "entry");	J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh)));	J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);	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;}/* * We've finished with this transaction structure: adios... * * The transaction must have no links except for the checkpoint by this * point. * * Called with the journal locked. * Called with j_list_lock held. */void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction){	assert_spin_locked(&journal->j_list_lock);	if (transaction->t_cpnext) {		transaction->t_cpnext->t_cpprev = transaction->t_cpprev;		transaction->t_cpprev->t_cpnext = transaction->t_cpnext;		if (journal->j_checkpoint_transactions == transaction)			journal->j_checkpoint_transactions =				transaction->t_cpnext;		if (journal->j_checkpoint_transactions == transaction)			journal->j_checkpoint_transactions = NULL;	}	J_ASSERT(transaction->t_state == T_FINISHED);	J_ASSERT(transaction->t_buffers == NULL);	J_ASSERT(transaction->t_sync_datalist == NULL);	J_ASSERT(transaction->t_forget == NULL);	J_ASSERT(transaction->t_iobuf_list == NULL);	J_ASSERT(transaction->t_shadow_list == NULL);	J_ASSERT(transaction->t_log_list == NULL);	J_ASSERT(transaction->t_checkpoint_list == NULL);	J_ASSERT(transaction->t_checkpoint_io_list == NULL);	J_ASSERT(transaction->t_updates == 0);	J_ASSERT(journal->j_committing_transaction != transaction);	J_ASSERT(journal->j_running_transaction != transaction);	jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);	kfree(transaction);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -