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

📄 jfs_txnmgr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   Copyright (C) International Business Machines Corp., 2000-2005 *   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/completion.h>#include <linux/freezer.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kthread.h>#include "jfs_incore.h"#include "jfs_inode.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 {	int freetid;		/* index of a free tid structure */	int freelock;		/* index first free lock word */	wait_queue_head_t freewait;	/* eventlist of free tblock */	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 */	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue *//*	struct tblock *sync_queue; * Transactions waiting for data sync */	struct list_head unlock_queue;	/* Txns waiting to be released */	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;int jfs_tlocks_low;		/* Indicates low number of available tlocks */#ifdef CONFIG_JFS_STATISTICSstatic struct {	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 = -1;	/* number of transaction blocks */module_param(nTxBlock, int, 0);MODULE_PARM_DESC(nTxBlock,		 "Number of transaction blocks (max:65536)");static int nTxLock = -1;	/* number of transaction locks */module_param(nTxLock, int, 0);MODULE_PARM_DESC(nTxLock,		 "Number of transaction locks (max:65536)");struct tblock *TxBlock;	/* transaction block table */static int TxLockLWM;	/* Low water mark for number of txLocks used */static int TxLockHWM;	/* High water mark for number of txLocks used */static int TxLockVHWM;	/* Very High water mark */struct tlock *TxLock;	/* transaction lock table *//* *	transaction management lock */static DEFINE_SPINLOCK(jfsTxnLock);#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)static DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);static int jfs_commit_thread_waking;/* * 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();	io_schedule();	__set_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 */static 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;/* * 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) && (jfs_tlocks_low == 0)) {		jfs_info("txLockAlloc tlocks low");		jfs_tlocks_low = 1;		wake_up_process(jfsSyncThread);	}	return lid;}static void txLockFree(lid_t lid){	TxLock[lid].tid = 0;	TxLock[lid].next = TxAnchor.freelock;	TxAnchor.freelock = lid;	TxAnchor.tlocksInUse--;	if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {		jfs_info("txLockFree jfs_tlocks_low no more");		jfs_tlocks_low = 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;	struct sysinfo si;	/* Set defaults for nTxLock and nTxBlock if unset */	if (nTxLock == -1) {		if (nTxBlock == -1) {			/* Base default on memory size */			si_meminfo(&si);			if (si.totalram > (256 * 1024)) /* 1 GB */				nTxLock = 64 * 1024;			else				nTxLock = si.totalram >> 2;		} else if (nTxBlock > (8 * 1024))			nTxLock = 64 * 1024;		else			nTxLock = nTxBlock << 3;	}	if (nTxBlock == -1)		nTxBlock = nTxLock >> 3;	/* Verify tunable parameters */	if (nTxBlock < 16)		nTxBlock = 16;	/* No one should set it this low */	if (nTxBlock > 65536)		nTxBlock = 65536;	if (nTxLock < 256)		nTxLock = 256;	/* No one should set it this low */	if (nTxLock > 65536)		nTxLock = 65536;	printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",	       nTxBlock, nTxLock);	/*	 * initialize transaction block (tblock) table	 *	 * transaction id (tid) = tblock index	 * tid = 0 is reserved.	 */	TxLockLWM = (nTxLock * 4) / 10;	TxLockHWM = (nTxLock * 7) / 10;	TxLockVHWM = (nTxLock * 8) / 10;	size = sizeof(struct tblock) * nTxBlock;	TxBlock = 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 = 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);	LAZY_LOCK_INIT();	INIT_LIST_HEAD(&TxAnchor.unlock_queue);	stattx.maxlid = 1;	/* statistics */	return 0;}/* * NAME:	txExit() * * FUNCTION:	clean up when module is unloaded */void txExit(void){	vfree(TxLock);	TxLock = NULL;	vfree(TxBlock);	TxBlock = NULL;}/* * 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.tlocksInUse > TxLockVHWM) {			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.tlocksInUse > TxLockVHWM) {		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

⌨️ 快捷键说明

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