162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2005
462306a36Sopenharmony_ci *   Portions Copyright (C) Christoph Hellwig, 2001-2002
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci *	jfs_txnmgr.c: transaction manager
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * notes:
1162306a36Sopenharmony_ci * transaction starts with txBegin() and ends with txCommit()
1262306a36Sopenharmony_ci * or txAbort().
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * tlock is acquired at the time of update;
1562306a36Sopenharmony_ci * (obviate scan at commit time for xtree and dtree)
1662306a36Sopenharmony_ci * tlock and mp points to each other;
1762306a36Sopenharmony_ci * (no hashlist for mp -> tlock).
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * special cases:
2062306a36Sopenharmony_ci * tlock on in-memory inode:
2162306a36Sopenharmony_ci * in-place tlock in the in-memory inode itself;
2262306a36Sopenharmony_ci * converted to page lock by iWrite() at commit time.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * tlock during write()/mmap() under anonymous transaction (tid = 0):
2562306a36Sopenharmony_ci * transferred (?) to transaction at commit time.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * use the page itself to update allocation maps
2862306a36Sopenharmony_ci * (obviate intermediate replication of allocation/deallocation data)
2962306a36Sopenharmony_ci * hold on to mp+lock thru update of maps
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/fs.h>
3362306a36Sopenharmony_ci#include <linux/vmalloc.h>
3462306a36Sopenharmony_ci#include <linux/completion.h>
3562306a36Sopenharmony_ci#include <linux/freezer.h>
3662306a36Sopenharmony_ci#include <linux/module.h>
3762306a36Sopenharmony_ci#include <linux/moduleparam.h>
3862306a36Sopenharmony_ci#include <linux/kthread.h>
3962306a36Sopenharmony_ci#include <linux/seq_file.h>
4062306a36Sopenharmony_ci#include "jfs_incore.h"
4162306a36Sopenharmony_ci#include "jfs_inode.h"
4262306a36Sopenharmony_ci#include "jfs_filsys.h"
4362306a36Sopenharmony_ci#include "jfs_metapage.h"
4462306a36Sopenharmony_ci#include "jfs_dinode.h"
4562306a36Sopenharmony_ci#include "jfs_imap.h"
4662306a36Sopenharmony_ci#include "jfs_dmap.h"
4762306a36Sopenharmony_ci#include "jfs_superblock.h"
4862306a36Sopenharmony_ci#include "jfs_debug.h"
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci *	transaction management structures
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_cistatic struct {
5462306a36Sopenharmony_ci	int freetid;		/* index of a free tid structure */
5562306a36Sopenharmony_ci	int freelock;		/* index first free lock word */
5662306a36Sopenharmony_ci	wait_queue_head_t freewait;	/* eventlist of free tblock */
5762306a36Sopenharmony_ci	wait_queue_head_t freelockwait;	/* eventlist of free tlock */
5862306a36Sopenharmony_ci	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */
5962306a36Sopenharmony_ci	int tlocksInUse;	/* Number of tlocks in use */
6062306a36Sopenharmony_ci	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue */
6162306a36Sopenharmony_ci/*	struct tblock *sync_queue; * Transactions waiting for data sync */
6262306a36Sopenharmony_ci	struct list_head unlock_queue;	/* Txns waiting to be released */
6362306a36Sopenharmony_ci	struct list_head anon_list;	/* inodes having anonymous txns */
6462306a36Sopenharmony_ci	struct list_head anon_list2;	/* inodes having anonymous txns
6562306a36Sopenharmony_ci					   that couldn't be sync'ed */
6662306a36Sopenharmony_ci} TxAnchor;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint jfs_tlocks_low;		/* Indicates low number of available tlocks */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS
7162306a36Sopenharmony_cistatic struct {
7262306a36Sopenharmony_ci	uint txBegin;
7362306a36Sopenharmony_ci	uint txBegin_barrier;
7462306a36Sopenharmony_ci	uint txBegin_lockslow;
7562306a36Sopenharmony_ci	uint txBegin_freetid;
7662306a36Sopenharmony_ci	uint txBeginAnon;
7762306a36Sopenharmony_ci	uint txBeginAnon_barrier;
7862306a36Sopenharmony_ci	uint txBeginAnon_lockslow;
7962306a36Sopenharmony_ci	uint txLockAlloc;
8062306a36Sopenharmony_ci	uint txLockAlloc_freelock;
8162306a36Sopenharmony_ci} TxStat;
8262306a36Sopenharmony_ci#endif
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int nTxBlock = -1;	/* number of transaction blocks */
8562306a36Sopenharmony_cimodule_param(nTxBlock, int, 0);
8662306a36Sopenharmony_ciMODULE_PARM_DESC(nTxBlock,
8762306a36Sopenharmony_ci		 "Number of transaction blocks (max:65536)");
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int nTxLock = -1;	/* number of transaction locks */
9062306a36Sopenharmony_cimodule_param(nTxLock, int, 0);
9162306a36Sopenharmony_ciMODULE_PARM_DESC(nTxLock,
9262306a36Sopenharmony_ci		 "Number of transaction locks (max:65536)");
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct tblock *TxBlock;	/* transaction block table */
9562306a36Sopenharmony_cistatic int TxLockLWM;	/* Low water mark for number of txLocks used */
9662306a36Sopenharmony_cistatic int TxLockHWM;	/* High water mark for number of txLocks used */
9762306a36Sopenharmony_cistatic int TxLockVHWM;	/* Very High water mark */
9862306a36Sopenharmony_cistruct tlock *TxLock;	/* transaction lock table */
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci *	transaction management lock
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(jfsTxnLock);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define TXN_LOCK()		spin_lock(&jfsTxnLock)
10662306a36Sopenharmony_ci#define TXN_UNLOCK()		spin_unlock(&jfsTxnLock)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define LAZY_LOCK_INIT()	spin_lock_init(&TxAnchor.LazyLock)
10962306a36Sopenharmony_ci#define LAZY_LOCK(flags)	spin_lock_irqsave(&TxAnchor.LazyLock, flags)
11062306a36Sopenharmony_ci#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
11362306a36Sopenharmony_cistatic int jfs_commit_thread_waking;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * Retry logic exist outside these macros to protect from spurrious wakeups.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	DECLARE_WAITQUEUE(wait, current);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	add_wait_queue(event, &wait);
12362306a36Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
12462306a36Sopenharmony_ci	TXN_UNLOCK();
12562306a36Sopenharmony_ci	io_schedule();
12662306a36Sopenharmony_ci	remove_wait_queue(event, &wait);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define TXN_SLEEP(event)\
13062306a36Sopenharmony_ci{\
13162306a36Sopenharmony_ci	TXN_SLEEP_DROP_LOCK(event);\
13262306a36Sopenharmony_ci	TXN_LOCK();\
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define TXN_WAKEUP(event) wake_up_all(event)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci *	statistics
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cistatic struct {
14162306a36Sopenharmony_ci	tid_t maxtid;		/* 4: biggest tid ever used */
14262306a36Sopenharmony_ci	lid_t maxlid;		/* 4: biggest lid ever used */
14362306a36Sopenharmony_ci	int ntid;		/* 4: # of transactions performed */
14462306a36Sopenharmony_ci	int nlid;		/* 4: # of tlocks acquired */
14562306a36Sopenharmony_ci	int waitlock;		/* 4: # of tlock wait */
14662306a36Sopenharmony_ci} stattx;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/*
14962306a36Sopenharmony_ci * forward references
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic void diLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
15262306a36Sopenharmony_ci		struct tlock *tlck, struct commit *cd);
15362306a36Sopenharmony_cistatic void dataLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
15462306a36Sopenharmony_ci		struct tlock *tlck);
15562306a36Sopenharmony_cistatic void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
15662306a36Sopenharmony_ci		struct tlock * tlck);
15762306a36Sopenharmony_cistatic void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
15862306a36Sopenharmony_ci		struct tlock * tlck);
15962306a36Sopenharmony_cistatic void txAllocPMap(struct inode *ip, struct maplock * maplock,
16062306a36Sopenharmony_ci		struct tblock * tblk);
16162306a36Sopenharmony_cistatic void txForce(struct tblock * tblk);
16262306a36Sopenharmony_cistatic void txLog(struct jfs_log *log, struct tblock *tblk,
16362306a36Sopenharmony_ci		struct commit *cd);
16462306a36Sopenharmony_cistatic void txUpdateMap(struct tblock * tblk);
16562306a36Sopenharmony_cistatic void txRelease(struct tblock * tblk);
16662306a36Sopenharmony_cistatic void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
16762306a36Sopenharmony_ci	   struct tlock * tlck);
16862306a36Sopenharmony_cistatic void LogSyncRelease(struct metapage * mp);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci *		transaction block/lock management
17262306a36Sopenharmony_ci *		---------------------------------
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * Get a transaction lock from the free list.  If the number in use is
17762306a36Sopenharmony_ci * greater than the high water mark, wake up the sync daemon.  This should
17862306a36Sopenharmony_ci * free some anonymous transaction locks.  (TXN_LOCK must be held.)
17962306a36Sopenharmony_ci */
18062306a36Sopenharmony_cistatic lid_t txLockAlloc(void)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	lid_t lid;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	INCREMENT(TxStat.txLockAlloc);
18562306a36Sopenharmony_ci	if (!TxAnchor.freelock) {
18662306a36Sopenharmony_ci		INCREMENT(TxStat.txLockAlloc_freelock);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	while (!(lid = TxAnchor.freelock))
19062306a36Sopenharmony_ci		TXN_SLEEP(&TxAnchor.freelockwait);
19162306a36Sopenharmony_ci	TxAnchor.freelock = TxLock[lid].next;
19262306a36Sopenharmony_ci	HIGHWATERMARK(stattx.maxlid, lid);
19362306a36Sopenharmony_ci	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
19462306a36Sopenharmony_ci		jfs_info("txLockAlloc tlocks low");
19562306a36Sopenharmony_ci		jfs_tlocks_low = 1;
19662306a36Sopenharmony_ci		wake_up_process(jfsSyncThread);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return lid;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void txLockFree(lid_t lid)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	TxLock[lid].tid = 0;
20562306a36Sopenharmony_ci	TxLock[lid].next = TxAnchor.freelock;
20662306a36Sopenharmony_ci	TxAnchor.freelock = lid;
20762306a36Sopenharmony_ci	TxAnchor.tlocksInUse--;
20862306a36Sopenharmony_ci	if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
20962306a36Sopenharmony_ci		jfs_info("txLockFree jfs_tlocks_low no more");
21062306a36Sopenharmony_ci		jfs_tlocks_low = 0;
21162306a36Sopenharmony_ci		TXN_WAKEUP(&TxAnchor.lowlockwait);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	TXN_WAKEUP(&TxAnchor.freelockwait);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/*
21762306a36Sopenharmony_ci * NAME:	txInit()
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * FUNCTION:	initialize transaction management structures
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * RETURN:
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * serialization: single thread at jfs_init()
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_ciint txInit(void)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	int k, size;
22862306a36Sopenharmony_ci	struct sysinfo si;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* Set defaults for nTxLock and nTxBlock if unset */
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (nTxLock == -1) {
23362306a36Sopenharmony_ci		if (nTxBlock == -1) {
23462306a36Sopenharmony_ci			/* Base default on memory size */
23562306a36Sopenharmony_ci			si_meminfo(&si);
23662306a36Sopenharmony_ci			if (si.totalram > (256 * 1024)) /* 1 GB */
23762306a36Sopenharmony_ci				nTxLock = 64 * 1024;
23862306a36Sopenharmony_ci			else
23962306a36Sopenharmony_ci				nTxLock = si.totalram >> 2;
24062306a36Sopenharmony_ci		} else if (nTxBlock > (8 * 1024))
24162306a36Sopenharmony_ci			nTxLock = 64 * 1024;
24262306a36Sopenharmony_ci		else
24362306a36Sopenharmony_ci			nTxLock = nTxBlock << 3;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	if (nTxBlock == -1)
24662306a36Sopenharmony_ci		nTxBlock = nTxLock >> 3;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Verify tunable parameters */
24962306a36Sopenharmony_ci	if (nTxBlock < 16)
25062306a36Sopenharmony_ci		nTxBlock = 16;	/* No one should set it this low */
25162306a36Sopenharmony_ci	if (nTxBlock > 65536)
25262306a36Sopenharmony_ci		nTxBlock = 65536;
25362306a36Sopenharmony_ci	if (nTxLock < 256)
25462306a36Sopenharmony_ci		nTxLock = 256;	/* No one should set it this low */
25562306a36Sopenharmony_ci	if (nTxLock > 65536)
25662306a36Sopenharmony_ci		nTxLock = 65536;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
25962306a36Sopenharmony_ci	       nTxBlock, nTxLock);
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * initialize transaction block (tblock) table
26262306a36Sopenharmony_ci	 *
26362306a36Sopenharmony_ci	 * transaction id (tid) = tblock index
26462306a36Sopenharmony_ci	 * tid = 0 is reserved.
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	TxLockLWM = (nTxLock * 4) / 10;
26762306a36Sopenharmony_ci	TxLockHWM = (nTxLock * 7) / 10;
26862306a36Sopenharmony_ci	TxLockVHWM = (nTxLock * 8) / 10;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	size = sizeof(struct tblock) * nTxBlock;
27162306a36Sopenharmony_ci	TxBlock = vmalloc(size);
27262306a36Sopenharmony_ci	if (TxBlock == NULL)
27362306a36Sopenharmony_ci		return -ENOMEM;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	for (k = 1; k < nTxBlock - 1; k++) {
27662306a36Sopenharmony_ci		TxBlock[k].next = k + 1;
27762306a36Sopenharmony_ci		init_waitqueue_head(&TxBlock[k].gcwait);
27862306a36Sopenharmony_ci		init_waitqueue_head(&TxBlock[k].waitor);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	TxBlock[k].next = 0;
28162306a36Sopenharmony_ci	init_waitqueue_head(&TxBlock[k].gcwait);
28262306a36Sopenharmony_ci	init_waitqueue_head(&TxBlock[k].waitor);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	TxAnchor.freetid = 1;
28562306a36Sopenharmony_ci	init_waitqueue_head(&TxAnchor.freewait);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	stattx.maxtid = 1;	/* statistics */
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/*
29062306a36Sopenharmony_ci	 * initialize transaction lock (tlock) table
29162306a36Sopenharmony_ci	 *
29262306a36Sopenharmony_ci	 * transaction lock id = tlock index
29362306a36Sopenharmony_ci	 * tlock id = 0 is reserved.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	size = sizeof(struct tlock) * nTxLock;
29662306a36Sopenharmony_ci	TxLock = vmalloc(size);
29762306a36Sopenharmony_ci	if (TxLock == NULL) {
29862306a36Sopenharmony_ci		vfree(TxBlock);
29962306a36Sopenharmony_ci		return -ENOMEM;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* initialize tlock table */
30362306a36Sopenharmony_ci	for (k = 1; k < nTxLock - 1; k++)
30462306a36Sopenharmony_ci		TxLock[k].next = k + 1;
30562306a36Sopenharmony_ci	TxLock[k].next = 0;
30662306a36Sopenharmony_ci	init_waitqueue_head(&TxAnchor.freelockwait);
30762306a36Sopenharmony_ci	init_waitqueue_head(&TxAnchor.lowlockwait);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	TxAnchor.freelock = 1;
31062306a36Sopenharmony_ci	TxAnchor.tlocksInUse = 0;
31162306a36Sopenharmony_ci	INIT_LIST_HEAD(&TxAnchor.anon_list);
31262306a36Sopenharmony_ci	INIT_LIST_HEAD(&TxAnchor.anon_list2);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	LAZY_LOCK_INIT();
31562306a36Sopenharmony_ci	INIT_LIST_HEAD(&TxAnchor.unlock_queue);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	stattx.maxlid = 1;	/* statistics */
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/*
32362306a36Sopenharmony_ci * NAME:	txExit()
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * FUNCTION:	clean up when module is unloaded
32662306a36Sopenharmony_ci */
32762306a36Sopenharmony_civoid txExit(void)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	vfree(TxLock);
33062306a36Sopenharmony_ci	TxLock = NULL;
33162306a36Sopenharmony_ci	vfree(TxBlock);
33262306a36Sopenharmony_ci	TxBlock = NULL;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/*
33662306a36Sopenharmony_ci * NAME:	txBegin()
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * FUNCTION:	start a transaction.
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * PARAMETER:	sb	- superblock
34162306a36Sopenharmony_ci *		flag	- force for nested tx;
34262306a36Sopenharmony_ci *
34362306a36Sopenharmony_ci * RETURN:	tid	- transaction id
34462306a36Sopenharmony_ci *
34562306a36Sopenharmony_ci * note: flag force allows to start tx for nested tx
34662306a36Sopenharmony_ci * to prevent deadlock on logsync barrier;
34762306a36Sopenharmony_ci */
34862306a36Sopenharmony_citid_t txBegin(struct super_block *sb, int flag)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	tid_t t;
35162306a36Sopenharmony_ci	struct tblock *tblk;
35262306a36Sopenharmony_ci	struct jfs_log *log;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	jfs_info("txBegin: flag = 0x%x", flag);
35562306a36Sopenharmony_ci	log = JFS_SBI(sb)->log;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (!log) {
35862306a36Sopenharmony_ci		jfs_error(sb, "read-only filesystem\n");
35962306a36Sopenharmony_ci		return 0;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	TXN_LOCK();
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	INCREMENT(TxStat.txBegin);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci      retry:
36762306a36Sopenharmony_ci	if (!(flag & COMMIT_FORCE)) {
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * synchronize with logsync barrier
37062306a36Sopenharmony_ci		 */
37162306a36Sopenharmony_ci		if (test_bit(log_SYNCBARRIER, &log->flag) ||
37262306a36Sopenharmony_ci		    test_bit(log_QUIESCE, &log->flag)) {
37362306a36Sopenharmony_ci			INCREMENT(TxStat.txBegin_barrier);
37462306a36Sopenharmony_ci			TXN_SLEEP(&log->syncwait);
37562306a36Sopenharmony_ci			goto retry;
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	if (flag == 0) {
37962306a36Sopenharmony_ci		/*
38062306a36Sopenharmony_ci		 * Don't begin transaction if we're getting starved for tlocks
38162306a36Sopenharmony_ci		 * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
38262306a36Sopenharmony_ci		 * free tlocks)
38362306a36Sopenharmony_ci		 */
38462306a36Sopenharmony_ci		if (TxAnchor.tlocksInUse > TxLockVHWM) {
38562306a36Sopenharmony_ci			INCREMENT(TxStat.txBegin_lockslow);
38662306a36Sopenharmony_ci			TXN_SLEEP(&TxAnchor.lowlockwait);
38762306a36Sopenharmony_ci			goto retry;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * allocate transaction id/block
39362306a36Sopenharmony_ci	 */
39462306a36Sopenharmony_ci	if ((t = TxAnchor.freetid) == 0) {
39562306a36Sopenharmony_ci		jfs_info("txBegin: waiting for free tid");
39662306a36Sopenharmony_ci		INCREMENT(TxStat.txBegin_freetid);
39762306a36Sopenharmony_ci		TXN_SLEEP(&TxAnchor.freewait);
39862306a36Sopenharmony_ci		goto retry;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	tblk = tid_to_tblock(t);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
40462306a36Sopenharmony_ci		/* Don't let a non-forced transaction take the last tblk */
40562306a36Sopenharmony_ci		jfs_info("txBegin: waiting for free tid");
40662306a36Sopenharmony_ci		INCREMENT(TxStat.txBegin_freetid);
40762306a36Sopenharmony_ci		TXN_SLEEP(&TxAnchor.freewait);
40862306a36Sopenharmony_ci		goto retry;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	TxAnchor.freetid = tblk->next;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/*
41462306a36Sopenharmony_ci	 * initialize transaction
41562306a36Sopenharmony_ci	 */
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/*
41862306a36Sopenharmony_ci	 * We can't zero the whole thing or we screw up another thread being
41962306a36Sopenharmony_ci	 * awakened after sleeping on tblk->waitor
42062306a36Sopenharmony_ci	 *
42162306a36Sopenharmony_ci	 * memset(tblk, 0, sizeof(struct tblock));
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	tblk->sb = sb;
42662306a36Sopenharmony_ci	++log->logtid;
42762306a36Sopenharmony_ci	tblk->logtid = log->logtid;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	++log->active;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	HIGHWATERMARK(stattx.maxtid, t);	/* statistics */
43262306a36Sopenharmony_ci	INCREMENT(stattx.ntid);	/* statistics */
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	TXN_UNLOCK();
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	jfs_info("txBegin: returning tid = %d", t);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return t;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci * NAME:	txBeginAnon()
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci * FUNCTION:	start an anonymous transaction.
44562306a36Sopenharmony_ci *		Blocks if logsync or available tlocks are low to prevent
44662306a36Sopenharmony_ci *		anonymous tlocks from depleting supply.
44762306a36Sopenharmony_ci *
44862306a36Sopenharmony_ci * PARAMETER:	sb	- superblock
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * RETURN:	none
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_civoid txBeginAnon(struct super_block *sb)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct jfs_log *log;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	log = JFS_SBI(sb)->log;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	TXN_LOCK();
45962306a36Sopenharmony_ci	INCREMENT(TxStat.txBeginAnon);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci      retry:
46262306a36Sopenharmony_ci	/*
46362306a36Sopenharmony_ci	 * synchronize with logsync barrier
46462306a36Sopenharmony_ci	 */
46562306a36Sopenharmony_ci	if (test_bit(log_SYNCBARRIER, &log->flag) ||
46662306a36Sopenharmony_ci	    test_bit(log_QUIESCE, &log->flag)) {
46762306a36Sopenharmony_ci		INCREMENT(TxStat.txBeginAnon_barrier);
46862306a36Sopenharmony_ci		TXN_SLEEP(&log->syncwait);
46962306a36Sopenharmony_ci		goto retry;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/*
47362306a36Sopenharmony_ci	 * Don't begin transaction if we're getting starved for tlocks
47462306a36Sopenharmony_ci	 */
47562306a36Sopenharmony_ci	if (TxAnchor.tlocksInUse > TxLockVHWM) {
47662306a36Sopenharmony_ci		INCREMENT(TxStat.txBeginAnon_lockslow);
47762306a36Sopenharmony_ci		TXN_SLEEP(&TxAnchor.lowlockwait);
47862306a36Sopenharmony_ci		goto retry;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci	TXN_UNLOCK();
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci/*
48462306a36Sopenharmony_ci *	txEnd()
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * function: free specified transaction block.
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci *	logsync barrier processing:
48962306a36Sopenharmony_ci *
49062306a36Sopenharmony_ci * serialization:
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_civoid txEnd(tid_t tid)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct tblock *tblk = tid_to_tblock(tid);
49562306a36Sopenharmony_ci	struct jfs_log *log;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	jfs_info("txEnd: tid = %d", tid);
49862306a36Sopenharmony_ci	TXN_LOCK();
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/*
50162306a36Sopenharmony_ci	 * wakeup transactions waiting on the page locked
50262306a36Sopenharmony_ci	 * by the current transaction
50362306a36Sopenharmony_ci	 */
50462306a36Sopenharmony_ci	TXN_WAKEUP(&tblk->waitor);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	log = JFS_SBI(tblk->sb)->log;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/*
50962306a36Sopenharmony_ci	 * Lazy commit thread can't free this guy until we mark it UNLOCKED,
51062306a36Sopenharmony_ci	 * otherwise, we would be left with a transaction that may have been
51162306a36Sopenharmony_ci	 * reused.
51262306a36Sopenharmony_ci	 *
51362306a36Sopenharmony_ci	 * Lazy commit thread will turn off tblkGC_LAZY before calling this
51462306a36Sopenharmony_ci	 * routine.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci	if (tblk->flag & tblkGC_LAZY) {
51762306a36Sopenharmony_ci		jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
51862306a36Sopenharmony_ci		TXN_UNLOCK();
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		spin_lock_irq(&log->gclock);	// LOGGC_LOCK
52162306a36Sopenharmony_ci		tblk->flag |= tblkGC_UNLOCKED;
52262306a36Sopenharmony_ci		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
52362306a36Sopenharmony_ci		return;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	assert(tblk->next == 0);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/*
53162306a36Sopenharmony_ci	 * insert tblock back on freelist
53262306a36Sopenharmony_ci	 */
53362306a36Sopenharmony_ci	tblk->next = TxAnchor.freetid;
53462306a36Sopenharmony_ci	TxAnchor.freetid = tid;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/*
53762306a36Sopenharmony_ci	 * mark the tblock not active
53862306a36Sopenharmony_ci	 */
53962306a36Sopenharmony_ci	if (--log->active == 0) {
54062306a36Sopenharmony_ci		clear_bit(log_FLUSH, &log->flag);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		/*
54362306a36Sopenharmony_ci		 * synchronize with logsync barrier
54462306a36Sopenharmony_ci		 */
54562306a36Sopenharmony_ci		if (test_bit(log_SYNCBARRIER, &log->flag)) {
54662306a36Sopenharmony_ci			TXN_UNLOCK();
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci			/* write dirty metadata & forward log syncpt */
54962306a36Sopenharmony_ci			jfs_syncpt(log, 1);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci			jfs_info("log barrier off: 0x%x", log->lsn);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			/* enable new transactions start */
55462306a36Sopenharmony_ci			clear_bit(log_SYNCBARRIER, &log->flag);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci			/* wakeup all waitors for logsync barrier */
55762306a36Sopenharmony_ci			TXN_WAKEUP(&log->syncwait);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci			goto wakeup;
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	TXN_UNLOCK();
56462306a36Sopenharmony_ciwakeup:
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * wakeup all waitors for a free tblock
56762306a36Sopenharmony_ci	 */
56862306a36Sopenharmony_ci	TXN_WAKEUP(&TxAnchor.freewait);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/*
57262306a36Sopenharmony_ci *	txLock()
57362306a36Sopenharmony_ci *
57462306a36Sopenharmony_ci * function: acquire a transaction lock on the specified <mp>
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci * parameter:
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * return:	transaction lock id
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * serialization:
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistruct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
58362306a36Sopenharmony_ci		     int type)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
58662306a36Sopenharmony_ci	int dir_xtree = 0;
58762306a36Sopenharmony_ci	lid_t lid;
58862306a36Sopenharmony_ci	tid_t xtid;
58962306a36Sopenharmony_ci	struct tlock *tlck;
59062306a36Sopenharmony_ci	struct xtlock *xtlck;
59162306a36Sopenharmony_ci	struct linelock *linelock;
59262306a36Sopenharmony_ci	xtpage_t *p;
59362306a36Sopenharmony_ci	struct tblock *tblk;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	TXN_LOCK();
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
59862306a36Sopenharmony_ci	    !(mp->xflag & COMMIT_PAGE)) {
59962306a36Sopenharmony_ci		/*
60062306a36Sopenharmony_ci		 * Directory inode is special.  It can have both an xtree tlock
60162306a36Sopenharmony_ci		 * and a dtree tlock associated with it.
60262306a36Sopenharmony_ci		 */
60362306a36Sopenharmony_ci		dir_xtree = 1;
60462306a36Sopenharmony_ci		lid = jfs_ip->xtlid;
60562306a36Sopenharmony_ci	} else
60662306a36Sopenharmony_ci		lid = mp->lid;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* is page not locked by a transaction ? */
60962306a36Sopenharmony_ci	if (lid == 0)
61062306a36Sopenharmony_ci		goto allocateLock;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* is page locked by the requester transaction ? */
61562306a36Sopenharmony_ci	tlck = lid_to_tlock(lid);
61662306a36Sopenharmony_ci	if ((xtid = tlck->tid) == tid) {
61762306a36Sopenharmony_ci		TXN_UNLOCK();
61862306a36Sopenharmony_ci		goto grantLock;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/*
62262306a36Sopenharmony_ci	 * is page locked by anonymous transaction/lock ?
62362306a36Sopenharmony_ci	 *
62462306a36Sopenharmony_ci	 * (page update without transaction (i.e., file write) is
62562306a36Sopenharmony_ci	 * locked under anonymous transaction tid = 0:
62662306a36Sopenharmony_ci	 * anonymous tlocks maintained on anonymous tlock list of
62762306a36Sopenharmony_ci	 * the inode of the page and available to all anonymous
62862306a36Sopenharmony_ci	 * transactions until txCommit() time at which point
62962306a36Sopenharmony_ci	 * they are transferred to the transaction tlock list of
63062306a36Sopenharmony_ci	 * the committing transaction of the inode)
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	if (xtid == 0) {
63362306a36Sopenharmony_ci		tlck->tid = tid;
63462306a36Sopenharmony_ci		TXN_UNLOCK();
63562306a36Sopenharmony_ci		tblk = tid_to_tblock(tid);
63662306a36Sopenharmony_ci		/*
63762306a36Sopenharmony_ci		 * The order of the tlocks in the transaction is important
63862306a36Sopenharmony_ci		 * (during truncate, child xtree pages must be freed before
63962306a36Sopenharmony_ci		 * parent's tlocks change the working map).
64062306a36Sopenharmony_ci		 * Take tlock off anonymous list and add to tail of
64162306a36Sopenharmony_ci		 * transaction list
64262306a36Sopenharmony_ci		 *
64362306a36Sopenharmony_ci		 * Note:  We really need to get rid of the tid & lid and
64462306a36Sopenharmony_ci		 * use list_head's.  This code is getting UGLY!
64562306a36Sopenharmony_ci		 */
64662306a36Sopenharmony_ci		if (jfs_ip->atlhead == lid) {
64762306a36Sopenharmony_ci			if (jfs_ip->atltail == lid) {
64862306a36Sopenharmony_ci				/* only anonymous txn.
64962306a36Sopenharmony_ci				 * Remove from anon_list
65062306a36Sopenharmony_ci				 */
65162306a36Sopenharmony_ci				TXN_LOCK();
65262306a36Sopenharmony_ci				list_del_init(&jfs_ip->anon_inode_list);
65362306a36Sopenharmony_ci				TXN_UNLOCK();
65462306a36Sopenharmony_ci			}
65562306a36Sopenharmony_ci			jfs_ip->atlhead = tlck->next;
65662306a36Sopenharmony_ci		} else {
65762306a36Sopenharmony_ci			lid_t last;
65862306a36Sopenharmony_ci			for (last = jfs_ip->atlhead;
65962306a36Sopenharmony_ci			     lid_to_tlock(last)->next != lid;
66062306a36Sopenharmony_ci			     last = lid_to_tlock(last)->next) {
66162306a36Sopenharmony_ci				assert(last);
66262306a36Sopenharmony_ci			}
66362306a36Sopenharmony_ci			lid_to_tlock(last)->next = tlck->next;
66462306a36Sopenharmony_ci			if (jfs_ip->atltail == lid)
66562306a36Sopenharmony_ci				jfs_ip->atltail = last;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		/* insert the tlock at tail of transaction tlock list */
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (tblk->next)
67162306a36Sopenharmony_ci			lid_to_tlock(tblk->last)->next = lid;
67262306a36Sopenharmony_ci		else
67362306a36Sopenharmony_ci			tblk->next = lid;
67462306a36Sopenharmony_ci		tlck->next = 0;
67562306a36Sopenharmony_ci		tblk->last = lid;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci		goto grantLock;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	goto waitLock;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/*
68362306a36Sopenharmony_ci	 * allocate a tlock
68462306a36Sopenharmony_ci	 */
68562306a36Sopenharmony_ci      allocateLock:
68662306a36Sopenharmony_ci	lid = txLockAlloc();
68762306a36Sopenharmony_ci	tlck = lid_to_tlock(lid);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/*
69062306a36Sopenharmony_ci	 * initialize tlock
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci	tlck->tid = tid;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	TXN_UNLOCK();
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* mark tlock for meta-data page */
69762306a36Sopenharmony_ci	if (mp->xflag & COMMIT_PAGE) {
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		tlck->flag = tlckPAGELOCK;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		/* mark the page dirty and nohomeok */
70262306a36Sopenharmony_ci		metapage_nohomeok(mp);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
70562306a36Sopenharmony_ci			 mp, mp->nohomeok, tid, tlck);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		/* if anonymous transaction, and buffer is on the group
70862306a36Sopenharmony_ci		 * commit synclist, mark inode to show this.  This will
70962306a36Sopenharmony_ci		 * prevent the buffer from being marked nohomeok for too
71062306a36Sopenharmony_ci		 * long a time.
71162306a36Sopenharmony_ci		 */
71262306a36Sopenharmony_ci		if ((tid == 0) && mp->lsn)
71362306a36Sopenharmony_ci			set_cflag(COMMIT_Synclist, ip);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci	/* mark tlock for in-memory inode */
71662306a36Sopenharmony_ci	else
71762306a36Sopenharmony_ci		tlck->flag = tlckINODELOCK;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (S_ISDIR(ip->i_mode))
72062306a36Sopenharmony_ci		tlck->flag |= tlckDIRECTORY;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	tlck->type = 0;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* bind the tlock and the page */
72562306a36Sopenharmony_ci	tlck->ip = ip;
72662306a36Sopenharmony_ci	tlck->mp = mp;
72762306a36Sopenharmony_ci	if (dir_xtree)
72862306a36Sopenharmony_ci		jfs_ip->xtlid = lid;
72962306a36Sopenharmony_ci	else
73062306a36Sopenharmony_ci		mp->lid = lid;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/*
73362306a36Sopenharmony_ci	 * enqueue transaction lock to transaction/inode
73462306a36Sopenharmony_ci	 */
73562306a36Sopenharmony_ci	/* insert the tlock at tail of transaction tlock list */
73662306a36Sopenharmony_ci	if (tid) {
73762306a36Sopenharmony_ci		tblk = tid_to_tblock(tid);
73862306a36Sopenharmony_ci		if (tblk->next)
73962306a36Sopenharmony_ci			lid_to_tlock(tblk->last)->next = lid;
74062306a36Sopenharmony_ci		else
74162306a36Sopenharmony_ci			tblk->next = lid;
74262306a36Sopenharmony_ci		tlck->next = 0;
74362306a36Sopenharmony_ci		tblk->last = lid;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	/* anonymous transaction:
74662306a36Sopenharmony_ci	 * insert the tlock at head of inode anonymous tlock list
74762306a36Sopenharmony_ci	 */
74862306a36Sopenharmony_ci	else {
74962306a36Sopenharmony_ci		tlck->next = jfs_ip->atlhead;
75062306a36Sopenharmony_ci		jfs_ip->atlhead = lid;
75162306a36Sopenharmony_ci		if (tlck->next == 0) {
75262306a36Sopenharmony_ci			/* This inode's first anonymous transaction */
75362306a36Sopenharmony_ci			jfs_ip->atltail = lid;
75462306a36Sopenharmony_ci			TXN_LOCK();
75562306a36Sopenharmony_ci			list_add_tail(&jfs_ip->anon_inode_list,
75662306a36Sopenharmony_ci				      &TxAnchor.anon_list);
75762306a36Sopenharmony_ci			TXN_UNLOCK();
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/* initialize type dependent area for linelock */
76262306a36Sopenharmony_ci	linelock = (struct linelock *) & tlck->lock;
76362306a36Sopenharmony_ci	linelock->next = 0;
76462306a36Sopenharmony_ci	linelock->flag = tlckLINELOCK;
76562306a36Sopenharmony_ci	linelock->maxcnt = TLOCKSHORT;
76662306a36Sopenharmony_ci	linelock->index = 0;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	switch (type & tlckTYPE) {
76962306a36Sopenharmony_ci	case tlckDTREE:
77062306a36Sopenharmony_ci		linelock->l2linesize = L2DTSLOTSIZE;
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	case tlckXTREE:
77462306a36Sopenharmony_ci		linelock->l2linesize = L2XTSLOTSIZE;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		xtlck = (struct xtlock *) linelock;
77762306a36Sopenharmony_ci		xtlck->header.offset = 0;
77862306a36Sopenharmony_ci		xtlck->header.length = 2;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		if (type & tlckNEW) {
78162306a36Sopenharmony_ci			xtlck->lwm.offset = XTENTRYSTART;
78262306a36Sopenharmony_ci		} else {
78362306a36Sopenharmony_ci			if (mp->xflag & COMMIT_PAGE)
78462306a36Sopenharmony_ci				p = (xtpage_t *) mp->data;
78562306a36Sopenharmony_ci			else
78662306a36Sopenharmony_ci				p = &jfs_ip->i_xtroot;
78762306a36Sopenharmony_ci			xtlck->lwm.offset =
78862306a36Sopenharmony_ci			    le16_to_cpu(p->header.nextindex);
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci		xtlck->lwm.length = 0;	/* ! */
79162306a36Sopenharmony_ci		xtlck->twm.offset = 0;
79262306a36Sopenharmony_ci		xtlck->hwm.offset = 0;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		xtlck->index = 2;
79562306a36Sopenharmony_ci		break;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	case tlckINODE:
79862306a36Sopenharmony_ci		linelock->l2linesize = L2INODESLOTSIZE;
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	case tlckDATA:
80262306a36Sopenharmony_ci		linelock->l2linesize = L2DATASLOTSIZE;
80362306a36Sopenharmony_ci		break;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	default:
80662306a36Sopenharmony_ci		jfs_err("UFO tlock:0x%p", tlck);
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/*
81062306a36Sopenharmony_ci	 * update tlock vector
81162306a36Sopenharmony_ci	 */
81262306a36Sopenharmony_ci      grantLock:
81362306a36Sopenharmony_ci	tlck->type |= type;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	return tlck;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * page is being locked by another transaction:
81962306a36Sopenharmony_ci	 */
82062306a36Sopenharmony_ci      waitLock:
82162306a36Sopenharmony_ci	/* Only locks on ipimap or ipaimap should reach here */
82262306a36Sopenharmony_ci	/* assert(jfs_ip->fileset == AGGREGATE_I); */
82362306a36Sopenharmony_ci	if (jfs_ip->fileset != AGGREGATE_I) {
82462306a36Sopenharmony_ci		printk(KERN_ERR "txLock: trying to lock locked page!");
82562306a36Sopenharmony_ci		print_hex_dump(KERN_ERR, "ip: ", DUMP_PREFIX_ADDRESS, 16, 4,
82662306a36Sopenharmony_ci			       ip, sizeof(*ip), 0);
82762306a36Sopenharmony_ci		print_hex_dump(KERN_ERR, "mp: ", DUMP_PREFIX_ADDRESS, 16, 4,
82862306a36Sopenharmony_ci			       mp, sizeof(*mp), 0);
82962306a36Sopenharmony_ci		print_hex_dump(KERN_ERR, "Locker's tblock: ",
83062306a36Sopenharmony_ci			       DUMP_PREFIX_ADDRESS, 16, 4, tid_to_tblock(tid),
83162306a36Sopenharmony_ci			       sizeof(struct tblock), 0);
83262306a36Sopenharmony_ci		print_hex_dump(KERN_ERR, "Tlock: ", DUMP_PREFIX_ADDRESS, 16, 4,
83362306a36Sopenharmony_ci			       tlck, sizeof(*tlck), 0);
83462306a36Sopenharmony_ci		BUG();
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci	INCREMENT(stattx.waitlock);	/* statistics */
83762306a36Sopenharmony_ci	TXN_UNLOCK();
83862306a36Sopenharmony_ci	release_metapage(mp);
83962306a36Sopenharmony_ci	TXN_LOCK();
84062306a36Sopenharmony_ci	xtid = tlck->tid;	/* reacquire after dropping TXN_LOCK */
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
84362306a36Sopenharmony_ci		 tid, xtid, lid);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	/* Recheck everything since dropping TXN_LOCK */
84662306a36Sopenharmony_ci	if (xtid && (tlck->mp == mp) && (mp->lid == lid))
84762306a36Sopenharmony_ci		TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
84862306a36Sopenharmony_ci	else
84962306a36Sopenharmony_ci		TXN_UNLOCK();
85062306a36Sopenharmony_ci	jfs_info("txLock: awakened     tid = %d, lid = %d", tid, lid);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return NULL;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/*
85662306a36Sopenharmony_ci * NAME:	txRelease()
85762306a36Sopenharmony_ci *
85862306a36Sopenharmony_ci * FUNCTION:	Release buffers associated with transaction locks, but don't
85962306a36Sopenharmony_ci *		mark homeok yet.  The allows other transactions to modify
86062306a36Sopenharmony_ci *		buffers, but won't let them go to disk until commit record
86162306a36Sopenharmony_ci *		actually gets written.
86262306a36Sopenharmony_ci *
86362306a36Sopenharmony_ci * PARAMETER:
86462306a36Sopenharmony_ci *		tblk	-
86562306a36Sopenharmony_ci *
86662306a36Sopenharmony_ci * RETURN:	Errors from subroutines.
86762306a36Sopenharmony_ci */
86862306a36Sopenharmony_cistatic void txRelease(struct tblock * tblk)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	struct metapage *mp;
87162306a36Sopenharmony_ci	lid_t lid;
87262306a36Sopenharmony_ci	struct tlock *tlck;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	TXN_LOCK();
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = tlck->next) {
87762306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
87862306a36Sopenharmony_ci		if ((mp = tlck->mp) != NULL &&
87962306a36Sopenharmony_ci		    (tlck->type & tlckBTROOT) == 0) {
88062306a36Sopenharmony_ci			assert(mp->xflag & COMMIT_PAGE);
88162306a36Sopenharmony_ci			mp->lid = 0;
88262306a36Sopenharmony_ci		}
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/*
88662306a36Sopenharmony_ci	 * wakeup transactions waiting on a page locked
88762306a36Sopenharmony_ci	 * by the current transaction
88862306a36Sopenharmony_ci	 */
88962306a36Sopenharmony_ci	TXN_WAKEUP(&tblk->waitor);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	TXN_UNLOCK();
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci/*
89562306a36Sopenharmony_ci * NAME:	txUnlock()
89662306a36Sopenharmony_ci *
89762306a36Sopenharmony_ci * FUNCTION:	Initiates pageout of pages modified by tid in journalled
89862306a36Sopenharmony_ci *		objects and frees their lockwords.
89962306a36Sopenharmony_ci */
90062306a36Sopenharmony_cistatic void txUnlock(struct tblock * tblk)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct tlock *tlck;
90362306a36Sopenharmony_ci	struct linelock *linelock;
90462306a36Sopenharmony_ci	lid_t lid, next, llid, k;
90562306a36Sopenharmony_ci	struct metapage *mp;
90662306a36Sopenharmony_ci	struct jfs_log *log;
90762306a36Sopenharmony_ci	int difft, diffp;
90862306a36Sopenharmony_ci	unsigned long flags;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	jfs_info("txUnlock: tblk = 0x%p", tblk);
91162306a36Sopenharmony_ci	log = JFS_SBI(tblk->sb)->log;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/*
91462306a36Sopenharmony_ci	 * mark page under tlock homeok (its log has been written):
91562306a36Sopenharmony_ci	 */
91662306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = next) {
91762306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
91862306a36Sopenharmony_ci		next = tlck->next;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci		/* unbind page from tlock */
92362306a36Sopenharmony_ci		if ((mp = tlck->mp) != NULL &&
92462306a36Sopenharmony_ci		    (tlck->type & tlckBTROOT) == 0) {
92562306a36Sopenharmony_ci			assert(mp->xflag & COMMIT_PAGE);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci			/* hold buffer
92862306a36Sopenharmony_ci			 */
92962306a36Sopenharmony_ci			hold_metapage(mp);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci			assert(mp->nohomeok > 0);
93262306a36Sopenharmony_ci			_metapage_homeok(mp);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci			/* inherit younger/larger clsn */
93562306a36Sopenharmony_ci			LOGSYNC_LOCK(log, flags);
93662306a36Sopenharmony_ci			if (mp->clsn) {
93762306a36Sopenharmony_ci				logdiff(difft, tblk->clsn, log);
93862306a36Sopenharmony_ci				logdiff(diffp, mp->clsn, log);
93962306a36Sopenharmony_ci				if (difft > diffp)
94062306a36Sopenharmony_ci					mp->clsn = tblk->clsn;
94162306a36Sopenharmony_ci			} else
94262306a36Sopenharmony_ci				mp->clsn = tblk->clsn;
94362306a36Sopenharmony_ci			LOGSYNC_UNLOCK(log, flags);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci			assert(!(tlck->flag & tlckFREEPAGE));
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci			put_metapage(mp);
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		/* insert tlock, and linelock(s) of the tlock if any,
95162306a36Sopenharmony_ci		 * at head of freelist
95262306a36Sopenharmony_ci		 */
95362306a36Sopenharmony_ci		TXN_LOCK();
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		llid = ((struct linelock *) & tlck->lock)->next;
95662306a36Sopenharmony_ci		while (llid) {
95762306a36Sopenharmony_ci			linelock = (struct linelock *) lid_to_tlock(llid);
95862306a36Sopenharmony_ci			k = linelock->next;
95962306a36Sopenharmony_ci			txLockFree(llid);
96062306a36Sopenharmony_ci			llid = k;
96162306a36Sopenharmony_ci		}
96262306a36Sopenharmony_ci		txLockFree(lid);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		TXN_UNLOCK();
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci	tblk->next = tblk->last = 0;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/*
96962306a36Sopenharmony_ci	 * remove tblock from logsynclist
97062306a36Sopenharmony_ci	 * (allocation map pages inherited lsn of tblk and
97162306a36Sopenharmony_ci	 * has been inserted in logsync list at txUpdateMap())
97262306a36Sopenharmony_ci	 */
97362306a36Sopenharmony_ci	if (tblk->lsn) {
97462306a36Sopenharmony_ci		LOGSYNC_LOCK(log, flags);
97562306a36Sopenharmony_ci		log->count--;
97662306a36Sopenharmony_ci		list_del(&tblk->synclist);
97762306a36Sopenharmony_ci		LOGSYNC_UNLOCK(log, flags);
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci/*
98262306a36Sopenharmony_ci *	txMaplock()
98362306a36Sopenharmony_ci *
98462306a36Sopenharmony_ci * function: allocate a transaction lock for freed page/entry;
98562306a36Sopenharmony_ci *	for freed page, maplock is used as xtlock/dtlock type;
98662306a36Sopenharmony_ci */
98762306a36Sopenharmony_cistruct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
99062306a36Sopenharmony_ci	lid_t lid;
99162306a36Sopenharmony_ci	struct tblock *tblk;
99262306a36Sopenharmony_ci	struct tlock *tlck;
99362306a36Sopenharmony_ci	struct maplock *maplock;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	TXN_LOCK();
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/*
99862306a36Sopenharmony_ci	 * allocate a tlock
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	lid = txLockAlloc();
100162306a36Sopenharmony_ci	tlck = lid_to_tlock(lid);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/*
100462306a36Sopenharmony_ci	 * initialize tlock
100562306a36Sopenharmony_ci	 */
100662306a36Sopenharmony_ci	tlck->tid = tid;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	/* bind the tlock and the object */
100962306a36Sopenharmony_ci	tlck->flag = tlckINODELOCK;
101062306a36Sopenharmony_ci	if (S_ISDIR(ip->i_mode))
101162306a36Sopenharmony_ci		tlck->flag |= tlckDIRECTORY;
101262306a36Sopenharmony_ci	tlck->ip = ip;
101362306a36Sopenharmony_ci	tlck->mp = NULL;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	tlck->type = type;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/*
101862306a36Sopenharmony_ci	 * enqueue transaction lock to transaction/inode
101962306a36Sopenharmony_ci	 */
102062306a36Sopenharmony_ci	/* insert the tlock at tail of transaction tlock list */
102162306a36Sopenharmony_ci	if (tid) {
102262306a36Sopenharmony_ci		tblk = tid_to_tblock(tid);
102362306a36Sopenharmony_ci		if (tblk->next)
102462306a36Sopenharmony_ci			lid_to_tlock(tblk->last)->next = lid;
102562306a36Sopenharmony_ci		else
102662306a36Sopenharmony_ci			tblk->next = lid;
102762306a36Sopenharmony_ci		tlck->next = 0;
102862306a36Sopenharmony_ci		tblk->last = lid;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci	/* anonymous transaction:
103162306a36Sopenharmony_ci	 * insert the tlock at head of inode anonymous tlock list
103262306a36Sopenharmony_ci	 */
103362306a36Sopenharmony_ci	else {
103462306a36Sopenharmony_ci		tlck->next = jfs_ip->atlhead;
103562306a36Sopenharmony_ci		jfs_ip->atlhead = lid;
103662306a36Sopenharmony_ci		if (tlck->next == 0) {
103762306a36Sopenharmony_ci			/* This inode's first anonymous transaction */
103862306a36Sopenharmony_ci			jfs_ip->atltail = lid;
103962306a36Sopenharmony_ci			list_add_tail(&jfs_ip->anon_inode_list,
104062306a36Sopenharmony_ci				      &TxAnchor.anon_list);
104162306a36Sopenharmony_ci		}
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	TXN_UNLOCK();
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/* initialize type dependent area for maplock */
104762306a36Sopenharmony_ci	maplock = (struct maplock *) & tlck->lock;
104862306a36Sopenharmony_ci	maplock->next = 0;
104962306a36Sopenharmony_ci	maplock->maxcnt = 0;
105062306a36Sopenharmony_ci	maplock->index = 0;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	return tlck;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci/*
105662306a36Sopenharmony_ci *	txLinelock()
105762306a36Sopenharmony_ci *
105862306a36Sopenharmony_ci * function: allocate a transaction lock for log vector list
105962306a36Sopenharmony_ci */
106062306a36Sopenharmony_cistruct linelock *txLinelock(struct linelock * tlock)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	lid_t lid;
106362306a36Sopenharmony_ci	struct tlock *tlck;
106462306a36Sopenharmony_ci	struct linelock *linelock;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	TXN_LOCK();
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	/* allocate a TxLock structure */
106962306a36Sopenharmony_ci	lid = txLockAlloc();
107062306a36Sopenharmony_ci	tlck = lid_to_tlock(lid);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	TXN_UNLOCK();
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	/* initialize linelock */
107562306a36Sopenharmony_ci	linelock = (struct linelock *) tlck;
107662306a36Sopenharmony_ci	linelock->next = 0;
107762306a36Sopenharmony_ci	linelock->flag = tlckLINELOCK;
107862306a36Sopenharmony_ci	linelock->maxcnt = TLOCKLONG;
107962306a36Sopenharmony_ci	linelock->index = 0;
108062306a36Sopenharmony_ci	if (tlck->flag & tlckDIRECTORY)
108162306a36Sopenharmony_ci		linelock->flag |= tlckDIRECTORY;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* append linelock after tlock */
108462306a36Sopenharmony_ci	linelock->next = tlock->next;
108562306a36Sopenharmony_ci	tlock->next = lid;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	return linelock;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci/*
109162306a36Sopenharmony_ci *		transaction commit management
109262306a36Sopenharmony_ci *		-----------------------------
109362306a36Sopenharmony_ci */
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci/*
109662306a36Sopenharmony_ci * NAME:	txCommit()
109762306a36Sopenharmony_ci *
109862306a36Sopenharmony_ci * FUNCTION:	commit the changes to the objects specified in
109962306a36Sopenharmony_ci *		clist.  For journalled segments only the
110062306a36Sopenharmony_ci *		changes of the caller are committed, ie by tid.
110162306a36Sopenharmony_ci *		for non-journalled segments the data are flushed to
110262306a36Sopenharmony_ci *		disk and then the change to the disk inode and indirect
110362306a36Sopenharmony_ci *		blocks committed (so blocks newly allocated to the
110462306a36Sopenharmony_ci *		segment will be made a part of the segment atomically).
110562306a36Sopenharmony_ci *
110662306a36Sopenharmony_ci *		all of the segments specified in clist must be in
110762306a36Sopenharmony_ci *		one file system. no more than 6 segments are needed
110862306a36Sopenharmony_ci *		to handle all unix svcs.
110962306a36Sopenharmony_ci *
111062306a36Sopenharmony_ci *		if the i_nlink field (i.e. disk inode link count)
111162306a36Sopenharmony_ci *		is zero, and the type of inode is a regular file or
111262306a36Sopenharmony_ci *		directory, or symbolic link , the inode is truncated
111362306a36Sopenharmony_ci *		to zero length. the truncation is committed but the
111462306a36Sopenharmony_ci *		VM resources are unaffected until it is closed (see
111562306a36Sopenharmony_ci *		iput and iclose).
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci * PARAMETER:
111862306a36Sopenharmony_ci *
111962306a36Sopenharmony_ci * RETURN:
112062306a36Sopenharmony_ci *
112162306a36Sopenharmony_ci * serialization:
112262306a36Sopenharmony_ci *		on entry the inode lock on each segment is assumed
112362306a36Sopenharmony_ci *		to be held.
112462306a36Sopenharmony_ci *
112562306a36Sopenharmony_ci * i/o error:
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_ciint txCommit(tid_t tid,		/* transaction identifier */
112862306a36Sopenharmony_ci	     int nip,		/* number of inodes to commit */
112962306a36Sopenharmony_ci	     struct inode **iplist,	/* list of inode to commit */
113062306a36Sopenharmony_ci	     int flag)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	int rc = 0;
113362306a36Sopenharmony_ci	struct commit cd;
113462306a36Sopenharmony_ci	struct jfs_log *log;
113562306a36Sopenharmony_ci	struct tblock *tblk;
113662306a36Sopenharmony_ci	struct lrd *lrd;
113762306a36Sopenharmony_ci	struct inode *ip;
113862306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip;
113962306a36Sopenharmony_ci	int k, n;
114062306a36Sopenharmony_ci	ino_t top;
114162306a36Sopenharmony_ci	struct super_block *sb;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	jfs_info("txCommit, tid = %d, flag = %d", tid, flag);
114462306a36Sopenharmony_ci	/* is read-only file system ? */
114562306a36Sopenharmony_ci	if (isReadOnly(iplist[0])) {
114662306a36Sopenharmony_ci		rc = -EROFS;
114762306a36Sopenharmony_ci		goto TheEnd;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	sb = cd.sb = iplist[0]->i_sb;
115162306a36Sopenharmony_ci	cd.tid = tid;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (tid == 0)
115462306a36Sopenharmony_ci		tid = txBegin(sb, 0);
115562306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	/*
115862306a36Sopenharmony_ci	 * initialize commit structure
115962306a36Sopenharmony_ci	 */
116062306a36Sopenharmony_ci	log = JFS_SBI(sb)->log;
116162306a36Sopenharmony_ci	cd.log = log;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* initialize log record descriptor in commit */
116462306a36Sopenharmony_ci	lrd = &cd.lrd;
116562306a36Sopenharmony_ci	lrd->logtid = cpu_to_le32(tblk->logtid);
116662306a36Sopenharmony_ci	lrd->backchain = 0;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	tblk->xflag |= flag;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0)
117162306a36Sopenharmony_ci		tblk->xflag |= COMMIT_LAZY;
117262306a36Sopenharmony_ci	/*
117362306a36Sopenharmony_ci	 *	prepare non-journaled objects for commit
117462306a36Sopenharmony_ci	 *
117562306a36Sopenharmony_ci	 * flush data pages of non-journaled file
117662306a36Sopenharmony_ci	 * to prevent the file getting non-initialized disk blocks
117762306a36Sopenharmony_ci	 * in case of crash.
117862306a36Sopenharmony_ci	 * (new blocks - )
117962306a36Sopenharmony_ci	 */
118062306a36Sopenharmony_ci	cd.iplist = iplist;
118162306a36Sopenharmony_ci	cd.nip = nip;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/*
118462306a36Sopenharmony_ci	 *	acquire transaction lock on (on-disk) inodes
118562306a36Sopenharmony_ci	 *
118662306a36Sopenharmony_ci	 * update on-disk inode from in-memory inode
118762306a36Sopenharmony_ci	 * acquiring transaction locks for AFTER records
118862306a36Sopenharmony_ci	 * on the on-disk inode of file object
118962306a36Sopenharmony_ci	 *
119062306a36Sopenharmony_ci	 * sort the inodes array by inode number in descending order
119162306a36Sopenharmony_ci	 * to prevent deadlock when acquiring transaction lock
119262306a36Sopenharmony_ci	 * of on-disk inodes on multiple on-disk inode pages by
119362306a36Sopenharmony_ci	 * multiple concurrent transactions
119462306a36Sopenharmony_ci	 */
119562306a36Sopenharmony_ci	for (k = 0; k < cd.nip; k++) {
119662306a36Sopenharmony_ci		top = (cd.iplist[k])->i_ino;
119762306a36Sopenharmony_ci		for (n = k + 1; n < cd.nip; n++) {
119862306a36Sopenharmony_ci			ip = cd.iplist[n];
119962306a36Sopenharmony_ci			if (ip->i_ino > top) {
120062306a36Sopenharmony_ci				top = ip->i_ino;
120162306a36Sopenharmony_ci				cd.iplist[n] = cd.iplist[k];
120262306a36Sopenharmony_ci				cd.iplist[k] = ip;
120362306a36Sopenharmony_ci			}
120462306a36Sopenharmony_ci		}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		ip = cd.iplist[k];
120762306a36Sopenharmony_ci		jfs_ip = JFS_IP(ip);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci		/*
121062306a36Sopenharmony_ci		 * BUGBUG - This code has temporarily been removed.  The
121162306a36Sopenharmony_ci		 * intent is to ensure that any file data is written before
121262306a36Sopenharmony_ci		 * the metadata is committed to the journal.  This prevents
121362306a36Sopenharmony_ci		 * uninitialized data from appearing in a file after the
121462306a36Sopenharmony_ci		 * journal has been replayed.  (The uninitialized data
121562306a36Sopenharmony_ci		 * could be sensitive data removed by another user.)
121662306a36Sopenharmony_ci		 *
121762306a36Sopenharmony_ci		 * The problem now is that we are holding the IWRITELOCK
121862306a36Sopenharmony_ci		 * on the inode, and calling filemap_fdatawrite on an
121962306a36Sopenharmony_ci		 * unmapped page will cause a deadlock in jfs_get_block.
122062306a36Sopenharmony_ci		 *
122162306a36Sopenharmony_ci		 * The long term solution is to pare down the use of
122262306a36Sopenharmony_ci		 * IWRITELOCK.  We are currently holding it too long.
122362306a36Sopenharmony_ci		 * We could also be smarter about which data pages need
122462306a36Sopenharmony_ci		 * to be written before the transaction is committed and
122562306a36Sopenharmony_ci		 * when we don't need to worry about it at all.
122662306a36Sopenharmony_ci		 *
122762306a36Sopenharmony_ci		 * if ((!S_ISDIR(ip->i_mode))
122862306a36Sopenharmony_ci		 *    && (tblk->flag & COMMIT_DELETE) == 0)
122962306a36Sopenharmony_ci		 *	filemap_write_and_wait(ip->i_mapping);
123062306a36Sopenharmony_ci		 */
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		/*
123362306a36Sopenharmony_ci		 * Mark inode as not dirty.  It will still be on the dirty
123462306a36Sopenharmony_ci		 * inode list, but we'll know not to commit it again unless
123562306a36Sopenharmony_ci		 * it gets marked dirty again
123662306a36Sopenharmony_ci		 */
123762306a36Sopenharmony_ci		clear_cflag(COMMIT_Dirty, ip);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		/* inherit anonymous tlock(s) of inode */
124062306a36Sopenharmony_ci		if (jfs_ip->atlhead) {
124162306a36Sopenharmony_ci			lid_to_tlock(jfs_ip->atltail)->next = tblk->next;
124262306a36Sopenharmony_ci			tblk->next = jfs_ip->atlhead;
124362306a36Sopenharmony_ci			if (!tblk->last)
124462306a36Sopenharmony_ci				tblk->last = jfs_ip->atltail;
124562306a36Sopenharmony_ci			jfs_ip->atlhead = jfs_ip->atltail = 0;
124662306a36Sopenharmony_ci			TXN_LOCK();
124762306a36Sopenharmony_ci			list_del_init(&jfs_ip->anon_inode_list);
124862306a36Sopenharmony_ci			TXN_UNLOCK();
124962306a36Sopenharmony_ci		}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		/*
125262306a36Sopenharmony_ci		 * acquire transaction lock on on-disk inode page
125362306a36Sopenharmony_ci		 * (become first tlock of the tblk's tlock list)
125462306a36Sopenharmony_ci		 */
125562306a36Sopenharmony_ci		if (((rc = diWrite(tid, ip))))
125662306a36Sopenharmony_ci			goto out;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/*
126062306a36Sopenharmony_ci	 *	write log records from transaction locks
126162306a36Sopenharmony_ci	 *
126262306a36Sopenharmony_ci	 * txUpdateMap() resets XAD_NEW in XAD.
126362306a36Sopenharmony_ci	 */
126462306a36Sopenharmony_ci	txLog(log, tblk, &cd);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/*
126762306a36Sopenharmony_ci	 * Ensure that inode isn't reused before
126862306a36Sopenharmony_ci	 * lazy commit thread finishes processing
126962306a36Sopenharmony_ci	 */
127062306a36Sopenharmony_ci	if (tblk->xflag & COMMIT_DELETE) {
127162306a36Sopenharmony_ci		ihold(tblk->u.ip);
127262306a36Sopenharmony_ci		/*
127362306a36Sopenharmony_ci		 * Avoid a rare deadlock
127462306a36Sopenharmony_ci		 *
127562306a36Sopenharmony_ci		 * If the inode is locked, we may be blocked in
127662306a36Sopenharmony_ci		 * jfs_commit_inode.  If so, we don't want the
127762306a36Sopenharmony_ci		 * lazy_commit thread doing the last iput() on the inode
127862306a36Sopenharmony_ci		 * since that may block on the locked inode.  Instead,
127962306a36Sopenharmony_ci		 * commit the transaction synchronously, so the last iput
128062306a36Sopenharmony_ci		 * will be done by the calling thread (or later)
128162306a36Sopenharmony_ci		 */
128262306a36Sopenharmony_ci		/*
128362306a36Sopenharmony_ci		 * I believe this code is no longer needed.  Splitting I_LOCK
128462306a36Sopenharmony_ci		 * into two bits, I_NEW and I_SYNC should prevent this
128562306a36Sopenharmony_ci		 * deadlock as well.  But since I don't have a JFS testload
128662306a36Sopenharmony_ci		 * to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
128762306a36Sopenharmony_ci		 * Joern
128862306a36Sopenharmony_ci		 */
128962306a36Sopenharmony_ci		if (tblk->u.ip->i_state & I_SYNC)
129062306a36Sopenharmony_ci			tblk->xflag &= ~COMMIT_LAZY;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	ASSERT((!(tblk->xflag & COMMIT_DELETE)) ||
129462306a36Sopenharmony_ci	       ((tblk->u.ip->i_nlink == 0) &&
129562306a36Sopenharmony_ci		!test_cflag(COMMIT_Nolink, tblk->u.ip)));
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	/*
129862306a36Sopenharmony_ci	 *	write COMMIT log record
129962306a36Sopenharmony_ci	 */
130062306a36Sopenharmony_ci	lrd->type = cpu_to_le16(LOG_COMMIT);
130162306a36Sopenharmony_ci	lrd->length = 0;
130262306a36Sopenharmony_ci	lmLog(log, tblk, lrd, NULL);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	lmGroupCommit(log, tblk);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/*
130762306a36Sopenharmony_ci	 *	- transaction is now committed -
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	/*
131162306a36Sopenharmony_ci	 * force pages in careful update
131262306a36Sopenharmony_ci	 * (imap addressing structure update)
131362306a36Sopenharmony_ci	 */
131462306a36Sopenharmony_ci	if (flag & COMMIT_FORCE)
131562306a36Sopenharmony_ci		txForce(tblk);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/*
131862306a36Sopenharmony_ci	 *	update allocation map.
131962306a36Sopenharmony_ci	 *
132062306a36Sopenharmony_ci	 * update inode allocation map and inode:
132162306a36Sopenharmony_ci	 * free pager lock on memory object of inode if any.
132262306a36Sopenharmony_ci	 * update block allocation map.
132362306a36Sopenharmony_ci	 *
132462306a36Sopenharmony_ci	 * txUpdateMap() resets XAD_NEW in XAD.
132562306a36Sopenharmony_ci	 */
132662306a36Sopenharmony_ci	if (tblk->xflag & COMMIT_FORCE)
132762306a36Sopenharmony_ci		txUpdateMap(tblk);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	/*
133062306a36Sopenharmony_ci	 *	free transaction locks and pageout/free pages
133162306a36Sopenharmony_ci	 */
133262306a36Sopenharmony_ci	txRelease(tblk);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if ((tblk->flag & tblkGC_LAZY) == 0)
133562306a36Sopenharmony_ci		txUnlock(tblk);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/*
133962306a36Sopenharmony_ci	 *	reset in-memory object state
134062306a36Sopenharmony_ci	 */
134162306a36Sopenharmony_ci	for (k = 0; k < cd.nip; k++) {
134262306a36Sopenharmony_ci		ip = cd.iplist[k];
134362306a36Sopenharmony_ci		jfs_ip = JFS_IP(ip);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci		/*
134662306a36Sopenharmony_ci		 * reset in-memory inode state
134762306a36Sopenharmony_ci		 */
134862306a36Sopenharmony_ci		jfs_ip->bxflag = 0;
134962306a36Sopenharmony_ci		jfs_ip->blid = 0;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci      out:
135362306a36Sopenharmony_ci	if (rc != 0)
135462306a36Sopenharmony_ci		txAbort(tid, 1);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci      TheEnd:
135762306a36Sopenharmony_ci	jfs_info("txCommit: tid = %d, returning %d", tid, rc);
135862306a36Sopenharmony_ci	return rc;
135962306a36Sopenharmony_ci}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci/*
136262306a36Sopenharmony_ci * NAME:	txLog()
136362306a36Sopenharmony_ci *
136462306a36Sopenharmony_ci * FUNCTION:	Writes AFTER log records for all lines modified
136562306a36Sopenharmony_ci *		by tid for segments specified by inodes in comdata.
136662306a36Sopenharmony_ci *		Code assumes only WRITELOCKS are recorded in lockwords.
136762306a36Sopenharmony_ci *
136862306a36Sopenharmony_ci * PARAMETERS:
136962306a36Sopenharmony_ci *
137062306a36Sopenharmony_ci * RETURN :
137162306a36Sopenharmony_ci */
137262306a36Sopenharmony_cistatic void txLog(struct jfs_log *log, struct tblock *tblk, struct commit *cd)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	struct inode *ip;
137562306a36Sopenharmony_ci	lid_t lid;
137662306a36Sopenharmony_ci	struct tlock *tlck;
137762306a36Sopenharmony_ci	struct lrd *lrd = &cd->lrd;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/*
138062306a36Sopenharmony_ci	 * write log record(s) for each tlock of transaction,
138162306a36Sopenharmony_ci	 */
138262306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = tlck->next) {
138362306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci		tlck->flag |= tlckLOG;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		/* initialize lrd common */
138862306a36Sopenharmony_ci		ip = tlck->ip;
138962306a36Sopenharmony_ci		lrd->aggregate = cpu_to_le32(JFS_SBI(ip->i_sb)->aggregate);
139062306a36Sopenharmony_ci		lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
139162306a36Sopenharmony_ci		lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		/* write log record of page from the tlock */
139462306a36Sopenharmony_ci		switch (tlck->type & tlckTYPE) {
139562306a36Sopenharmony_ci		case tlckXTREE:
139662306a36Sopenharmony_ci			xtLog(log, tblk, lrd, tlck);
139762306a36Sopenharmony_ci			break;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		case tlckDTREE:
140062306a36Sopenharmony_ci			dtLog(log, tblk, lrd, tlck);
140162306a36Sopenharmony_ci			break;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci		case tlckINODE:
140462306a36Sopenharmony_ci			diLog(log, tblk, lrd, tlck, cd);
140562306a36Sopenharmony_ci			break;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci		case tlckMAP:
140862306a36Sopenharmony_ci			mapLog(log, tblk, lrd, tlck);
140962306a36Sopenharmony_ci			break;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		case tlckDATA:
141262306a36Sopenharmony_ci			dataLog(log, tblk, lrd, tlck);
141362306a36Sopenharmony_ci			break;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		default:
141662306a36Sopenharmony_ci			jfs_err("UFO tlock:0x%p", tlck);
141762306a36Sopenharmony_ci		}
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	return;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci/*
142462306a36Sopenharmony_ci *	diLog()
142562306a36Sopenharmony_ci *
142662306a36Sopenharmony_ci * function:	log inode tlock and format maplock to update bmap;
142762306a36Sopenharmony_ci */
142862306a36Sopenharmony_cistatic void diLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
142962306a36Sopenharmony_ci		 struct tlock *tlck, struct commit *cd)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	struct metapage *mp;
143262306a36Sopenharmony_ci	pxd_t *pxd;
143362306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	mp = tlck->mp;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* initialize as REDOPAGE record format */
143862306a36Sopenharmony_ci	lrd->log.redopage.type = cpu_to_le16(LOG_INODE);
143962306a36Sopenharmony_ci	lrd->log.redopage.l2linesize = cpu_to_le16(L2INODESLOTSIZE);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	pxd = &lrd->log.redopage.pxd;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	/*
144462306a36Sopenharmony_ci	 *	inode after image
144562306a36Sopenharmony_ci	 */
144662306a36Sopenharmony_ci	if (tlck->type & tlckENTRY) {
144762306a36Sopenharmony_ci		/* log after-image for logredo(): */
144862306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_REDOPAGE);
144962306a36Sopenharmony_ci		PXDaddress(pxd, mp->index);
145062306a36Sopenharmony_ci		PXDlength(pxd,
145162306a36Sopenharmony_ci			  mp->logical_size >> tblk->sb->s_blocksize_bits);
145262306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		/* mark page as homeward bound */
145562306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
145662306a36Sopenharmony_ci	} else if (tlck->type & tlckFREE) {
145762306a36Sopenharmony_ci		/*
145862306a36Sopenharmony_ci		 *	free inode extent
145962306a36Sopenharmony_ci		 *
146062306a36Sopenharmony_ci		 * (pages of the freed inode extent have been invalidated and
146162306a36Sopenharmony_ci		 * a maplock for free of the extent has been formatted at
146262306a36Sopenharmony_ci		 * txLock() time);
146362306a36Sopenharmony_ci		 *
146462306a36Sopenharmony_ci		 * the tlock had been acquired on the inode allocation map page
146562306a36Sopenharmony_ci		 * (iag) that specifies the freed extent, even though the map
146662306a36Sopenharmony_ci		 * page is not itself logged, to prevent pageout of the map
146762306a36Sopenharmony_ci		 * page before the log;
146862306a36Sopenharmony_ci		 */
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci		/* log LOG_NOREDOINOEXT of the freed inode extent for
147162306a36Sopenharmony_ci		 * logredo() to start NoRedoPage filters, and to update
147262306a36Sopenharmony_ci		 * imap and bmap for free of the extent;
147362306a36Sopenharmony_ci		 */
147462306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_NOREDOINOEXT);
147562306a36Sopenharmony_ci		/*
147662306a36Sopenharmony_ci		 * For the LOG_NOREDOINOEXT record, we need
147762306a36Sopenharmony_ci		 * to pass the IAG number and inode extent
147862306a36Sopenharmony_ci		 * index (within that IAG) from which the
147962306a36Sopenharmony_ci		 * extent is being released.  These have been
148062306a36Sopenharmony_ci		 * passed to us in the iplist[1] and iplist[2].
148162306a36Sopenharmony_ci		 */
148262306a36Sopenharmony_ci		lrd->log.noredoinoext.iagnum =
148362306a36Sopenharmony_ci		    cpu_to_le32((u32) (size_t) cd->iplist[1]);
148462306a36Sopenharmony_ci		lrd->log.noredoinoext.inoext_idx =
148562306a36Sopenharmony_ci		    cpu_to_le32((u32) (size_t) cd->iplist[2]);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
148862306a36Sopenharmony_ci		*pxd = pxdlock->pxd;
148962306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci		/* update bmap */
149262306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		/* mark page as homeward bound */
149562306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
149662306a36Sopenharmony_ci	} else
149762306a36Sopenharmony_ci		jfs_err("diLog: UFO type tlck:0x%p", tlck);
149862306a36Sopenharmony_ci	return;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci/*
150262306a36Sopenharmony_ci *	dataLog()
150362306a36Sopenharmony_ci *
150462306a36Sopenharmony_ci * function:	log data tlock
150562306a36Sopenharmony_ci */
150662306a36Sopenharmony_cistatic void dataLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
150762306a36Sopenharmony_ci	    struct tlock *tlck)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	struct metapage *mp;
151062306a36Sopenharmony_ci	pxd_t *pxd;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	mp = tlck->mp;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* initialize as REDOPAGE record format */
151562306a36Sopenharmony_ci	lrd->log.redopage.type = cpu_to_le16(LOG_DATA);
151662306a36Sopenharmony_ci	lrd->log.redopage.l2linesize = cpu_to_le16(L2DATASLOTSIZE);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	pxd = &lrd->log.redopage.pxd;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	/* log after-image for logredo(): */
152162306a36Sopenharmony_ci	lrd->type = cpu_to_le16(LOG_REDOPAGE);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (jfs_dirtable_inline(tlck->ip)) {
152462306a36Sopenharmony_ci		/*
152562306a36Sopenharmony_ci		 * The table has been truncated, we've must have deleted
152662306a36Sopenharmony_ci		 * the last entry, so don't bother logging this
152762306a36Sopenharmony_ci		 */
152862306a36Sopenharmony_ci		mp->lid = 0;
152962306a36Sopenharmony_ci		grab_metapage(mp);
153062306a36Sopenharmony_ci		metapage_homeok(mp);
153162306a36Sopenharmony_ci		discard_metapage(mp);
153262306a36Sopenharmony_ci		tlck->mp = NULL;
153362306a36Sopenharmony_ci		return;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	PXDaddress(pxd, mp->index);
153762306a36Sopenharmony_ci	PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	/* mark page as homeward bound */
154262306a36Sopenharmony_ci	tlck->flag |= tlckWRITEPAGE;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	return;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci/*
154862306a36Sopenharmony_ci *	dtLog()
154962306a36Sopenharmony_ci *
155062306a36Sopenharmony_ci * function:	log dtree tlock and format maplock to update bmap;
155162306a36Sopenharmony_ci */
155262306a36Sopenharmony_cistatic void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
155362306a36Sopenharmony_ci	   struct tlock * tlck)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	struct metapage *mp;
155662306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
155762306a36Sopenharmony_ci	pxd_t *pxd;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	mp = tlck->mp;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/* initialize as REDOPAGE/NOREDOPAGE record format */
156262306a36Sopenharmony_ci	lrd->log.redopage.type = cpu_to_le16(LOG_DTREE);
156362306a36Sopenharmony_ci	lrd->log.redopage.l2linesize = cpu_to_le16(L2DTSLOTSIZE);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	pxd = &lrd->log.redopage.pxd;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (tlck->type & tlckBTROOT)
156862306a36Sopenharmony_ci		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	/*
157162306a36Sopenharmony_ci	 *	page extension via relocation: entry insertion;
157262306a36Sopenharmony_ci	 *	page extension in-place: entry insertion;
157362306a36Sopenharmony_ci	 *	new right page from page split, reinitialized in-line
157462306a36Sopenharmony_ci	 *	root from root page split: entry insertion;
157562306a36Sopenharmony_ci	 */
157662306a36Sopenharmony_ci	if (tlck->type & (tlckNEW | tlckEXTEND)) {
157762306a36Sopenharmony_ci		/* log after-image of the new page for logredo():
157862306a36Sopenharmony_ci		 * mark log (LOG_NEW) for logredo() to initialize
157962306a36Sopenharmony_ci		 * freelist and update bmap for alloc of the new page;
158062306a36Sopenharmony_ci		 */
158162306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_REDOPAGE);
158262306a36Sopenharmony_ci		if (tlck->type & tlckEXTEND)
158362306a36Sopenharmony_ci			lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND);
158462306a36Sopenharmony_ci		else
158562306a36Sopenharmony_ci			lrd->log.redopage.type |= cpu_to_le16(LOG_NEW);
158662306a36Sopenharmony_ci		PXDaddress(pxd, mp->index);
158762306a36Sopenharmony_ci		PXDlength(pxd,
158862306a36Sopenharmony_ci			  mp->logical_size >> tblk->sb->s_blocksize_bits);
158962306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		/* format a maplock for txUpdateMap() to update bPMAP for
159262306a36Sopenharmony_ci		 * alloc of the new page;
159362306a36Sopenharmony_ci		 */
159462306a36Sopenharmony_ci		if (tlck->type & tlckBTROOT)
159562306a36Sopenharmony_ci			return;
159662306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
159762306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
159862306a36Sopenharmony_ci		pxdlock->flag = mlckALLOCPXD;
159962306a36Sopenharmony_ci		pxdlock->pxd = *pxd;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		pxdlock->index = 1;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		/* mark page as homeward bound */
160462306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
160562306a36Sopenharmony_ci		return;
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	/*
160962306a36Sopenharmony_ci	 *	entry insertion/deletion,
161062306a36Sopenharmony_ci	 *	sibling page link update (old right page before split);
161162306a36Sopenharmony_ci	 */
161262306a36Sopenharmony_ci	if (tlck->type & (tlckENTRY | tlckRELINK)) {
161362306a36Sopenharmony_ci		/* log after-image for logredo(): */
161462306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_REDOPAGE);
161562306a36Sopenharmony_ci		PXDaddress(pxd, mp->index);
161662306a36Sopenharmony_ci		PXDlength(pxd,
161762306a36Sopenharmony_ci			  mp->logical_size >> tblk->sb->s_blocksize_bits);
161862306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci		/* mark page as homeward bound */
162162306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
162262306a36Sopenharmony_ci		return;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/*
162662306a36Sopenharmony_ci	 *	page deletion: page has been invalidated
162762306a36Sopenharmony_ci	 *	page relocation: source extent
162862306a36Sopenharmony_ci	 *
162962306a36Sopenharmony_ci	 *	a maplock for free of the page has been formatted
163062306a36Sopenharmony_ci	 *	at txLock() time);
163162306a36Sopenharmony_ci	 */
163262306a36Sopenharmony_ci	if (tlck->type & (tlckFREE | tlckRELOCATE)) {
163362306a36Sopenharmony_ci		/* log LOG_NOREDOPAGE of the deleted page for logredo()
163462306a36Sopenharmony_ci		 * to start NoRedoPage filter and to update bmap for free
163562306a36Sopenharmony_ci		 * of the deletd page
163662306a36Sopenharmony_ci		 */
163762306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
163862306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
163962306a36Sopenharmony_ci		*pxd = pxdlock->pxd;
164062306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		/* a maplock for txUpdateMap() for free of the page
164362306a36Sopenharmony_ci		 * has been formatted at txLock() time;
164462306a36Sopenharmony_ci		 */
164562306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci	return;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci/*
165162306a36Sopenharmony_ci *	xtLog()
165262306a36Sopenharmony_ci *
165362306a36Sopenharmony_ci * function:	log xtree tlock and format maplock to update bmap;
165462306a36Sopenharmony_ci */
165562306a36Sopenharmony_cistatic void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
165662306a36Sopenharmony_ci	   struct tlock * tlck)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct inode *ip;
165962306a36Sopenharmony_ci	struct metapage *mp;
166062306a36Sopenharmony_ci	xtpage_t *p;
166162306a36Sopenharmony_ci	struct xtlock *xtlck;
166262306a36Sopenharmony_ci	struct maplock *maplock;
166362306a36Sopenharmony_ci	struct xdlistlock *xadlock;
166462306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
166562306a36Sopenharmony_ci	pxd_t *page_pxd;
166662306a36Sopenharmony_ci	int next, lwm, hwm;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	ip = tlck->ip;
166962306a36Sopenharmony_ci	mp = tlck->mp;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	/* initialize as REDOPAGE/NOREDOPAGE record format */
167262306a36Sopenharmony_ci	lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
167362306a36Sopenharmony_ci	lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	page_pxd = &lrd->log.redopage.pxd;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (tlck->type & tlckBTROOT) {
167862306a36Sopenharmony_ci		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
167962306a36Sopenharmony_ci		p = &JFS_IP(ip)->i_xtroot;
168062306a36Sopenharmony_ci		if (S_ISDIR(ip->i_mode))
168162306a36Sopenharmony_ci			lrd->log.redopage.type |=
168262306a36Sopenharmony_ci			    cpu_to_le16(LOG_DIR_XTREE);
168362306a36Sopenharmony_ci	} else
168462306a36Sopenharmony_ci		p = (xtpage_t *) mp->data;
168562306a36Sopenharmony_ci	next = le16_to_cpu(p->header.nextindex);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	xtlck = (struct xtlock *) & tlck->lock;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	maplock = (struct maplock *) & tlck->lock;
169062306a36Sopenharmony_ci	xadlock = (struct xdlistlock *) maplock;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/*
169362306a36Sopenharmony_ci	 *	entry insertion/extension;
169462306a36Sopenharmony_ci	 *	sibling page link update (old right page before split);
169562306a36Sopenharmony_ci	 */
169662306a36Sopenharmony_ci	if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) {
169762306a36Sopenharmony_ci		/* log after-image for logredo():
169862306a36Sopenharmony_ci		 * logredo() will update bmap for alloc of new/extended
169962306a36Sopenharmony_ci		 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
170062306a36Sopenharmony_ci		 * after-image of XADlist;
170162306a36Sopenharmony_ci		 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
170262306a36Sopenharmony_ci		 * applying the after-image to the meta-data page.
170362306a36Sopenharmony_ci		 */
170462306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_REDOPAGE);
170562306a36Sopenharmony_ci		PXDaddress(page_pxd, mp->index);
170662306a36Sopenharmony_ci		PXDlength(page_pxd,
170762306a36Sopenharmony_ci			  mp->logical_size >> tblk->sb->s_blocksize_bits);
170862306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		/* format a maplock for txUpdateMap() to update bPMAP
171162306a36Sopenharmony_ci		 * for alloc of new/extended extents of XAD[lwm:next)
171262306a36Sopenharmony_ci		 * from the page itself;
171362306a36Sopenharmony_ci		 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
171462306a36Sopenharmony_ci		 */
171562306a36Sopenharmony_ci		lwm = xtlck->lwm.offset;
171662306a36Sopenharmony_ci		if (lwm == 0)
171762306a36Sopenharmony_ci			lwm = XTPAGEMAXSLOT;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		if (lwm == next)
172062306a36Sopenharmony_ci			goto out;
172162306a36Sopenharmony_ci		if (lwm > next) {
172262306a36Sopenharmony_ci			jfs_err("xtLog: lwm > next");
172362306a36Sopenharmony_ci			goto out;
172462306a36Sopenharmony_ci		}
172562306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
172662306a36Sopenharmony_ci		xadlock->flag = mlckALLOCXADLIST;
172762306a36Sopenharmony_ci		xadlock->count = next - lwm;
172862306a36Sopenharmony_ci		if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
172962306a36Sopenharmony_ci			int i;
173062306a36Sopenharmony_ci			pxd_t *pxd;
173162306a36Sopenharmony_ci			/*
173262306a36Sopenharmony_ci			 * Lazy commit may allow xtree to be modified before
173362306a36Sopenharmony_ci			 * txUpdateMap runs.  Copy xad into linelock to
173462306a36Sopenharmony_ci			 * preserve correct data.
173562306a36Sopenharmony_ci			 *
173662306a36Sopenharmony_ci			 * We can fit twice as may pxd's as xads in the lock
173762306a36Sopenharmony_ci			 */
173862306a36Sopenharmony_ci			xadlock->flag = mlckALLOCPXDLIST;
173962306a36Sopenharmony_ci			pxd = xadlock->xdlist = &xtlck->pxdlock;
174062306a36Sopenharmony_ci			for (i = 0; i < xadlock->count; i++) {
174162306a36Sopenharmony_ci				PXDaddress(pxd, addressXAD(&p->xad[lwm + i]));
174262306a36Sopenharmony_ci				PXDlength(pxd, lengthXAD(&p->xad[lwm + i]));
174362306a36Sopenharmony_ci				p->xad[lwm + i].flag &=
174462306a36Sopenharmony_ci				    ~(XAD_NEW | XAD_EXTENDED);
174562306a36Sopenharmony_ci				pxd++;
174662306a36Sopenharmony_ci			}
174762306a36Sopenharmony_ci		} else {
174862306a36Sopenharmony_ci			/*
174962306a36Sopenharmony_ci			 * xdlist will point to into inode's xtree, ensure
175062306a36Sopenharmony_ci			 * that transaction is not committed lazily.
175162306a36Sopenharmony_ci			 */
175262306a36Sopenharmony_ci			xadlock->flag = mlckALLOCXADLIST;
175362306a36Sopenharmony_ci			xadlock->xdlist = &p->xad[lwm];
175462306a36Sopenharmony_ci			tblk->xflag &= ~COMMIT_LAZY;
175562306a36Sopenharmony_ci		}
175662306a36Sopenharmony_ci		jfs_info("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d",
175762306a36Sopenharmony_ci			 tlck->ip, mp, tlck, lwm, xadlock->count);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci		maplock->index = 1;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	      out:
176262306a36Sopenharmony_ci		/* mark page as homeward bound */
176362306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		return;
176662306a36Sopenharmony_ci	}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	/*
176962306a36Sopenharmony_ci	 *	page deletion: file deletion/truncation (ref. xtTruncate())
177062306a36Sopenharmony_ci	 *
177162306a36Sopenharmony_ci	 * (page will be invalidated after log is written and bmap
177262306a36Sopenharmony_ci	 * is updated from the page);
177362306a36Sopenharmony_ci	 */
177462306a36Sopenharmony_ci	if (tlck->type & tlckFREE) {
177562306a36Sopenharmony_ci		/* LOG_NOREDOPAGE log for NoRedoPage filter:
177662306a36Sopenharmony_ci		 * if page free from file delete, NoRedoFile filter from
177762306a36Sopenharmony_ci		 * inode image of zero link count will subsume NoRedoPage
177862306a36Sopenharmony_ci		 * filters for each page;
177962306a36Sopenharmony_ci		 * if page free from file truncattion, write NoRedoPage
178062306a36Sopenharmony_ci		 * filter;
178162306a36Sopenharmony_ci		 *
178262306a36Sopenharmony_ci		 * upadte of block allocation map for the page itself:
178362306a36Sopenharmony_ci		 * if page free from deletion and truncation, LOG_UPDATEMAP
178462306a36Sopenharmony_ci		 * log for the page itself is generated from processing
178562306a36Sopenharmony_ci		 * its parent page xad entries;
178662306a36Sopenharmony_ci		 */
178762306a36Sopenharmony_ci		/* if page free from file truncation, log LOG_NOREDOPAGE
178862306a36Sopenharmony_ci		 * of the deleted page for logredo() to start NoRedoPage
178962306a36Sopenharmony_ci		 * filter for the page;
179062306a36Sopenharmony_ci		 */
179162306a36Sopenharmony_ci		if (tblk->xflag & COMMIT_TRUNCATE) {
179262306a36Sopenharmony_ci			/* write NOREDOPAGE for the page */
179362306a36Sopenharmony_ci			lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
179462306a36Sopenharmony_ci			PXDaddress(page_pxd, mp->index);
179562306a36Sopenharmony_ci			PXDlength(page_pxd,
179662306a36Sopenharmony_ci				  mp->logical_size >> tblk->sb->
179762306a36Sopenharmony_ci				  s_blocksize_bits);
179862306a36Sopenharmony_ci			lrd->backchain =
179962306a36Sopenharmony_ci			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci			if (tlck->type & tlckBTROOT) {
180262306a36Sopenharmony_ci				/* Empty xtree must be logged */
180362306a36Sopenharmony_ci				lrd->type = cpu_to_le16(LOG_REDOPAGE);
180462306a36Sopenharmony_ci				lrd->backchain =
180562306a36Sopenharmony_ci				    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
180662306a36Sopenharmony_ci			}
180762306a36Sopenharmony_ci		}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci		/* init LOG_UPDATEMAP of the freed extents
181062306a36Sopenharmony_ci		 * XAD[XTENTRYSTART:hwm) from the deleted page itself
181162306a36Sopenharmony_ci		 * for logredo() to update bmap;
181262306a36Sopenharmony_ci		 */
181362306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
181462306a36Sopenharmony_ci		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST);
181562306a36Sopenharmony_ci		xtlck = (struct xtlock *) & tlck->lock;
181662306a36Sopenharmony_ci		hwm = xtlck->hwm.offset;
181762306a36Sopenharmony_ci		lrd->log.updatemap.nxd =
181862306a36Sopenharmony_ci		    cpu_to_le16(hwm - XTENTRYSTART + 1);
181962306a36Sopenharmony_ci		/* reformat linelock for lmLog() */
182062306a36Sopenharmony_ci		xtlck->header.offset = XTENTRYSTART;
182162306a36Sopenharmony_ci		xtlck->header.length = hwm - XTENTRYSTART + 1;
182262306a36Sopenharmony_ci		xtlck->index = 1;
182362306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		/* format a maplock for txUpdateMap() to update bmap
182662306a36Sopenharmony_ci		 * to free extents of XAD[XTENTRYSTART:hwm) from the
182762306a36Sopenharmony_ci		 * deleted page itself;
182862306a36Sopenharmony_ci		 */
182962306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
183062306a36Sopenharmony_ci		xadlock->count = hwm - XTENTRYSTART + 1;
183162306a36Sopenharmony_ci		if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
183262306a36Sopenharmony_ci			int i;
183362306a36Sopenharmony_ci			pxd_t *pxd;
183462306a36Sopenharmony_ci			/*
183562306a36Sopenharmony_ci			 * Lazy commit may allow xtree to be modified before
183662306a36Sopenharmony_ci			 * txUpdateMap runs.  Copy xad into linelock to
183762306a36Sopenharmony_ci			 * preserve correct data.
183862306a36Sopenharmony_ci			 *
183962306a36Sopenharmony_ci			 * We can fit twice as may pxd's as xads in the lock
184062306a36Sopenharmony_ci			 */
184162306a36Sopenharmony_ci			xadlock->flag = mlckFREEPXDLIST;
184262306a36Sopenharmony_ci			pxd = xadlock->xdlist = &xtlck->pxdlock;
184362306a36Sopenharmony_ci			for (i = 0; i < xadlock->count; i++) {
184462306a36Sopenharmony_ci				PXDaddress(pxd,
184562306a36Sopenharmony_ci					addressXAD(&p->xad[XTENTRYSTART + i]));
184662306a36Sopenharmony_ci				PXDlength(pxd,
184762306a36Sopenharmony_ci					lengthXAD(&p->xad[XTENTRYSTART + i]));
184862306a36Sopenharmony_ci				pxd++;
184962306a36Sopenharmony_ci			}
185062306a36Sopenharmony_ci		} else {
185162306a36Sopenharmony_ci			/*
185262306a36Sopenharmony_ci			 * xdlist will point to into inode's xtree, ensure
185362306a36Sopenharmony_ci			 * that transaction is not committed lazily.
185462306a36Sopenharmony_ci			 */
185562306a36Sopenharmony_ci			xadlock->flag = mlckFREEXADLIST;
185662306a36Sopenharmony_ci			xadlock->xdlist = &p->xad[XTENTRYSTART];
185762306a36Sopenharmony_ci			tblk->xflag &= ~COMMIT_LAZY;
185862306a36Sopenharmony_ci		}
185962306a36Sopenharmony_ci		jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2",
186062306a36Sopenharmony_ci			 tlck->ip, mp, xadlock->count);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci		maplock->index = 1;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci		/* mark page as invalid */
186562306a36Sopenharmony_ci		if (((tblk->xflag & COMMIT_PWMAP) || S_ISDIR(ip->i_mode))
186662306a36Sopenharmony_ci		    && !(tlck->type & tlckBTROOT))
186762306a36Sopenharmony_ci			tlck->flag |= tlckFREEPAGE;
186862306a36Sopenharmony_ci		/*
186962306a36Sopenharmony_ci		   else (tblk->xflag & COMMIT_PMAP)
187062306a36Sopenharmony_ci		   ? release the page;
187162306a36Sopenharmony_ci		 */
187262306a36Sopenharmony_ci		return;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	/*
187662306a36Sopenharmony_ci	 *	page/entry truncation: file truncation (ref. xtTruncate())
187762306a36Sopenharmony_ci	 *
187862306a36Sopenharmony_ci	 *	|----------+------+------+---------------|
187962306a36Sopenharmony_ci	 *		   |      |      |
188062306a36Sopenharmony_ci	 *		   |      |     hwm - hwm before truncation
188162306a36Sopenharmony_ci	 *		   |     next - truncation point
188262306a36Sopenharmony_ci	 *		  lwm - lwm before truncation
188362306a36Sopenharmony_ci	 * header ?
188462306a36Sopenharmony_ci	 */
188562306a36Sopenharmony_ci	if (tlck->type & tlckTRUNCATE) {
188662306a36Sopenharmony_ci		pxd_t pxd;	/* truncated extent of xad */
188762306a36Sopenharmony_ci		int twm;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci		/*
189062306a36Sopenharmony_ci		 * For truncation the entire linelock may be used, so it would
189162306a36Sopenharmony_ci		 * be difficult to store xad list in linelock itself.
189262306a36Sopenharmony_ci		 * Therefore, we'll just force transaction to be committed
189362306a36Sopenharmony_ci		 * synchronously, so that xtree pages won't be changed before
189462306a36Sopenharmony_ci		 * txUpdateMap runs.
189562306a36Sopenharmony_ci		 */
189662306a36Sopenharmony_ci		tblk->xflag &= ~COMMIT_LAZY;
189762306a36Sopenharmony_ci		lwm = xtlck->lwm.offset;
189862306a36Sopenharmony_ci		if (lwm == 0)
189962306a36Sopenharmony_ci			lwm = XTPAGEMAXSLOT;
190062306a36Sopenharmony_ci		hwm = xtlck->hwm.offset;
190162306a36Sopenharmony_ci		twm = xtlck->twm.offset;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci		/*
190462306a36Sopenharmony_ci		 *	write log records
190562306a36Sopenharmony_ci		 */
190662306a36Sopenharmony_ci		/* log after-image for logredo():
190762306a36Sopenharmony_ci		 *
190862306a36Sopenharmony_ci		 * logredo() will update bmap for alloc of new/extended
190962306a36Sopenharmony_ci		 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
191062306a36Sopenharmony_ci		 * after-image of XADlist;
191162306a36Sopenharmony_ci		 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
191262306a36Sopenharmony_ci		 * applying the after-image to the meta-data page.
191362306a36Sopenharmony_ci		 */
191462306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_REDOPAGE);
191562306a36Sopenharmony_ci		PXDaddress(page_pxd, mp->index);
191662306a36Sopenharmony_ci		PXDlength(page_pxd,
191762306a36Sopenharmony_ci			  mp->logical_size >> tblk->sb->s_blocksize_bits);
191862306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci		/*
192162306a36Sopenharmony_ci		 * truncate entry XAD[twm == next - 1]:
192262306a36Sopenharmony_ci		 */
192362306a36Sopenharmony_ci		if (twm == next - 1) {
192462306a36Sopenharmony_ci			/* init LOG_UPDATEMAP for logredo() to update bmap for
192562306a36Sopenharmony_ci			 * free of truncated delta extent of the truncated
192662306a36Sopenharmony_ci			 * entry XAD[next - 1]:
192762306a36Sopenharmony_ci			 * (xtlck->pxdlock = truncated delta extent);
192862306a36Sopenharmony_ci			 */
192962306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
193062306a36Sopenharmony_ci			/* assert(pxdlock->type & tlckTRUNCATE); */
193162306a36Sopenharmony_ci			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
193262306a36Sopenharmony_ci			lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
193362306a36Sopenharmony_ci			lrd->log.updatemap.nxd = cpu_to_le16(1);
193462306a36Sopenharmony_ci			lrd->log.updatemap.pxd = pxdlock->pxd;
193562306a36Sopenharmony_ci			pxd = pxdlock->pxd;	/* save to format maplock */
193662306a36Sopenharmony_ci			lrd->backchain =
193762306a36Sopenharmony_ci			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
193862306a36Sopenharmony_ci		}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci		/*
194162306a36Sopenharmony_ci		 * free entries XAD[next:hwm]:
194262306a36Sopenharmony_ci		 */
194362306a36Sopenharmony_ci		if (hwm >= next) {
194462306a36Sopenharmony_ci			/* init LOG_UPDATEMAP of the freed extents
194562306a36Sopenharmony_ci			 * XAD[next:hwm] from the deleted page itself
194662306a36Sopenharmony_ci			 * for logredo() to update bmap;
194762306a36Sopenharmony_ci			 */
194862306a36Sopenharmony_ci			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
194962306a36Sopenharmony_ci			lrd->log.updatemap.type =
195062306a36Sopenharmony_ci			    cpu_to_le16(LOG_FREEXADLIST);
195162306a36Sopenharmony_ci			xtlck = (struct xtlock *) & tlck->lock;
195262306a36Sopenharmony_ci			hwm = xtlck->hwm.offset;
195362306a36Sopenharmony_ci			lrd->log.updatemap.nxd =
195462306a36Sopenharmony_ci			    cpu_to_le16(hwm - next + 1);
195562306a36Sopenharmony_ci			/* reformat linelock for lmLog() */
195662306a36Sopenharmony_ci			xtlck->header.offset = next;
195762306a36Sopenharmony_ci			xtlck->header.length = hwm - next + 1;
195862306a36Sopenharmony_ci			xtlck->index = 1;
195962306a36Sopenharmony_ci			lrd->backchain =
196062306a36Sopenharmony_ci			    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
196162306a36Sopenharmony_ci		}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci		/*
196462306a36Sopenharmony_ci		 *	format maplock(s) for txUpdateMap() to update bmap
196562306a36Sopenharmony_ci		 */
196662306a36Sopenharmony_ci		maplock->index = 0;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		/*
196962306a36Sopenharmony_ci		 * allocate entries XAD[lwm:next):
197062306a36Sopenharmony_ci		 */
197162306a36Sopenharmony_ci		if (lwm < next) {
197262306a36Sopenharmony_ci			/* format a maplock for txUpdateMap() to update bPMAP
197362306a36Sopenharmony_ci			 * for alloc of new/extended extents of XAD[lwm:next)
197462306a36Sopenharmony_ci			 * from the page itself;
197562306a36Sopenharmony_ci			 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
197662306a36Sopenharmony_ci			 */
197762306a36Sopenharmony_ci			tlck->flag |= tlckUPDATEMAP;
197862306a36Sopenharmony_ci			xadlock->flag = mlckALLOCXADLIST;
197962306a36Sopenharmony_ci			xadlock->count = next - lwm;
198062306a36Sopenharmony_ci			xadlock->xdlist = &p->xad[lwm];
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci			jfs_info("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d",
198362306a36Sopenharmony_ci				 tlck->ip, mp, xadlock->count, lwm, next);
198462306a36Sopenharmony_ci			maplock->index++;
198562306a36Sopenharmony_ci			xadlock++;
198662306a36Sopenharmony_ci		}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci		/*
198962306a36Sopenharmony_ci		 * truncate entry XAD[twm == next - 1]:
199062306a36Sopenharmony_ci		 */
199162306a36Sopenharmony_ci		if (twm == next - 1) {
199262306a36Sopenharmony_ci			/* format a maplock for txUpdateMap() to update bmap
199362306a36Sopenharmony_ci			 * to free truncated delta extent of the truncated
199462306a36Sopenharmony_ci			 * entry XAD[next - 1];
199562306a36Sopenharmony_ci			 * (xtlck->pxdlock = truncated delta extent);
199662306a36Sopenharmony_ci			 */
199762306a36Sopenharmony_ci			tlck->flag |= tlckUPDATEMAP;
199862306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) xadlock;
199962306a36Sopenharmony_ci			pxdlock->flag = mlckFREEPXD;
200062306a36Sopenharmony_ci			pxdlock->count = 1;
200162306a36Sopenharmony_ci			pxdlock->pxd = pxd;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci			jfs_info("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d",
200462306a36Sopenharmony_ci				 ip, mp, pxdlock->count, hwm);
200562306a36Sopenharmony_ci			maplock->index++;
200662306a36Sopenharmony_ci			xadlock++;
200762306a36Sopenharmony_ci		}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		/*
201062306a36Sopenharmony_ci		 * free entries XAD[next:hwm]:
201162306a36Sopenharmony_ci		 */
201262306a36Sopenharmony_ci		if (hwm >= next) {
201362306a36Sopenharmony_ci			/* format a maplock for txUpdateMap() to update bmap
201462306a36Sopenharmony_ci			 * to free extents of XAD[next:hwm] from thedeleted
201562306a36Sopenharmony_ci			 * page itself;
201662306a36Sopenharmony_ci			 */
201762306a36Sopenharmony_ci			tlck->flag |= tlckUPDATEMAP;
201862306a36Sopenharmony_ci			xadlock->flag = mlckFREEXADLIST;
201962306a36Sopenharmony_ci			xadlock->count = hwm - next + 1;
202062306a36Sopenharmony_ci			xadlock->xdlist = &p->xad[next];
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci			jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d",
202362306a36Sopenharmony_ci				 tlck->ip, mp, xadlock->count, next, hwm);
202462306a36Sopenharmony_ci			maplock->index++;
202562306a36Sopenharmony_ci		}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci		/* mark page as homeward bound */
202862306a36Sopenharmony_ci		tlck->flag |= tlckWRITEPAGE;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci	return;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci/*
203462306a36Sopenharmony_ci *	mapLog()
203562306a36Sopenharmony_ci *
203662306a36Sopenharmony_ci * function:	log from maplock of freed data extents;
203762306a36Sopenharmony_ci */
203862306a36Sopenharmony_cistatic void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
203962306a36Sopenharmony_ci		   struct tlock * tlck)
204062306a36Sopenharmony_ci{
204162306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
204262306a36Sopenharmony_ci	int i, nlock;
204362306a36Sopenharmony_ci	pxd_t *pxd;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	/*
204662306a36Sopenharmony_ci	 *	page relocation: free the source page extent
204762306a36Sopenharmony_ci	 *
204862306a36Sopenharmony_ci	 * a maplock for txUpdateMap() for free of the page
204962306a36Sopenharmony_ci	 * has been formatted at txLock() time saving the src
205062306a36Sopenharmony_ci	 * relocated page address;
205162306a36Sopenharmony_ci	 */
205262306a36Sopenharmony_ci	if (tlck->type & tlckRELOCATE) {
205362306a36Sopenharmony_ci		/* log LOG_NOREDOPAGE of the old relocated page
205462306a36Sopenharmony_ci		 * for logredo() to start NoRedoPage filter;
205562306a36Sopenharmony_ci		 */
205662306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
205762306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
205862306a36Sopenharmony_ci		pxd = &lrd->log.redopage.pxd;
205962306a36Sopenharmony_ci		*pxd = pxdlock->pxd;
206062306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci		/* (N.B. currently, logredo() does NOT update bmap
206362306a36Sopenharmony_ci		 * for free of the page itself for (LOG_XTREE|LOG_NOREDOPAGE);
206462306a36Sopenharmony_ci		 * if page free from relocation, LOG_UPDATEMAP log is
206562306a36Sopenharmony_ci		 * specifically generated now for logredo()
206662306a36Sopenharmony_ci		 * to update bmap for free of src relocated page;
206762306a36Sopenharmony_ci		 * (new flag LOG_RELOCATE may be introduced which will
206862306a36Sopenharmony_ci		 * inform logredo() to start NORedoPage filter and also
206962306a36Sopenharmony_ci		 * update block allocation map at the same time, thus
207062306a36Sopenharmony_ci		 * avoiding an extra log write);
207162306a36Sopenharmony_ci		 */
207262306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
207362306a36Sopenharmony_ci		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
207462306a36Sopenharmony_ci		lrd->log.updatemap.nxd = cpu_to_le16(1);
207562306a36Sopenharmony_ci		lrd->log.updatemap.pxd = pxdlock->pxd;
207662306a36Sopenharmony_ci		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci		/* a maplock for txUpdateMap() for free of the page
207962306a36Sopenharmony_ci		 * has been formatted at txLock() time;
208062306a36Sopenharmony_ci		 */
208162306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
208262306a36Sopenharmony_ci		return;
208362306a36Sopenharmony_ci	}
208462306a36Sopenharmony_ci	/*
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	 * Otherwise it's not a relocate request
208762306a36Sopenharmony_ci	 *
208862306a36Sopenharmony_ci	 */
208962306a36Sopenharmony_ci	else {
209062306a36Sopenharmony_ci		/* log LOG_UPDATEMAP for logredo() to update bmap for
209162306a36Sopenharmony_ci		 * free of truncated/relocated delta extent of the data;
209262306a36Sopenharmony_ci		 * e.g.: external EA extent, relocated/truncated extent
209362306a36Sopenharmony_ci		 * from xtTailgate();
209462306a36Sopenharmony_ci		 */
209562306a36Sopenharmony_ci		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
209662306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
209762306a36Sopenharmony_ci		nlock = pxdlock->index;
209862306a36Sopenharmony_ci		for (i = 0; i < nlock; i++, pxdlock++) {
209962306a36Sopenharmony_ci			if (pxdlock->flag & mlckALLOCPXD)
210062306a36Sopenharmony_ci				lrd->log.updatemap.type =
210162306a36Sopenharmony_ci				    cpu_to_le16(LOG_ALLOCPXD);
210262306a36Sopenharmony_ci			else
210362306a36Sopenharmony_ci				lrd->log.updatemap.type =
210462306a36Sopenharmony_ci				    cpu_to_le16(LOG_FREEPXD);
210562306a36Sopenharmony_ci			lrd->log.updatemap.nxd = cpu_to_le16(1);
210662306a36Sopenharmony_ci			lrd->log.updatemap.pxd = pxdlock->pxd;
210762306a36Sopenharmony_ci			lrd->backchain =
210862306a36Sopenharmony_ci			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
210962306a36Sopenharmony_ci			jfs_info("mapLog: xaddr:0x%lx xlen:0x%x",
211062306a36Sopenharmony_ci				 (ulong) addressPXD(&pxdlock->pxd),
211162306a36Sopenharmony_ci				 lengthPXD(&pxdlock->pxd));
211262306a36Sopenharmony_ci		}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci		/* update bmap */
211562306a36Sopenharmony_ci		tlck->flag |= tlckUPDATEMAP;
211662306a36Sopenharmony_ci	}
211762306a36Sopenharmony_ci}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci/*
212062306a36Sopenharmony_ci *	txEA()
212162306a36Sopenharmony_ci *
212262306a36Sopenharmony_ci * function:	acquire maplock for EA/ACL extents or
212362306a36Sopenharmony_ci *		set COMMIT_INLINE flag;
212462306a36Sopenharmony_ci */
212562306a36Sopenharmony_civoid txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
212662306a36Sopenharmony_ci{
212762306a36Sopenharmony_ci	struct tlock *tlck = NULL;
212862306a36Sopenharmony_ci	struct pxd_lock *maplock = NULL, *pxdlock = NULL;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	/*
213162306a36Sopenharmony_ci	 * format maplock for alloc of new EA extent
213262306a36Sopenharmony_ci	 */
213362306a36Sopenharmony_ci	if (newea) {
213462306a36Sopenharmony_ci		/* Since the newea could be a completely zeroed entry we need to
213562306a36Sopenharmony_ci		 * check for the two flags which indicate we should actually
213662306a36Sopenharmony_ci		 * commit new EA data
213762306a36Sopenharmony_ci		 */
213862306a36Sopenharmony_ci		if (newea->flag & DXD_EXTENT) {
213962306a36Sopenharmony_ci			tlck = txMaplock(tid, ip, tlckMAP);
214062306a36Sopenharmony_ci			maplock = (struct pxd_lock *) & tlck->lock;
214162306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) maplock;
214262306a36Sopenharmony_ci			pxdlock->flag = mlckALLOCPXD;
214362306a36Sopenharmony_ci			PXDaddress(&pxdlock->pxd, addressDXD(newea));
214462306a36Sopenharmony_ci			PXDlength(&pxdlock->pxd, lengthDXD(newea));
214562306a36Sopenharmony_ci			pxdlock++;
214662306a36Sopenharmony_ci			maplock->index = 1;
214762306a36Sopenharmony_ci		} else if (newea->flag & DXD_INLINE) {
214862306a36Sopenharmony_ci			tlck = NULL;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci			set_cflag(COMMIT_Inlineea, ip);
215162306a36Sopenharmony_ci		}
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	/*
215562306a36Sopenharmony_ci	 * format maplock for free of old EA extent
215662306a36Sopenharmony_ci	 */
215762306a36Sopenharmony_ci	if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) {
215862306a36Sopenharmony_ci		if (tlck == NULL) {
215962306a36Sopenharmony_ci			tlck = txMaplock(tid, ip, tlckMAP);
216062306a36Sopenharmony_ci			maplock = (struct pxd_lock *) & tlck->lock;
216162306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) maplock;
216262306a36Sopenharmony_ci			maplock->index = 0;
216362306a36Sopenharmony_ci		}
216462306a36Sopenharmony_ci		pxdlock->flag = mlckFREEPXD;
216562306a36Sopenharmony_ci		PXDaddress(&pxdlock->pxd, addressDXD(oldea));
216662306a36Sopenharmony_ci		PXDlength(&pxdlock->pxd, lengthDXD(oldea));
216762306a36Sopenharmony_ci		maplock->index++;
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci/*
217262306a36Sopenharmony_ci *	txForce()
217362306a36Sopenharmony_ci *
217462306a36Sopenharmony_ci * function: synchronously write pages locked by transaction
217562306a36Sopenharmony_ci *	     after txLog() but before txUpdateMap();
217662306a36Sopenharmony_ci */
217762306a36Sopenharmony_cistatic void txForce(struct tblock * tblk)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	struct tlock *tlck;
218062306a36Sopenharmony_ci	lid_t lid, next;
218162306a36Sopenharmony_ci	struct metapage *mp;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	/*
218462306a36Sopenharmony_ci	 * reverse the order of transaction tlocks in
218562306a36Sopenharmony_ci	 * careful update order of address index pages
218662306a36Sopenharmony_ci	 * (right to left, bottom up)
218762306a36Sopenharmony_ci	 */
218862306a36Sopenharmony_ci	tlck = lid_to_tlock(tblk->next);
218962306a36Sopenharmony_ci	lid = tlck->next;
219062306a36Sopenharmony_ci	tlck->next = 0;
219162306a36Sopenharmony_ci	while (lid) {
219262306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
219362306a36Sopenharmony_ci		next = tlck->next;
219462306a36Sopenharmony_ci		tlck->next = tblk->next;
219562306a36Sopenharmony_ci		tblk->next = lid;
219662306a36Sopenharmony_ci		lid = next;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/*
220062306a36Sopenharmony_ci	 * synchronously write the page, and
220162306a36Sopenharmony_ci	 * hold the page for txUpdateMap();
220262306a36Sopenharmony_ci	 */
220362306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = next) {
220462306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
220562306a36Sopenharmony_ci		next = tlck->next;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci		if ((mp = tlck->mp) != NULL &&
220862306a36Sopenharmony_ci		    (tlck->type & tlckBTROOT) == 0) {
220962306a36Sopenharmony_ci			assert(mp->xflag & COMMIT_PAGE);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci			if (tlck->flag & tlckWRITEPAGE) {
221262306a36Sopenharmony_ci				tlck->flag &= ~tlckWRITEPAGE;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci				/* do not release page to freelist */
221562306a36Sopenharmony_ci				force_metapage(mp);
221662306a36Sopenharmony_ci#if 0
221762306a36Sopenharmony_ci				/*
221862306a36Sopenharmony_ci				 * The "right" thing to do here is to
221962306a36Sopenharmony_ci				 * synchronously write the metadata.
222062306a36Sopenharmony_ci				 * With the current implementation this
222162306a36Sopenharmony_ci				 * is hard since write_metapage requires
222262306a36Sopenharmony_ci				 * us to kunmap & remap the page.  If we
222362306a36Sopenharmony_ci				 * have tlocks pointing into the metadata
222462306a36Sopenharmony_ci				 * pages, we don't want to do this.  I think
222562306a36Sopenharmony_ci				 * we can get by with synchronously writing
222662306a36Sopenharmony_ci				 * the pages when they are released.
222762306a36Sopenharmony_ci				 */
222862306a36Sopenharmony_ci				assert(mp->nohomeok);
222962306a36Sopenharmony_ci				set_bit(META_dirty, &mp->flag);
223062306a36Sopenharmony_ci				set_bit(META_sync, &mp->flag);
223162306a36Sopenharmony_ci#endif
223262306a36Sopenharmony_ci			}
223362306a36Sopenharmony_ci		}
223462306a36Sopenharmony_ci	}
223562306a36Sopenharmony_ci}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci/*
223862306a36Sopenharmony_ci *	txUpdateMap()
223962306a36Sopenharmony_ci *
224062306a36Sopenharmony_ci * function:	update persistent allocation map (and working map
224162306a36Sopenharmony_ci *		if appropriate);
224262306a36Sopenharmony_ci *
224362306a36Sopenharmony_ci * parameter:
224462306a36Sopenharmony_ci */
224562306a36Sopenharmony_cistatic void txUpdateMap(struct tblock * tblk)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	struct inode *ip;
224862306a36Sopenharmony_ci	struct inode *ipimap;
224962306a36Sopenharmony_ci	lid_t lid;
225062306a36Sopenharmony_ci	struct tlock *tlck;
225162306a36Sopenharmony_ci	struct maplock *maplock;
225262306a36Sopenharmony_ci	struct pxd_lock pxdlock;
225362306a36Sopenharmony_ci	int maptype;
225462306a36Sopenharmony_ci	int k, nlock;
225562306a36Sopenharmony_ci	struct metapage *mp = NULL;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	ipimap = JFS_SBI(tblk->sb)->ipimap;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	maptype = (tblk->xflag & COMMIT_PMAP) ? COMMIT_PMAP : COMMIT_PWMAP;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	/*
226362306a36Sopenharmony_ci	 *	update block allocation map
226462306a36Sopenharmony_ci	 *
226562306a36Sopenharmony_ci	 * update allocation state in pmap (and wmap) and
226662306a36Sopenharmony_ci	 * update lsn of the pmap page;
226762306a36Sopenharmony_ci	 */
226862306a36Sopenharmony_ci	/*
226962306a36Sopenharmony_ci	 * scan each tlock/page of transaction for block allocation/free:
227062306a36Sopenharmony_ci	 *
227162306a36Sopenharmony_ci	 * for each tlock/page of transaction, update map.
227262306a36Sopenharmony_ci	 *  ? are there tlock for pmap and pwmap at the same time ?
227362306a36Sopenharmony_ci	 */
227462306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = tlck->next) {
227562306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci		if ((tlck->flag & tlckUPDATEMAP) == 0)
227862306a36Sopenharmony_ci			continue;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		if (tlck->flag & tlckFREEPAGE) {
228162306a36Sopenharmony_ci			/*
228262306a36Sopenharmony_ci			 * Another thread may attempt to reuse freed space
228362306a36Sopenharmony_ci			 * immediately, so we want to get rid of the metapage
228462306a36Sopenharmony_ci			 * before anyone else has a chance to get it.
228562306a36Sopenharmony_ci			 * Lock metapage, update maps, then invalidate
228662306a36Sopenharmony_ci			 * the metapage.
228762306a36Sopenharmony_ci			 */
228862306a36Sopenharmony_ci			mp = tlck->mp;
228962306a36Sopenharmony_ci			ASSERT(mp->xflag & COMMIT_PAGE);
229062306a36Sopenharmony_ci			grab_metapage(mp);
229162306a36Sopenharmony_ci		}
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci		/*
229462306a36Sopenharmony_ci		 * extent list:
229562306a36Sopenharmony_ci		 * . in-line PXD list:
229662306a36Sopenharmony_ci		 * . out-of-line XAD list:
229762306a36Sopenharmony_ci		 */
229862306a36Sopenharmony_ci		maplock = (struct maplock *) & tlck->lock;
229962306a36Sopenharmony_ci		nlock = maplock->index;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		for (k = 0; k < nlock; k++, maplock++) {
230262306a36Sopenharmony_ci			/*
230362306a36Sopenharmony_ci			 * allocate blocks in persistent map:
230462306a36Sopenharmony_ci			 *
230562306a36Sopenharmony_ci			 * blocks have been allocated from wmap at alloc time;
230662306a36Sopenharmony_ci			 */
230762306a36Sopenharmony_ci			if (maplock->flag & mlckALLOC) {
230862306a36Sopenharmony_ci				txAllocPMap(ipimap, maplock, tblk);
230962306a36Sopenharmony_ci			}
231062306a36Sopenharmony_ci			/*
231162306a36Sopenharmony_ci			 * free blocks in persistent and working map:
231262306a36Sopenharmony_ci			 * blocks will be freed in pmap and then in wmap;
231362306a36Sopenharmony_ci			 *
231462306a36Sopenharmony_ci			 * ? tblock specifies the PMAP/PWMAP based upon
231562306a36Sopenharmony_ci			 * transaction
231662306a36Sopenharmony_ci			 *
231762306a36Sopenharmony_ci			 * free blocks in persistent map:
231862306a36Sopenharmony_ci			 * blocks will be freed from wmap at last reference
231962306a36Sopenharmony_ci			 * release of the object for regular files;
232062306a36Sopenharmony_ci			 *
232162306a36Sopenharmony_ci			 * Alway free blocks from both persistent & working
232262306a36Sopenharmony_ci			 * maps for directories
232362306a36Sopenharmony_ci			 */
232462306a36Sopenharmony_ci			else {	/* (maplock->flag & mlckFREE) */
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci				if (tlck->flag & tlckDIRECTORY)
232762306a36Sopenharmony_ci					txFreeMap(ipimap, maplock,
232862306a36Sopenharmony_ci						  tblk, COMMIT_PWMAP);
232962306a36Sopenharmony_ci				else
233062306a36Sopenharmony_ci					txFreeMap(ipimap, maplock,
233162306a36Sopenharmony_ci						  tblk, maptype);
233262306a36Sopenharmony_ci			}
233362306a36Sopenharmony_ci		}
233462306a36Sopenharmony_ci		if (tlck->flag & tlckFREEPAGE) {
233562306a36Sopenharmony_ci			if (!(tblk->flag & tblkGC_LAZY)) {
233662306a36Sopenharmony_ci				/* This is equivalent to txRelease */
233762306a36Sopenharmony_ci				ASSERT(mp->lid == lid);
233862306a36Sopenharmony_ci				tlck->mp->lid = 0;
233962306a36Sopenharmony_ci			}
234062306a36Sopenharmony_ci			assert(mp->nohomeok == 1);
234162306a36Sopenharmony_ci			metapage_homeok(mp);
234262306a36Sopenharmony_ci			discard_metapage(mp);
234362306a36Sopenharmony_ci			tlck->mp = NULL;
234462306a36Sopenharmony_ci		}
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci	/*
234762306a36Sopenharmony_ci	 *	update inode allocation map
234862306a36Sopenharmony_ci	 *
234962306a36Sopenharmony_ci	 * update allocation state in pmap and
235062306a36Sopenharmony_ci	 * update lsn of the pmap page;
235162306a36Sopenharmony_ci	 * update in-memory inode flag/state
235262306a36Sopenharmony_ci	 *
235362306a36Sopenharmony_ci	 * unlock mapper/write lock
235462306a36Sopenharmony_ci	 */
235562306a36Sopenharmony_ci	if (tblk->xflag & COMMIT_CREATE) {
235662306a36Sopenharmony_ci		diUpdatePMap(ipimap, tblk->ino, false, tblk);
235762306a36Sopenharmony_ci		/* update persistent block allocation map
235862306a36Sopenharmony_ci		 * for the allocation of inode extent;
235962306a36Sopenharmony_ci		 */
236062306a36Sopenharmony_ci		pxdlock.flag = mlckALLOCPXD;
236162306a36Sopenharmony_ci		pxdlock.pxd = tblk->u.ixpxd;
236262306a36Sopenharmony_ci		pxdlock.index = 1;
236362306a36Sopenharmony_ci		txAllocPMap(ipimap, (struct maplock *) & pxdlock, tblk);
236462306a36Sopenharmony_ci	} else if (tblk->xflag & COMMIT_DELETE) {
236562306a36Sopenharmony_ci		ip = tblk->u.ip;
236662306a36Sopenharmony_ci		diUpdatePMap(ipimap, ip->i_ino, true, tblk);
236762306a36Sopenharmony_ci		iput(ip);
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci/*
237262306a36Sopenharmony_ci *	txAllocPMap()
237362306a36Sopenharmony_ci *
237462306a36Sopenharmony_ci * function: allocate from persistent map;
237562306a36Sopenharmony_ci *
237662306a36Sopenharmony_ci * parameter:
237762306a36Sopenharmony_ci *	ipbmap	-
237862306a36Sopenharmony_ci *	malock	-
237962306a36Sopenharmony_ci *		xad list:
238062306a36Sopenharmony_ci *		pxd:
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci *	maptype -
238362306a36Sopenharmony_ci *		allocate from persistent map;
238462306a36Sopenharmony_ci *		free from persistent map;
238562306a36Sopenharmony_ci *		(e.g., tmp file - free from working map at releae
238662306a36Sopenharmony_ci *		 of last reference);
238762306a36Sopenharmony_ci *		free from persistent and working map;
238862306a36Sopenharmony_ci *
238962306a36Sopenharmony_ci *	lsn	- log sequence number;
239062306a36Sopenharmony_ci */
239162306a36Sopenharmony_cistatic void txAllocPMap(struct inode *ip, struct maplock * maplock,
239262306a36Sopenharmony_ci			struct tblock * tblk)
239362306a36Sopenharmony_ci{
239462306a36Sopenharmony_ci	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
239562306a36Sopenharmony_ci	struct xdlistlock *xadlistlock;
239662306a36Sopenharmony_ci	xad_t *xad;
239762306a36Sopenharmony_ci	s64 xaddr;
239862306a36Sopenharmony_ci	int xlen;
239962306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
240062306a36Sopenharmony_ci	struct xdlistlock *pxdlistlock;
240162306a36Sopenharmony_ci	pxd_t *pxd;
240262306a36Sopenharmony_ci	int n;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/*
240562306a36Sopenharmony_ci	 * allocate from persistent map;
240662306a36Sopenharmony_ci	 */
240762306a36Sopenharmony_ci	if (maplock->flag & mlckALLOCXADLIST) {
240862306a36Sopenharmony_ci		xadlistlock = (struct xdlistlock *) maplock;
240962306a36Sopenharmony_ci		xad = xadlistlock->xdlist;
241062306a36Sopenharmony_ci		for (n = 0; n < xadlistlock->count; n++, xad++) {
241162306a36Sopenharmony_ci			if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
241262306a36Sopenharmony_ci				xaddr = addressXAD(xad);
241362306a36Sopenharmony_ci				xlen = lengthXAD(xad);
241462306a36Sopenharmony_ci				dbUpdatePMap(ipbmap, false, xaddr,
241562306a36Sopenharmony_ci					     (s64) xlen, tblk);
241662306a36Sopenharmony_ci				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
241762306a36Sopenharmony_ci				jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
241862306a36Sopenharmony_ci					 (ulong) xaddr, xlen);
241962306a36Sopenharmony_ci			}
242062306a36Sopenharmony_ci		}
242162306a36Sopenharmony_ci	} else if (maplock->flag & mlckALLOCPXD) {
242262306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) maplock;
242362306a36Sopenharmony_ci		xaddr = addressPXD(&pxdlock->pxd);
242462306a36Sopenharmony_ci		xlen = lengthPXD(&pxdlock->pxd);
242562306a36Sopenharmony_ci		dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen, tblk);
242662306a36Sopenharmony_ci		jfs_info("allocPMap: xaddr:0x%lx xlen:%d", (ulong) xaddr, xlen);
242762306a36Sopenharmony_ci	} else {		/* (maplock->flag & mlckALLOCPXDLIST) */
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci		pxdlistlock = (struct xdlistlock *) maplock;
243062306a36Sopenharmony_ci		pxd = pxdlistlock->xdlist;
243162306a36Sopenharmony_ci		for (n = 0; n < pxdlistlock->count; n++, pxd++) {
243262306a36Sopenharmony_ci			xaddr = addressPXD(pxd);
243362306a36Sopenharmony_ci			xlen = lengthPXD(pxd);
243462306a36Sopenharmony_ci			dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen,
243562306a36Sopenharmony_ci				     tblk);
243662306a36Sopenharmony_ci			jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
243762306a36Sopenharmony_ci				 (ulong) xaddr, xlen);
243862306a36Sopenharmony_ci		}
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci/*
244362306a36Sopenharmony_ci *	txFreeMap()
244462306a36Sopenharmony_ci *
244562306a36Sopenharmony_ci * function:	free from persistent and/or working map;
244662306a36Sopenharmony_ci *
244762306a36Sopenharmony_ci * todo: optimization
244862306a36Sopenharmony_ci */
244962306a36Sopenharmony_civoid txFreeMap(struct inode *ip,
245062306a36Sopenharmony_ci	       struct maplock * maplock, struct tblock * tblk, int maptype)
245162306a36Sopenharmony_ci{
245262306a36Sopenharmony_ci	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
245362306a36Sopenharmony_ci	struct xdlistlock *xadlistlock;
245462306a36Sopenharmony_ci	xad_t *xad;
245562306a36Sopenharmony_ci	s64 xaddr;
245662306a36Sopenharmony_ci	int xlen;
245762306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
245862306a36Sopenharmony_ci	struct xdlistlock *pxdlistlock;
245962306a36Sopenharmony_ci	pxd_t *pxd;
246062306a36Sopenharmony_ci	int n;
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	jfs_info("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x",
246362306a36Sopenharmony_ci		 tblk, maplock, maptype);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	/*
246662306a36Sopenharmony_ci	 * free from persistent map;
246762306a36Sopenharmony_ci	 */
246862306a36Sopenharmony_ci	if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) {
246962306a36Sopenharmony_ci		if (maplock->flag & mlckFREEXADLIST) {
247062306a36Sopenharmony_ci			xadlistlock = (struct xdlistlock *) maplock;
247162306a36Sopenharmony_ci			xad = xadlistlock->xdlist;
247262306a36Sopenharmony_ci			for (n = 0; n < xadlistlock->count; n++, xad++) {
247362306a36Sopenharmony_ci				if (!(xad->flag & XAD_NEW)) {
247462306a36Sopenharmony_ci					xaddr = addressXAD(xad);
247562306a36Sopenharmony_ci					xlen = lengthXAD(xad);
247662306a36Sopenharmony_ci					dbUpdatePMap(ipbmap, true, xaddr,
247762306a36Sopenharmony_ci						     (s64) xlen, tblk);
247862306a36Sopenharmony_ci					jfs_info("freePMap: xaddr:0x%lx xlen:%d",
247962306a36Sopenharmony_ci						 (ulong) xaddr, xlen);
248062306a36Sopenharmony_ci				}
248162306a36Sopenharmony_ci			}
248262306a36Sopenharmony_ci		} else if (maplock->flag & mlckFREEPXD) {
248362306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) maplock;
248462306a36Sopenharmony_ci			xaddr = addressPXD(&pxdlock->pxd);
248562306a36Sopenharmony_ci			xlen = lengthPXD(&pxdlock->pxd);
248662306a36Sopenharmony_ci			dbUpdatePMap(ipbmap, true, xaddr, (s64) xlen,
248762306a36Sopenharmony_ci				     tblk);
248862306a36Sopenharmony_ci			jfs_info("freePMap: xaddr:0x%lx xlen:%d",
248962306a36Sopenharmony_ci				 (ulong) xaddr, xlen);
249062306a36Sopenharmony_ci		} else {	/* (maplock->flag & mlckALLOCPXDLIST) */
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci			pxdlistlock = (struct xdlistlock *) maplock;
249362306a36Sopenharmony_ci			pxd = pxdlistlock->xdlist;
249462306a36Sopenharmony_ci			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
249562306a36Sopenharmony_ci				xaddr = addressPXD(pxd);
249662306a36Sopenharmony_ci				xlen = lengthPXD(pxd);
249762306a36Sopenharmony_ci				dbUpdatePMap(ipbmap, true, xaddr,
249862306a36Sopenharmony_ci					     (s64) xlen, tblk);
249962306a36Sopenharmony_ci				jfs_info("freePMap: xaddr:0x%lx xlen:%d",
250062306a36Sopenharmony_ci					 (ulong) xaddr, xlen);
250162306a36Sopenharmony_ci			}
250262306a36Sopenharmony_ci		}
250362306a36Sopenharmony_ci	}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	/*
250662306a36Sopenharmony_ci	 * free from working map;
250762306a36Sopenharmony_ci	 */
250862306a36Sopenharmony_ci	if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) {
250962306a36Sopenharmony_ci		if (maplock->flag & mlckFREEXADLIST) {
251062306a36Sopenharmony_ci			xadlistlock = (struct xdlistlock *) maplock;
251162306a36Sopenharmony_ci			xad = xadlistlock->xdlist;
251262306a36Sopenharmony_ci			for (n = 0; n < xadlistlock->count; n++, xad++) {
251362306a36Sopenharmony_ci				xaddr = addressXAD(xad);
251462306a36Sopenharmony_ci				xlen = lengthXAD(xad);
251562306a36Sopenharmony_ci				dbFree(ip, xaddr, (s64) xlen);
251662306a36Sopenharmony_ci				xad->flag = 0;
251762306a36Sopenharmony_ci				jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
251862306a36Sopenharmony_ci					 (ulong) xaddr, xlen);
251962306a36Sopenharmony_ci			}
252062306a36Sopenharmony_ci		} else if (maplock->flag & mlckFREEPXD) {
252162306a36Sopenharmony_ci			pxdlock = (struct pxd_lock *) maplock;
252262306a36Sopenharmony_ci			xaddr = addressPXD(&pxdlock->pxd);
252362306a36Sopenharmony_ci			xlen = lengthPXD(&pxdlock->pxd);
252462306a36Sopenharmony_ci			dbFree(ip, xaddr, (s64) xlen);
252562306a36Sopenharmony_ci			jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
252662306a36Sopenharmony_ci				 (ulong) xaddr, xlen);
252762306a36Sopenharmony_ci		} else {	/* (maplock->flag & mlckFREEPXDLIST) */
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci			pxdlistlock = (struct xdlistlock *) maplock;
253062306a36Sopenharmony_ci			pxd = pxdlistlock->xdlist;
253162306a36Sopenharmony_ci			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
253262306a36Sopenharmony_ci				xaddr = addressPXD(pxd);
253362306a36Sopenharmony_ci				xlen = lengthPXD(pxd);
253462306a36Sopenharmony_ci				dbFree(ip, xaddr, (s64) xlen);
253562306a36Sopenharmony_ci				jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
253662306a36Sopenharmony_ci					 (ulong) xaddr, xlen);
253762306a36Sopenharmony_ci			}
253862306a36Sopenharmony_ci		}
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci/*
254362306a36Sopenharmony_ci *	txFreelock()
254462306a36Sopenharmony_ci *
254562306a36Sopenharmony_ci * function:	remove tlock from inode anonymous locklist
254662306a36Sopenharmony_ci */
254762306a36Sopenharmony_civoid txFreelock(struct inode *ip)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
255062306a36Sopenharmony_ci	struct tlock *xtlck, *tlck;
255162306a36Sopenharmony_ci	lid_t xlid = 0, lid;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	if (!jfs_ip->atlhead)
255462306a36Sopenharmony_ci		return;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	TXN_LOCK();
255762306a36Sopenharmony_ci	xtlck = (struct tlock *) &jfs_ip->atlhead;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	while ((lid = xtlck->next) != 0) {
256062306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
256162306a36Sopenharmony_ci		if (tlck->flag & tlckFREELOCK) {
256262306a36Sopenharmony_ci			xtlck->next = tlck->next;
256362306a36Sopenharmony_ci			txLockFree(lid);
256462306a36Sopenharmony_ci		} else {
256562306a36Sopenharmony_ci			xtlck = tlck;
256662306a36Sopenharmony_ci			xlid = lid;
256762306a36Sopenharmony_ci		}
256862306a36Sopenharmony_ci	}
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	if (jfs_ip->atlhead)
257162306a36Sopenharmony_ci		jfs_ip->atltail = xlid;
257262306a36Sopenharmony_ci	else {
257362306a36Sopenharmony_ci		jfs_ip->atltail = 0;
257462306a36Sopenharmony_ci		/*
257562306a36Sopenharmony_ci		 * If inode was on anon_list, remove it
257662306a36Sopenharmony_ci		 */
257762306a36Sopenharmony_ci		list_del_init(&jfs_ip->anon_inode_list);
257862306a36Sopenharmony_ci	}
257962306a36Sopenharmony_ci	TXN_UNLOCK();
258062306a36Sopenharmony_ci}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci/*
258362306a36Sopenharmony_ci *	txAbort()
258462306a36Sopenharmony_ci *
258562306a36Sopenharmony_ci * function: abort tx before commit;
258662306a36Sopenharmony_ci *
258762306a36Sopenharmony_ci * frees line-locks and segment locks for all
258862306a36Sopenharmony_ci * segments in comdata structure.
258962306a36Sopenharmony_ci * Optionally sets state of file-system to FM_DIRTY in super-block.
259062306a36Sopenharmony_ci * log age of page-frames in memory for which caller has
259162306a36Sopenharmony_ci * are reset to 0 (to avoid logwarap).
259262306a36Sopenharmony_ci */
259362306a36Sopenharmony_civoid txAbort(tid_t tid, int dirty)
259462306a36Sopenharmony_ci{
259562306a36Sopenharmony_ci	lid_t lid, next;
259662306a36Sopenharmony_ci	struct metapage *mp;
259762306a36Sopenharmony_ci	struct tblock *tblk = tid_to_tblock(tid);
259862306a36Sopenharmony_ci	struct tlock *tlck;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	/*
260162306a36Sopenharmony_ci	 * free tlocks of the transaction
260262306a36Sopenharmony_ci	 */
260362306a36Sopenharmony_ci	for (lid = tblk->next; lid; lid = next) {
260462306a36Sopenharmony_ci		tlck = lid_to_tlock(lid);
260562306a36Sopenharmony_ci		next = tlck->next;
260662306a36Sopenharmony_ci		mp = tlck->mp;
260762306a36Sopenharmony_ci		JFS_IP(tlck->ip)->xtlid = 0;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci		if (mp) {
261062306a36Sopenharmony_ci			mp->lid = 0;
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci			/*
261362306a36Sopenharmony_ci			 * reset lsn of page to avoid logwarap:
261462306a36Sopenharmony_ci			 *
261562306a36Sopenharmony_ci			 * (page may have been previously committed by another
261662306a36Sopenharmony_ci			 * transaction(s) but has not been paged, i.e.,
261762306a36Sopenharmony_ci			 * it may be on logsync list even though it has not
261862306a36Sopenharmony_ci			 * been logged for the current tx.)
261962306a36Sopenharmony_ci			 */
262062306a36Sopenharmony_ci			if (mp->xflag & COMMIT_PAGE && mp->lsn)
262162306a36Sopenharmony_ci				LogSyncRelease(mp);
262262306a36Sopenharmony_ci		}
262362306a36Sopenharmony_ci		/* insert tlock at head of freelist */
262462306a36Sopenharmony_ci		TXN_LOCK();
262562306a36Sopenharmony_ci		txLockFree(lid);
262662306a36Sopenharmony_ci		TXN_UNLOCK();
262762306a36Sopenharmony_ci	}
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	/* caller will free the transaction block */
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	tblk->next = tblk->last = 0;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	/*
263462306a36Sopenharmony_ci	 * mark filesystem dirty
263562306a36Sopenharmony_ci	 */
263662306a36Sopenharmony_ci	if (dirty)
263762306a36Sopenharmony_ci		jfs_error(tblk->sb, "\n");
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	return;
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci/*
264362306a36Sopenharmony_ci *	txLazyCommit(void)
264462306a36Sopenharmony_ci *
264562306a36Sopenharmony_ci *	All transactions except those changing ipimap (COMMIT_FORCE) are
264662306a36Sopenharmony_ci *	processed by this routine.  This insures that the inode and block
264762306a36Sopenharmony_ci *	allocation maps are updated in order.  For synchronous transactions,
264862306a36Sopenharmony_ci *	let the user thread finish processing after txUpdateMap() is called.
264962306a36Sopenharmony_ci */
265062306a36Sopenharmony_cistatic void txLazyCommit(struct tblock * tblk)
265162306a36Sopenharmony_ci{
265262306a36Sopenharmony_ci	struct jfs_log *log;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	while (((tblk->flag & tblkGC_READY) == 0) &&
265562306a36Sopenharmony_ci	       ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
265662306a36Sopenharmony_ci		/* We must have gotten ahead of the user thread
265762306a36Sopenharmony_ci		 */
265862306a36Sopenharmony_ci		jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk);
265962306a36Sopenharmony_ci		yield();
266062306a36Sopenharmony_ci	}
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	txUpdateMap(tblk);
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	tblk->flag |= tblkGC_COMMITTED;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	if (tblk->flag & tblkGC_READY)
267362306a36Sopenharmony_ci		log->gcrtc--;
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	wake_up_all(&tblk->gcwait);	// LOGGC_WAKEUP
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	/*
267862306a36Sopenharmony_ci	 * Can't release log->gclock until we've tested tblk->flag
267962306a36Sopenharmony_ci	 */
268062306a36Sopenharmony_ci	if (tblk->flag & tblkGC_LAZY) {
268162306a36Sopenharmony_ci		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
268262306a36Sopenharmony_ci		txUnlock(tblk);
268362306a36Sopenharmony_ci		tblk->flag &= ~tblkGC_LAZY;
268462306a36Sopenharmony_ci		txEnd(tblk - TxBlock);	/* Convert back to tid */
268562306a36Sopenharmony_ci	} else
268662306a36Sopenharmony_ci		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	jfs_info("txLazyCommit: done: tblk = 0x%p", tblk);
268962306a36Sopenharmony_ci}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci/*
269262306a36Sopenharmony_ci *	jfs_lazycommit(void)
269362306a36Sopenharmony_ci *
269462306a36Sopenharmony_ci *	To be run as a kernel daemon.  If lbmIODone is called in an interrupt
269562306a36Sopenharmony_ci *	context, or where blocking is not wanted, this routine will process
269662306a36Sopenharmony_ci *	committed transactions from the unlock queue.
269762306a36Sopenharmony_ci */
269862306a36Sopenharmony_ciint jfs_lazycommit(void *arg)
269962306a36Sopenharmony_ci{
270062306a36Sopenharmony_ci	int WorkDone;
270162306a36Sopenharmony_ci	struct tblock *tblk;
270262306a36Sopenharmony_ci	unsigned long flags;
270362306a36Sopenharmony_ci	struct jfs_sb_info *sbi;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	do {
270662306a36Sopenharmony_ci		LAZY_LOCK(flags);
270762306a36Sopenharmony_ci		jfs_commit_thread_waking = 0;	/* OK to wake another thread */
270862306a36Sopenharmony_ci		while (!list_empty(&TxAnchor.unlock_queue)) {
270962306a36Sopenharmony_ci			WorkDone = 0;
271062306a36Sopenharmony_ci			list_for_each_entry(tblk, &TxAnchor.unlock_queue,
271162306a36Sopenharmony_ci					    cqueue) {
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci				sbi = JFS_SBI(tblk->sb);
271462306a36Sopenharmony_ci				/*
271562306a36Sopenharmony_ci				 * For each volume, the transactions must be
271662306a36Sopenharmony_ci				 * handled in order.  If another commit thread
271762306a36Sopenharmony_ci				 * is handling a tblk for this superblock,
271862306a36Sopenharmony_ci				 * skip it
271962306a36Sopenharmony_ci				 */
272062306a36Sopenharmony_ci				if (sbi->commit_state & IN_LAZYCOMMIT)
272162306a36Sopenharmony_ci					continue;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci				sbi->commit_state |= IN_LAZYCOMMIT;
272462306a36Sopenharmony_ci				WorkDone = 1;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci				/*
272762306a36Sopenharmony_ci				 * Remove transaction from queue
272862306a36Sopenharmony_ci				 */
272962306a36Sopenharmony_ci				list_del(&tblk->cqueue);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci				LAZY_UNLOCK(flags);
273262306a36Sopenharmony_ci				txLazyCommit(tblk);
273362306a36Sopenharmony_ci				LAZY_LOCK(flags);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci				sbi->commit_state &= ~IN_LAZYCOMMIT;
273662306a36Sopenharmony_ci				/*
273762306a36Sopenharmony_ci				 * Don't continue in the for loop.  (We can't
273862306a36Sopenharmony_ci				 * anyway, it's unsafe!)  We want to go back to
273962306a36Sopenharmony_ci				 * the beginning of the list.
274062306a36Sopenharmony_ci				 */
274162306a36Sopenharmony_ci				break;
274262306a36Sopenharmony_ci			}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci			/* If there was nothing to do, don't continue */
274562306a36Sopenharmony_ci			if (!WorkDone)
274662306a36Sopenharmony_ci				break;
274762306a36Sopenharmony_ci		}
274862306a36Sopenharmony_ci		/* In case a wakeup came while all threads were active */
274962306a36Sopenharmony_ci		jfs_commit_thread_waking = 0;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci		if (freezing(current)) {
275262306a36Sopenharmony_ci			LAZY_UNLOCK(flags);
275362306a36Sopenharmony_ci			try_to_freeze();
275462306a36Sopenharmony_ci		} else {
275562306a36Sopenharmony_ci			DECLARE_WAITQUEUE(wq, current);
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci			add_wait_queue(&jfs_commit_thread_wait, &wq);
275862306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
275962306a36Sopenharmony_ci			LAZY_UNLOCK(flags);
276062306a36Sopenharmony_ci			schedule();
276162306a36Sopenharmony_ci			remove_wait_queue(&jfs_commit_thread_wait, &wq);
276262306a36Sopenharmony_ci		}
276362306a36Sopenharmony_ci	} while (!kthread_should_stop());
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	if (!list_empty(&TxAnchor.unlock_queue))
276662306a36Sopenharmony_ci		jfs_err("jfs_lazycommit being killed w/pending transactions!");
276762306a36Sopenharmony_ci	else
276862306a36Sopenharmony_ci		jfs_info("jfs_lazycommit being killed");
276962306a36Sopenharmony_ci	return 0;
277062306a36Sopenharmony_ci}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_civoid txLazyUnlock(struct tblock * tblk)
277362306a36Sopenharmony_ci{
277462306a36Sopenharmony_ci	unsigned long flags;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	LAZY_LOCK(flags);
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
277962306a36Sopenharmony_ci	/*
278062306a36Sopenharmony_ci	 * Don't wake up a commit thread if there is already one servicing
278162306a36Sopenharmony_ci	 * this superblock, or if the last one we woke up hasn't started yet.
278262306a36Sopenharmony_ci	 */
278362306a36Sopenharmony_ci	if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT) &&
278462306a36Sopenharmony_ci	    !jfs_commit_thread_waking) {
278562306a36Sopenharmony_ci		jfs_commit_thread_waking = 1;
278662306a36Sopenharmony_ci		wake_up(&jfs_commit_thread_wait);
278762306a36Sopenharmony_ci	}
278862306a36Sopenharmony_ci	LAZY_UNLOCK(flags);
278962306a36Sopenharmony_ci}
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_cistatic void LogSyncRelease(struct metapage * mp)
279262306a36Sopenharmony_ci{
279362306a36Sopenharmony_ci	struct jfs_log *log = mp->log;
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	assert(mp->nohomeok);
279662306a36Sopenharmony_ci	assert(log);
279762306a36Sopenharmony_ci	metapage_homeok(mp);
279862306a36Sopenharmony_ci}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci/*
280162306a36Sopenharmony_ci *	txQuiesce
280262306a36Sopenharmony_ci *
280362306a36Sopenharmony_ci *	Block all new transactions and push anonymous transactions to
280462306a36Sopenharmony_ci *	completion
280562306a36Sopenharmony_ci *
280662306a36Sopenharmony_ci *	This does almost the same thing as jfs_sync below.  We don't
280762306a36Sopenharmony_ci *	worry about deadlocking when jfs_tlocks_low is set, since we would
280862306a36Sopenharmony_ci *	expect jfs_sync to get us out of that jam.
280962306a36Sopenharmony_ci */
281062306a36Sopenharmony_civoid txQuiesce(struct super_block *sb)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	struct inode *ip;
281362306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip;
281462306a36Sopenharmony_ci	struct jfs_log *log = JFS_SBI(sb)->log;
281562306a36Sopenharmony_ci	tid_t tid;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	set_bit(log_QUIESCE, &log->flag);
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	TXN_LOCK();
282062306a36Sopenharmony_cirestart:
282162306a36Sopenharmony_ci	while (!list_empty(&TxAnchor.anon_list)) {
282262306a36Sopenharmony_ci		jfs_ip = list_entry(TxAnchor.anon_list.next,
282362306a36Sopenharmony_ci				    struct jfs_inode_info,
282462306a36Sopenharmony_ci				    anon_inode_list);
282562306a36Sopenharmony_ci		ip = &jfs_ip->vfs_inode;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci		/*
282862306a36Sopenharmony_ci		 * inode will be removed from anonymous list
282962306a36Sopenharmony_ci		 * when it is committed
283062306a36Sopenharmony_ci		 */
283162306a36Sopenharmony_ci		TXN_UNLOCK();
283262306a36Sopenharmony_ci		tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
283362306a36Sopenharmony_ci		mutex_lock(&jfs_ip->commit_mutex);
283462306a36Sopenharmony_ci		txCommit(tid, 1, &ip, 0);
283562306a36Sopenharmony_ci		txEnd(tid);
283662306a36Sopenharmony_ci		mutex_unlock(&jfs_ip->commit_mutex);
283762306a36Sopenharmony_ci		/*
283862306a36Sopenharmony_ci		 * Just to be safe.  I don't know how
283962306a36Sopenharmony_ci		 * long we can run without blocking
284062306a36Sopenharmony_ci		 */
284162306a36Sopenharmony_ci		cond_resched();
284262306a36Sopenharmony_ci		TXN_LOCK();
284362306a36Sopenharmony_ci	}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	/*
284662306a36Sopenharmony_ci	 * If jfs_sync is running in parallel, there could be some inodes
284762306a36Sopenharmony_ci	 * on anon_list2.  Let's check.
284862306a36Sopenharmony_ci	 */
284962306a36Sopenharmony_ci	if (!list_empty(&TxAnchor.anon_list2)) {
285062306a36Sopenharmony_ci		list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
285162306a36Sopenharmony_ci		goto restart;
285262306a36Sopenharmony_ci	}
285362306a36Sopenharmony_ci	TXN_UNLOCK();
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	/*
285662306a36Sopenharmony_ci	 * We may need to kick off the group commit
285762306a36Sopenharmony_ci	 */
285862306a36Sopenharmony_ci	jfs_flush_journal(log, 0);
285962306a36Sopenharmony_ci}
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci/*
286262306a36Sopenharmony_ci * txResume()
286362306a36Sopenharmony_ci *
286462306a36Sopenharmony_ci * Allows transactions to start again following txQuiesce
286562306a36Sopenharmony_ci */
286662306a36Sopenharmony_civoid txResume(struct super_block *sb)
286762306a36Sopenharmony_ci{
286862306a36Sopenharmony_ci	struct jfs_log *log = JFS_SBI(sb)->log;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	clear_bit(log_QUIESCE, &log->flag);
287162306a36Sopenharmony_ci	TXN_WAKEUP(&log->syncwait);
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci/*
287562306a36Sopenharmony_ci *	jfs_sync(void)
287662306a36Sopenharmony_ci *
287762306a36Sopenharmony_ci *	To be run as a kernel daemon.  This is awakened when tlocks run low.
287862306a36Sopenharmony_ci *	We write any inodes that have anonymous tlocks so they will become
287962306a36Sopenharmony_ci *	available.
288062306a36Sopenharmony_ci */
288162306a36Sopenharmony_ciint jfs_sync(void *arg)
288262306a36Sopenharmony_ci{
288362306a36Sopenharmony_ci	struct inode *ip;
288462306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip;
288562306a36Sopenharmony_ci	tid_t tid;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	do {
288862306a36Sopenharmony_ci		/*
288962306a36Sopenharmony_ci		 * write each inode on the anonymous inode list
289062306a36Sopenharmony_ci		 */
289162306a36Sopenharmony_ci		TXN_LOCK();
289262306a36Sopenharmony_ci		while (jfs_tlocks_low && !list_empty(&TxAnchor.anon_list)) {
289362306a36Sopenharmony_ci			jfs_ip = list_entry(TxAnchor.anon_list.next,
289462306a36Sopenharmony_ci					    struct jfs_inode_info,
289562306a36Sopenharmony_ci					    anon_inode_list);
289662306a36Sopenharmony_ci			ip = &jfs_ip->vfs_inode;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci			if (! igrab(ip)) {
289962306a36Sopenharmony_ci				/*
290062306a36Sopenharmony_ci				 * Inode is being freed
290162306a36Sopenharmony_ci				 */
290262306a36Sopenharmony_ci				list_del_init(&jfs_ip->anon_inode_list);
290362306a36Sopenharmony_ci			} else if (mutex_trylock(&jfs_ip->commit_mutex)) {
290462306a36Sopenharmony_ci				/*
290562306a36Sopenharmony_ci				 * inode will be removed from anonymous list
290662306a36Sopenharmony_ci				 * when it is committed
290762306a36Sopenharmony_ci				 */
290862306a36Sopenharmony_ci				TXN_UNLOCK();
290962306a36Sopenharmony_ci				tid = txBegin(ip->i_sb, COMMIT_INODE);
291062306a36Sopenharmony_ci				txCommit(tid, 1, &ip, 0);
291162306a36Sopenharmony_ci				txEnd(tid);
291262306a36Sopenharmony_ci				mutex_unlock(&jfs_ip->commit_mutex);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci				iput(ip);
291562306a36Sopenharmony_ci				/*
291662306a36Sopenharmony_ci				 * Just to be safe.  I don't know how
291762306a36Sopenharmony_ci				 * long we can run without blocking
291862306a36Sopenharmony_ci				 */
291962306a36Sopenharmony_ci				cond_resched();
292062306a36Sopenharmony_ci				TXN_LOCK();
292162306a36Sopenharmony_ci			} else {
292262306a36Sopenharmony_ci				/* We can't get the commit mutex.  It may
292362306a36Sopenharmony_ci				 * be held by a thread waiting for tlock's
292462306a36Sopenharmony_ci				 * so let's not block here.  Save it to
292562306a36Sopenharmony_ci				 * put back on the anon_list.
292662306a36Sopenharmony_ci				 */
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci				/* Move from anon_list to anon_list2 */
292962306a36Sopenharmony_ci				list_move(&jfs_ip->anon_inode_list,
293062306a36Sopenharmony_ci					  &TxAnchor.anon_list2);
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci				TXN_UNLOCK();
293362306a36Sopenharmony_ci				iput(ip);
293462306a36Sopenharmony_ci				TXN_LOCK();
293562306a36Sopenharmony_ci			}
293662306a36Sopenharmony_ci		}
293762306a36Sopenharmony_ci		/* Add anon_list2 back to anon_list */
293862306a36Sopenharmony_ci		list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci		if (freezing(current)) {
294162306a36Sopenharmony_ci			TXN_UNLOCK();
294262306a36Sopenharmony_ci			try_to_freeze();
294362306a36Sopenharmony_ci		} else {
294462306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
294562306a36Sopenharmony_ci			TXN_UNLOCK();
294662306a36Sopenharmony_ci			schedule();
294762306a36Sopenharmony_ci		}
294862306a36Sopenharmony_ci	} while (!kthread_should_stop());
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	jfs_info("jfs_sync being killed");
295162306a36Sopenharmony_ci	return 0;
295262306a36Sopenharmony_ci}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
295562306a36Sopenharmony_ciint jfs_txanchor_proc_show(struct seq_file *m, void *v)
295662306a36Sopenharmony_ci{
295762306a36Sopenharmony_ci	char *freewait;
295862306a36Sopenharmony_ci	char *freelockwait;
295962306a36Sopenharmony_ci	char *lowlockwait;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	freewait =
296262306a36Sopenharmony_ci	    waitqueue_active(&TxAnchor.freewait) ? "active" : "empty";
296362306a36Sopenharmony_ci	freelockwait =
296462306a36Sopenharmony_ci	    waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty";
296562306a36Sopenharmony_ci	lowlockwait =
296662306a36Sopenharmony_ci	    waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	seq_printf(m,
296962306a36Sopenharmony_ci		       "JFS TxAnchor\n"
297062306a36Sopenharmony_ci		       "============\n"
297162306a36Sopenharmony_ci		       "freetid = %d\n"
297262306a36Sopenharmony_ci		       "freewait = %s\n"
297362306a36Sopenharmony_ci		       "freelock = %d\n"
297462306a36Sopenharmony_ci		       "freelockwait = %s\n"
297562306a36Sopenharmony_ci		       "lowlockwait = %s\n"
297662306a36Sopenharmony_ci		       "tlocksInUse = %d\n"
297762306a36Sopenharmony_ci		       "jfs_tlocks_low = %d\n"
297862306a36Sopenharmony_ci		       "unlock_queue is %sempty\n",
297962306a36Sopenharmony_ci		       TxAnchor.freetid,
298062306a36Sopenharmony_ci		       freewait,
298162306a36Sopenharmony_ci		       TxAnchor.freelock,
298262306a36Sopenharmony_ci		       freelockwait,
298362306a36Sopenharmony_ci		       lowlockwait,
298462306a36Sopenharmony_ci		       TxAnchor.tlocksInUse,
298562306a36Sopenharmony_ci		       jfs_tlocks_low,
298662306a36Sopenharmony_ci		       list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
298762306a36Sopenharmony_ci	return 0;
298862306a36Sopenharmony_ci}
298962306a36Sopenharmony_ci#endif
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_STATISTICS)
299262306a36Sopenharmony_ciint jfs_txstats_proc_show(struct seq_file *m, void *v)
299362306a36Sopenharmony_ci{
299462306a36Sopenharmony_ci	seq_printf(m,
299562306a36Sopenharmony_ci		       "JFS TxStats\n"
299662306a36Sopenharmony_ci		       "===========\n"
299762306a36Sopenharmony_ci		       "calls to txBegin = %d\n"
299862306a36Sopenharmony_ci		       "txBegin blocked by sync barrier = %d\n"
299962306a36Sopenharmony_ci		       "txBegin blocked by tlocks low = %d\n"
300062306a36Sopenharmony_ci		       "txBegin blocked by no free tid = %d\n"
300162306a36Sopenharmony_ci		       "calls to txBeginAnon = %d\n"
300262306a36Sopenharmony_ci		       "txBeginAnon blocked by sync barrier = %d\n"
300362306a36Sopenharmony_ci		       "txBeginAnon blocked by tlocks low = %d\n"
300462306a36Sopenharmony_ci		       "calls to txLockAlloc = %d\n"
300562306a36Sopenharmony_ci		       "tLockAlloc blocked by no free lock = %d\n",
300662306a36Sopenharmony_ci		       TxStat.txBegin,
300762306a36Sopenharmony_ci		       TxStat.txBegin_barrier,
300862306a36Sopenharmony_ci		       TxStat.txBegin_lockslow,
300962306a36Sopenharmony_ci		       TxStat.txBegin_freetid,
301062306a36Sopenharmony_ci		       TxStat.txBeginAnon,
301162306a36Sopenharmony_ci		       TxStat.txBeginAnon_barrier,
301262306a36Sopenharmony_ci		       TxStat.txBeginAnon_lockslow,
301362306a36Sopenharmony_ci		       TxStat.txLockAlloc,
301462306a36Sopenharmony_ci		       TxStat.txLockAlloc_freelock);
301562306a36Sopenharmony_ci	return 0;
301662306a36Sopenharmony_ci}
301762306a36Sopenharmony_ci#endif
3018