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

📄 jfs_txnmgr.c

📁 jfs-2.4-1.1.7.tar.gz jfs 2.4-1.1.7 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   Copyright (C) International Business Machines Corp., 2000-2004 *   Portions Copyright (C) Christoph Hellwig, 2001-2002 * *   This program is free software;  you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or  *   (at your option) any later version. *  *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY;  without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See *   the GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program;  if not, write to the Free Software  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* *      jfs_txnmgr.c: transaction manager * * notes: * transaction starts with txBegin() and ends with txCommit() * or txAbort(). * * tlock is acquired at the time of update; * (obviate scan at commit time for xtree and dtree) * tlock and mp points to each other; * (no hashlist for mp -> tlock). * * special cases: * tlock on in-memory inode: * in-place tlock in the in-memory inode itself; * converted to page lock by iWrite() at commit time. * * tlock during write()/mmap() under anonymous transaction (tid = 0): * transferred (?) to transaction at commit time. * * use the page itself to update allocation maps * (obviate intermediate replication of allocation/deallocation data) * hold on to mp+lock thru update of maps */#include <linux/fs.h>#include <linux/vmalloc.h>#include <linux/smp_lock.h>#include <linux/completion.h>#include "jfs_incore.h"#include "jfs_filsys.h"#include "jfs_metapage.h"#include "jfs_dinode.h"#include "jfs_imap.h"#include "jfs_dmap.h"#include "jfs_superblock.h"#include "jfs_debug.h"/* *      transaction management structures */static struct {	/* tblock */	int freetid;		/* index of a free tid structure */	wait_queue_head_t freewait;	/* eventlist of free tblock */	/* tlock */	int freelock;		/* index first free lock word */	wait_queue_head_t freelockwait;	/* eventlist of free tlock */	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */	int tlocksInUse;	/* Number of tlocks in use */	int TlocksLow;		/* Indicates low number of available tlocks */	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue *//*	struct tblock *sync_queue; * Transactions waiting for data sync */	struct tblock *unlock_queue;	/* Txns waiting to be released */	struct tblock *unlock_tail;	/* Tail of unlock_queue */	struct list_head anon_list;	/* inodes having anonymous txns */	struct list_head anon_list2;	/* inodes having anonymous txns					   that couldn't be sync'ed */} TxAnchor;#ifdef CONFIG_JFS_STATISTICSstruct {	uint txBegin;	uint txBegin_barrier;	uint txBegin_lockslow;	uint txBegin_freetid;	uint txBeginAnon;	uint txBeginAnon_barrier;	uint txBeginAnon_lockslow;	uint txLockAlloc;	uint txLockAlloc_freelock;} TxStat;#endifstatic int nTxBlock = 512;	/* number of transaction blocks */struct tblock *TxBlock;	        /* transaction block table */static int nTxLock = 4096;	/* number of transaction locks */static int TxLockLWM = 4096*.4;	/* Low water mark for number of txLocks used */static int TxLockHWM = 4096*.8;	/* High water mark for number of txLocks used */struct tlock *TxLock;           /* transaction lock table *//* *      transaction management lock */static spinlock_t jfsTxnLock = SPIN_LOCK_UNLOCKED;#define TXN_LOCK()              spin_lock(&jfsTxnLock)#define TXN_UNLOCK()            spin_unlock(&jfsTxnLock)#define LAZY_LOCK_INIT()	spin_lock_init(&TxAnchor.LazyLock);#define LAZY_LOCK(flags)	spin_lock_irqsave(&TxAnchor.LazyLock, flags)#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);/* * Retry logic exist outside these macros to protect from spurrious wakeups. */static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event){	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(event, &wait);	set_current_state(TASK_UNINTERRUPTIBLE);	TXN_UNLOCK();	schedule();	current->state = TASK_RUNNING;	remove_wait_queue(event, &wait);}#define TXN_SLEEP(event)\{\	TXN_SLEEP_DROP_LOCK(event);\	TXN_LOCK();\}#define TXN_WAKEUP(event) wake_up_all(event)/* *      statistics */struct {	tid_t maxtid;		/* 4: biggest tid ever used */	lid_t maxlid;		/* 4: biggest lid ever used */	int ntid;		/* 4: # of transactions performed */	int nlid;		/* 4: # of tlocks acquired */	int waitlock;		/* 4: # of tlock wait */} stattx;/* * external references */extern int lmGroupCommit(struct jfs_log *, struct tblock *);extern void lmSync(struct jfs_log *);extern int jfs_commit_inode(struct inode *, int);extern int jfs_stop_threads;struct task_struct *jfsCommitTask;extern struct completion jfsIOwait;/* * forward references */static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,		struct tlock * tlck, struct commit * cd);static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,		struct tlock * tlck);static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,		struct tlock * tlck);static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,		struct tlock * tlck);static void txAllocPMap(struct inode *ip, struct maplock * maplock,		struct tblock * tblk);static void txForce(struct tblock * tblk);static int txLog(struct jfs_log * log, struct tblock * tblk,		struct commit * cd);static void txUpdateMap(struct tblock * tblk);static void txRelease(struct tblock * tblk);static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,	   struct tlock * tlck);static void LogSyncRelease(struct metapage * mp);/* *              transaction block/lock management *              --------------------------------- *//* * Get a transaction lock from the free list.  If the number in use is * greater than the high water mark, wake up the sync daemon.  This should * free some anonymous transaction locks.  (TXN_LOCK must be held.) */static lid_t txLockAlloc(void){	lid_t lid;	INCREMENT(TxStat.txLockAlloc);	if (!TxAnchor.freelock) {		INCREMENT(TxStat.txLockAlloc_freelock);	}	while (!(lid = TxAnchor.freelock))		TXN_SLEEP(&TxAnchor.freelockwait);	TxAnchor.freelock = TxLock[lid].next;	HIGHWATERMARK(stattx.maxlid, lid);	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TxAnchor.TlocksLow == 0)) {		jfs_info("txLockAlloc TlocksLow");		TxAnchor.TlocksLow = 1;		wake_up(&jfs_sync_thread_wait);	}	return lid;}static void txLockFree(lid_t lid){	TxLock[lid].next = TxAnchor.freelock;	TxAnchor.freelock = lid;	TxAnchor.tlocksInUse--;	if (TxAnchor.TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {		jfs_info("txLockFree TlocksLow no more");		TxAnchor.TlocksLow = 0;		TXN_WAKEUP(&TxAnchor.lowlockwait);	}	TXN_WAKEUP(&TxAnchor.freelockwait);}/* * NAME:        txInit() * * FUNCTION:    initialize transaction management structures * * RETURN: * * serialization: single thread at jfs_init() */int txInit(void){	int k, size;	/*	 * initialize transaction block (tblock) table	 *	 * transaction id (tid) = tblock index	 * tid = 0 is reserved.	 */	size = sizeof(struct tblock) * nTxBlock;	TxBlock = (struct tblock *) vmalloc(size);	if (TxBlock == NULL)		return -ENOMEM;	for (k = 1; k < nTxBlock - 1; k++) {		TxBlock[k].next = k + 1;		init_waitqueue_head(&TxBlock[k].gcwait);		init_waitqueue_head(&TxBlock[k].waitor);	}	TxBlock[k].next = 0;	init_waitqueue_head(&TxBlock[k].gcwait);	init_waitqueue_head(&TxBlock[k].waitor);	TxAnchor.freetid = 1;	init_waitqueue_head(&TxAnchor.freewait);	stattx.maxtid = 1;	/* statistics */	/*	 * initialize transaction lock (tlock) table	 *	 * transaction lock id = tlock index	 * tlock id = 0 is reserved.	 */	size = sizeof(struct tlock) * nTxLock;	TxLock = (struct tlock *) vmalloc(size);	if (TxLock == NULL) {		vfree(TxBlock);		return -ENOMEM;	}	/* initialize tlock table */	for (k = 1; k < nTxLock - 1; k++)		TxLock[k].next = k + 1;	TxLock[k].next = 0;	init_waitqueue_head(&TxAnchor.freelockwait);	init_waitqueue_head(&TxAnchor.lowlockwait);	TxAnchor.freelock = 1;	TxAnchor.tlocksInUse = 0;	INIT_LIST_HEAD(&TxAnchor.anon_list);	INIT_LIST_HEAD(&TxAnchor.anon_list2);	stattx.maxlid = 1;	/* statistics */	return 0;}/* * NAME:        txExit() * * FUNCTION:    clean up when module is unloaded */void txExit(void){	vfree(TxLock);	TxLock = 0;	vfree(TxBlock);	TxBlock = 0;}/* * NAME:        txBegin() * * FUNCTION:    start a transaction. * * PARAMETER:   sb	- superblock *              flag	- force for nested tx; * * RETURN:	tid	- transaction id * * note: flag force allows to start tx for nested tx * to prevent deadlock on logsync barrier; */tid_t txBegin(struct super_block *sb, int flag){	tid_t t;	struct tblock *tblk;	struct jfs_log *log;	jfs_info("txBegin: flag = 0x%x", flag);	log = JFS_SBI(sb)->log;	TXN_LOCK();	INCREMENT(TxStat.txBegin);      retry:	if (!(flag & COMMIT_FORCE)) {		/*		 * synchronize with logsync barrier		 */		if (test_bit(log_SYNCBARRIER, &log->flag) ||		    test_bit(log_QUIESCE, &log->flag)) {			INCREMENT(TxStat.txBegin_barrier);			TXN_SLEEP(&log->syncwait);			goto retry;		}	}	if (flag == 0) {		/*		 * Don't begin transaction if we're getting starved for tlocks		 * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately		 * free tlocks)		 */		if (TxAnchor.TlocksLow) {			INCREMENT(TxStat.txBegin_lockslow);			TXN_SLEEP(&TxAnchor.lowlockwait);			goto retry;		}	}	/*	 * allocate transaction id/block	 */	if ((t = TxAnchor.freetid) == 0) {		jfs_info("txBegin: waiting for free tid");		INCREMENT(TxStat.txBegin_freetid);		TXN_SLEEP(&TxAnchor.freewait);		goto retry;	}	tblk = tid_to_tblock(t);	if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {		/* Don't let a non-forced transaction take the last tblk */		jfs_info("txBegin: waiting for free tid");		INCREMENT(TxStat.txBegin_freetid);		TXN_SLEEP(&TxAnchor.freewait);		goto retry;	}	TxAnchor.freetid = tblk->next;	/*	 * initialize transaction	 */	/*	 * We can't zero the whole thing or we screw up another thread being	 * awakened after sleeping on tblk->waitor	 *	 * memset(tblk, 0, sizeof(struct tblock));	 */	tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;	tblk->sb = sb;	++log->logtid;	tblk->logtid = log->logtid;	++log->active;	HIGHWATERMARK(stattx.maxtid, t);	/* statistics */	INCREMENT(stattx.ntid);	/* statistics */	TXN_UNLOCK();	jfs_info("txBegin: returning tid = %d", t);	return t;}/* * NAME:        txBeginAnon() * * FUNCTION:    start an anonymous transaction. *		Blocks if logsync or available tlocks are low to prevent *		anonymous tlocks from depleting supply. * * PARAMETER:   sb	- superblock * * RETURN:	none */void txBeginAnon(struct super_block *sb){	struct jfs_log *log;	log = JFS_SBI(sb)->log;	TXN_LOCK();	INCREMENT(TxStat.txBeginAnon);      retry:	/*	 * synchronize with logsync barrier	 */	if (test_bit(log_SYNCBARRIER, &log->flag) ||	    test_bit(log_QUIESCE, &log->flag)) {		INCREMENT(TxStat.txBeginAnon_barrier);		TXN_SLEEP(&log->syncwait);		goto retry;	}	/*	 * Don't begin transaction if we're getting starved for tlocks	 */	if (TxAnchor.TlocksLow) {		INCREMENT(TxStat.txBeginAnon_lockslow);		TXN_SLEEP(&TxAnchor.lowlockwait);		goto retry;	}	TXN_UNLOCK();}/* *      txEnd() * * function: free specified transaction block. * *      logsync barrier processing: * * serialization: */void txEnd(tid_t tid){	struct tblock *tblk = tid_to_tblock(tid);	struct jfs_log *log;	jfs_info("txEnd: tid = %d", tid);	TXN_LOCK();	/*	 * wakeup transactions waiting on the page locked	 * by the current transaction	 */	TXN_WAKEUP(&tblk->waitor);	log = JFS_SBI(tblk->sb)->log;	/*	 * Lazy commit thread can't free this guy until we mark it UNLOCKED,	 * otherwise, we would be left with a transaction that may have been	 * reused.	 *	 * Lazy commit thread will turn off tblkGC_LAZY before calling this	 * routine.	 */	if (tblk->flag & tblkGC_LAZY) {		jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);		TXN_UNLOCK();		spin_lock_irq(&log->gclock);	// LOGGC_LOCK		tblk->flag |= tblkGC_UNLOCKED;		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK		return;	}	jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);	assert(tblk->next == 0);	/*	 * insert tblock back on freelist	 */	tblk->next = TxAnchor.freetid;	TxAnchor.freetid = tid;	/*	 * mark the tblock not active	 */	if (--log->active == 0) {		clear_bit(log_FLUSH, &log->flag);		/*		 * synchronize with logsync barrier		 */		if (test_bit(log_SYNCBARRIER, &log->flag)) {			/* forward log syncpt */			/* lmSync(log); */

⌨️ 快捷键说明

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