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

📄 transaction.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
	result = 0;	jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);	error_out:	unlock_journal (journal);	return result;}/* * journal_restart: restart a handle for a multi-transaction filesystem * operation. * * If the journal_extend() call above fails to grant new buffer credits * to a running handle, a call to journal_restart will commit the * handle's transaction so far and reattach the handle to a new * transaction capabable of guaranteeing the requested number of * credits. */int journal_restart(handle_t *handle, int nblocks){	transaction_t *transaction = handle->h_transaction;	journal_t *journal = transaction->t_journal;	int ret;	/* If we've had an abort of any type, don't even think about	 * actually doing the restart! */	if (is_handle_aborted(handle))		return 0;		/* First unlink the handle from its current transaction, and	 * start the commit on that. */		J_ASSERT (transaction->t_updates > 0);	J_ASSERT (journal_current_handle() == handle);	transaction->t_outstanding_credits -= handle->h_buffer_credits;	transaction->t_updates--;	if (!transaction->t_updates)		wake_up(&journal->j_wait_updates);	jbd_debug(2, "restarting handle %p\n", handle);	log_start_commit(journal, transaction);	handle->h_buffer_credits = nblocks;	ret = start_this_handle(journal, handle);	return ret;}/*  * Barrier operation: establish a transaction barrier.  * * This locks out any further updates from being started, and blocks * until all existing updates have completed, returning only once the * journal is in a quiescent state with no updates running. * * The journal lock should not be held on entry. */void journal_lock_updates (journal_t *journal){	lock_journal(journal);	++journal->j_barrier_count;	/* Wait until there are no running updates */	while (1) {		transaction_t *transaction = journal->j_running_transaction;		if (!transaction)			break;		if (!transaction->t_updates)			break;				unlock_journal(journal);		sleep_on(&journal->j_wait_updates);		lock_journal(journal);	}	unlock_journal(journal);	/* We have now established a barrier against other normal	 * updates, but we also need to barrier against other	 * journal_lock_updates() calls to make sure that we serialise	 * special journal-locked operations too. */	down(&journal->j_barrier);}/* * Release a transaction barrier obtained with journal_lock_updates(). * * Should be called without the journal lock held. */void journal_unlock_updates (journal_t *journal){	lock_journal(journal);	J_ASSERT (journal->j_barrier_count != 0);		up(&journal->j_barrier);	--journal->j_barrier_count;	wake_up(&journal->j_wait_transaction_locked);	unlock_journal(journal);}/* * journal_get_write_access: notify intent to modify a buffer for metadata * (not data) update. * * If the buffer is already part of the current transaction, then there * is nothing we need to do.  If it is already part of a prior * transaction which we are still committing to disk, then we need to * make sure that we do not overwrite the old copy: we do copy-out to * preserve the copy going to disk.  We also account the buffer against * the handle's metadata buffer credits (unless the buffer is already * part of the transaction, that is). * * Returns an error code or 0 on success. * * In full data journalling mode the buffer may be of type BJ_AsyncData, * because we're write()ing a buffer which is also part of a shared mapping. */static intdo_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) {	transaction_t *transaction = handle->h_transaction;	journal_t *journal = transaction->t_journal;	int error;	char *frozen_buffer = NULL;	int need_copy = 0;	jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);	JBUFFER_TRACE(jh, "entry");repeat:	/* @@@ Need to check for errors here at some point. */	/*	 * AKPM: neither bdflush nor kupdate run with the BKL.   There's	 * nothing we can do to prevent them from starting writeout of a	 * BUF_DIRTY buffer at any time.  And checkpointing buffers are on	 * BUF_DIRTY.  So.  We no longer assert that the buffer is unlocked.	 *	 * However.  It is very wrong for us to allow ext3 to start directly	 * altering the ->b_data of buffers which may at that very time be	 * undergoing writeout to the client filesystem.  This can leave	 * the filesystem in an inconsistent, transient state if we crash.	 * So what we do is to steal the buffer if it is in checkpoint	 * mode and dirty.  The journal lock will keep out checkpoint-mode	 * state transitions within journal_remove_checkpoint() and the buffer	 * is locked to keep bdflush/kupdate/whoever away from it as well.	 *	 * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a	 * simple lock_journal().  This code here will care for locked buffers.	 */	/*	 * The buffer_locked() || buffer_dirty() tests here are simply an	 * optimisation tweak.  If anyone else in the system decides to	 * lock this buffer later on, we'll blow up.  There doesn't seem	 * to be a good reason why they should do this.	 */	if (jh->b_cp_transaction &&	    (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) {		unlock_journal(journal);		lock_buffer(jh2bh(jh));		spin_lock(&journal_datalist_lock);		if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) {			/* OK, we need to steal it */			JBUFFER_TRACE(jh, "stealing from checkpoint mode");			J_ASSERT_JH(jh, jh->b_next_transaction == NULL);			J_ASSERT_JH(jh, jh->b_frozen_data == NULL);			J_ASSERT(handle->h_buffer_credits > 0);			handle->h_buffer_credits--;			/* This will clear BH_Dirty and set BH_JBDDirty. */			JBUFFER_TRACE(jh, "file as BJ_Reserved");			__journal_file_buffer(jh, transaction, BJ_Reserved);			/* And pull it off BUF_DIRTY, onto BUF_CLEAN */			refile_buffer(jh2bh(jh));			/*			 * The buffer is now hidden from bdflush.   It is			 * metadata against the current transaction.			 */			JBUFFER_TRACE(jh, "steal from cp mode is complete");		}		spin_unlock(&journal_datalist_lock);		unlock_buffer(jh2bh(jh));		lock_journal(journal);		goto repeat;	}	J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh)));	error = -EROFS;	if (is_handle_aborted(handle)) 		goto out_unlocked;	error = 0;	spin_lock(&journal_datalist_lock);	/* The buffer is already part of this transaction if	 * b_transaction or b_next_transaction points to it. */	if (jh->b_transaction == transaction ||	    jh->b_next_transaction == transaction)		goto done_locked;	/* If there is already a copy-out version of this buffer, then	 * we don't need to make another one. */	if (jh->b_frozen_data) {		JBUFFER_TRACE(jh, "has frozen data");		J_ASSERT_JH(jh, jh->b_next_transaction == NULL);		jh->b_next_transaction = transaction;		J_ASSERT_JH(jh, handle->h_buffer_credits > 0);		handle->h_buffer_credits--;		goto done_locked;	}		/* Is there data here we need to preserve? */	if (jh->b_transaction && jh->b_transaction != transaction) {		JBUFFER_TRACE(jh, "owned by older transaction");		J_ASSERT_JH(jh, jh->b_next_transaction == NULL);		J_ASSERT_JH(jh, jh->b_transaction ==					journal->j_committing_transaction);		/* There is one case we have to be very careful about.		 * If the committing transaction is currently writing		 * this buffer out to disk and has NOT made a copy-out,		 * then we cannot modify the buffer contents at all		 * right now.  The essence of copy-out is that it is the		 * extra copy, not the primary copy, which gets		 * journaled.  If the primary copy is already going to		 * disk then we cannot do copy-out here. */		if (jh->b_jlist == BJ_Shadow) {			JBUFFER_TRACE(jh, "on shadow: sleep");			spin_unlock(&journal_datalist_lock);			unlock_journal(journal);			/* commit wakes up all shadow buffers after IO */			sleep_on(&jh2bh(jh)->b_wait);			lock_journal(journal);			goto repeat;		}					/* Only do the copy if the currently-owning transaction		 * still needs it.  If it is on the Forget list, the		 * committing transaction is past that stage.  The		 * buffer had better remain locked during the kmalloc,		 * but that should be true --- we hold the journal lock		 * still and the buffer is already on the BUF_JOURNAL		 * list so won't be flushed. 		 *		 * Subtle point, though: if this is a get_undo_access,		 * then we will be relying on the frozen_data to contain		 * the new value of the committed_data record after the		 * transaction, so we HAVE to force the frozen_data copy		 * in that case. */		if (jh->b_jlist != BJ_Forget || force_copy) {			JBUFFER_TRACE(jh, "generate frozen data");			if (!frozen_buffer) {				JBUFFER_TRACE(jh, "allocate memory for buffer");				spin_unlock(&journal_datalist_lock);				unlock_journal(journal);				frozen_buffer = jbd_kmalloc(jh2bh(jh)->b_size,							    GFP_NOFS);				lock_journal(journal);				if (!frozen_buffer) {					printk(KERN_EMERG __FUNCTION__						"OOM for frozen_buffer\n");					JBUFFER_TRACE(jh, "oom!");					error = -ENOMEM;					spin_lock(&journal_datalist_lock);					goto done_locked;				}				goto repeat;			}			jh->b_frozen_data = frozen_buffer;			frozen_buffer = NULL;			need_copy = 1;		}		jh->b_next_transaction = transaction;	}	J_ASSERT(handle->h_buffer_credits > 0);	handle->h_buffer_credits--;	/* Finally, if the buffer is not journaled right now, we need to	 * make sure it doesn't get written to disk before the caller	 * actually commits the new data. */	if (!jh->b_transaction) {		JBUFFER_TRACE(jh, "no transaction");		J_ASSERT_JH(jh, !jh->b_next_transaction);		jh->b_transaction = transaction;		JBUFFER_TRACE(jh, "file as BJ_Reserved");		__journal_file_buffer(jh, transaction, BJ_Reserved);	}	done_locked:	spin_unlock(&journal_datalist_lock);	if (need_copy) {		struct page *page;		int offset;		char *source;		J_ASSERT_JH(jh, buffer_uptodate(jh2bh(jh)));		page = jh2bh(jh)->b_page;		offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;		source = kmap(page);		memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);		kunmap(page);	}		/* If we are about to journal a buffer, then any revoke pending           on it is no longer valid. */	journal_cancel_revoke(handle, jh);out_unlocked:	if (frozen_buffer)		kfree(frozen_buffer);	JBUFFER_TRACE(jh, "exit");	return error;}int journal_get_write_access (handle_t *handle, struct buffer_head *bh) {	transaction_t *transaction = handle->h_transaction;	journal_t *journal = transaction->t_journal;	struct journal_head *jh = journal_add_journal_head(bh);	int rc;	/* We do not want to get caught playing with fields which the	 * log thread also manipulates.  Make sure that the buffer	 * completes any outstanding IO before proceeding. */	lock_journal(journal);	rc = do_get_write_access(handle, jh, 0);	journal_unlock_journal_head(jh);	unlock_journal(journal);	return rc;}/* * When the user wants to journal a newly created buffer_head * (ie. getblk() returned a new buffer and we are going to populate it * manually rather than reading off disk), then we need to keep the * buffer_head locked until it has been completely filled with new * data.  In this case, we should be able to make the assertion that * the bh is not already part of an existing transaction.   *  * The buffer should already be locked by the caller by this point. * There is no lock ranking violation: it was a newly created, * unlocked buffer beforehand. */int journal_get_create_access (handle_t *handle, struct buffer_head *bh) {	transaction_t *transaction = handle->h_transaction;	journal_t *journal = transaction->t_journal;	struct journal_head *jh = journal_add_journal_head(bh);	int err;		jbd_debug(5, "journal_head %p\n", jh);	lock_journal(journal);	err = -EROFS;	if (is_handle_aborted(handle))		goto out;	err = 0;		JBUFFER_TRACE(jh, "entry");	/* The buffer may already belong to this transaction due to	 * pre-zeroing in the filesystem's new_block code.  It may also	 * be on the previous, committing transaction's lists, but it	 * HAS to be in Forget state in that case: the transaction must	 * have deleted the buffer for it to be reused here. */	J_ASSERT_JH(jh, (jh->b_transaction == transaction ||			 jh->b_transaction == NULL ||			 (jh->b_transaction == journal->j_committing_transaction &&			  jh->b_jlist == BJ_Forget)));	J_ASSERT_JH(jh, jh->b_next_transaction == NULL);	J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));	J_ASSERT_JH(jh, handle->h_buffer_credits > 0);	handle->h_buffer_credits--;	spin_lock(&journal_datalist_lock);	if (jh->b_transaction == NULL) {		jh->b_transaction = transaction;		JBUFFER_TRACE(jh, "file as BJ_Reserved");		__journal_file_buffer(jh, transaction, BJ_Reserved);		JBUFFER_TRACE(jh, "refile");		refile_buffer(jh2bh(jh));	} else if (jh->b_transaction == journal->j_committing_transaction) {		JBUFFER_TRACE(jh, "set next transaction");		jh->b_next_transaction = transaction;	}	spin_unlock(&journal_datalist_lock);

⌨️ 快捷键说明

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