162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
462306a36Sopenharmony_ci *   Portions Copyright (C) Christoph Hellwig, 2001-2002
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci *	jfs_logmgr.c: log manager
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * for related information, see transaction manager (jfs_txnmgr.c), and
1162306a36Sopenharmony_ci * recovery manager (jfs_logredo.c).
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * note: for detail, RTFS.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *	log buffer manager:
1662306a36Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements.
1762306a36Sopenharmony_ci * per log serial pageout of logpage
1862306a36Sopenharmony_ci * queuing i/o requests and redrive i/o at iodone
1962306a36Sopenharmony_ci * maintain current logpage buffer
2062306a36Sopenharmony_ci * no caching since append only
2162306a36Sopenharmony_ci * appropriate jfs buffer cache buffers as needed
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *	group commit:
2462306a36Sopenharmony_ci * transactions which wrote COMMIT records in the same in-memory
2562306a36Sopenharmony_ci * log page during the pageout of previous/current log page(s) are
2662306a36Sopenharmony_ci * committed together by the pageout of the page.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *	TBD lazy commit:
2962306a36Sopenharmony_ci * transactions are committed asynchronously when the log page
3062306a36Sopenharmony_ci * containing it COMMIT is paged out when it becomes full;
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *	serialization:
3362306a36Sopenharmony_ci * . a per log lock serialize log write.
3462306a36Sopenharmony_ci * . a per log lock serialize group commit.
3562306a36Sopenharmony_ci * . a per log lock serialize log open/close;
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci *	TBD log integrity:
3862306a36Sopenharmony_ci * careful-write (ping-pong) of last logpage to recover from crash
3962306a36Sopenharmony_ci * in overwrite.
4062306a36Sopenharmony_ci * detection of split (out-of-order) write of physical sectors
4162306a36Sopenharmony_ci * of last logpage via timestamp at end of each sector
4262306a36Sopenharmony_ci * with its mirror data array at trailer).
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *	alternatives:
4562306a36Sopenharmony_ci * lsn - 64-bit monotonically increasing integer vs
4662306a36Sopenharmony_ci * 32-bit lspn and page eor.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <linux/fs.h>
5062306a36Sopenharmony_ci#include <linux/blkdev.h>
5162306a36Sopenharmony_ci#include <linux/interrupt.h>
5262306a36Sopenharmony_ci#include <linux/completion.h>
5362306a36Sopenharmony_ci#include <linux/kthread.h>
5462306a36Sopenharmony_ci#include <linux/buffer_head.h>		/* for sync_blockdev() */
5562306a36Sopenharmony_ci#include <linux/bio.h>
5662306a36Sopenharmony_ci#include <linux/freezer.h>
5762306a36Sopenharmony_ci#include <linux/export.h>
5862306a36Sopenharmony_ci#include <linux/delay.h>
5962306a36Sopenharmony_ci#include <linux/mutex.h>
6062306a36Sopenharmony_ci#include <linux/seq_file.h>
6162306a36Sopenharmony_ci#include <linux/slab.h>
6262306a36Sopenharmony_ci#include "jfs_incore.h"
6362306a36Sopenharmony_ci#include "jfs_filsys.h"
6462306a36Sopenharmony_ci#include "jfs_metapage.h"
6562306a36Sopenharmony_ci#include "jfs_superblock.h"
6662306a36Sopenharmony_ci#include "jfs_txnmgr.h"
6762306a36Sopenharmony_ci#include "jfs_debug.h"
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * lbuf's ready to be redriven.  Protected by log_redrive_lock (jfsIO thread)
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic struct lbuf *log_redrive_list;
7462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(log_redrive_lock);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci *	log read/write serialization (per log)
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci#define LOG_LOCK_INIT(log)	mutex_init(&(log)->loglock)
8162306a36Sopenharmony_ci#define LOG_LOCK(log)		mutex_lock(&((log)->loglock))
8262306a36Sopenharmony_ci#define LOG_UNLOCK(log)		mutex_unlock(&((log)->loglock))
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci *	log group commit serialization (per log)
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define LOGGC_LOCK_INIT(log)	spin_lock_init(&(log)->gclock)
9062306a36Sopenharmony_ci#define LOGGC_LOCK(log)		spin_lock_irq(&(log)->gclock)
9162306a36Sopenharmony_ci#define LOGGC_UNLOCK(log)	spin_unlock_irq(&(log)->gclock)
9262306a36Sopenharmony_ci#define LOGGC_WAKEUP(tblk)	wake_up_all(&(tblk)->gcwait)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci *	log sync serialization (per log)
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_ci#define	LOGSYNC_DELTA(logsize)		min((logsize)/8, 128*LOGPSIZE)
9862306a36Sopenharmony_ci#define	LOGSYNC_BARRIER(logsize)	((logsize)/4)
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci#define	LOGSYNC_DELTA(logsize)		min((logsize)/4, 256*LOGPSIZE)
10162306a36Sopenharmony_ci#define	LOGSYNC_BARRIER(logsize)	((logsize)/2)
10262306a36Sopenharmony_ci*/
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci *	log buffer cache synchronization
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(jfsLCacheLock);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define	LCACHE_LOCK(flags)	spin_lock_irqsave(&jfsLCacheLock, flags)
11162306a36Sopenharmony_ci#define	LCACHE_UNLOCK(flags)	spin_unlock_irqrestore(&jfsLCacheLock, flags)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/*
11462306a36Sopenharmony_ci * See __SLEEP_COND in jfs_locks.h
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ci#define LCACHE_SLEEP_COND(wq, cond, flags)	\
11762306a36Sopenharmony_cido {						\
11862306a36Sopenharmony_ci	if (cond)				\
11962306a36Sopenharmony_ci		break;				\
12062306a36Sopenharmony_ci	__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
12162306a36Sopenharmony_ci} while (0)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define	LCACHE_WAKEUP(event)	wake_up(event)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci *	lbuf buffer cache (lCache) control
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci/* log buffer manager pageout control (cumulative, inclusive) */
13062306a36Sopenharmony_ci#define	lbmREAD		0x0001
13162306a36Sopenharmony_ci#define	lbmWRITE	0x0002	/* enqueue at tail of write queue;
13262306a36Sopenharmony_ci				 * init pageout if at head of queue;
13362306a36Sopenharmony_ci				 */
13462306a36Sopenharmony_ci#define	lbmRELEASE	0x0004	/* remove from write queue
13562306a36Sopenharmony_ci				 * at completion of pageout;
13662306a36Sopenharmony_ci				 * do not free/recycle it yet:
13762306a36Sopenharmony_ci				 * caller will free it;
13862306a36Sopenharmony_ci				 */
13962306a36Sopenharmony_ci#define	lbmSYNC		0x0008	/* do not return to freelist
14062306a36Sopenharmony_ci				 * when removed from write queue;
14162306a36Sopenharmony_ci				 */
14262306a36Sopenharmony_ci#define lbmFREE		0x0010	/* return to freelist
14362306a36Sopenharmony_ci				 * at completion of pageout;
14462306a36Sopenharmony_ci				 * the buffer may be recycled;
14562306a36Sopenharmony_ci				 */
14662306a36Sopenharmony_ci#define	lbmDONE		0x0020
14762306a36Sopenharmony_ci#define	lbmERROR	0x0040
14862306a36Sopenharmony_ci#define lbmGC		0x0080	/* lbmIODone to perform post-GC processing
14962306a36Sopenharmony_ci				 * of log page
15062306a36Sopenharmony_ci				 */
15162306a36Sopenharmony_ci#define lbmDIRECT	0x0100
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/*
15462306a36Sopenharmony_ci * Global list of active external journals
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistatic LIST_HEAD(jfs_external_logs);
15762306a36Sopenharmony_cistatic struct jfs_log *dummy_log;
15862306a36Sopenharmony_cistatic DEFINE_MUTEX(jfs_log_mutex);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/*
16162306a36Sopenharmony_ci * forward references
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cistatic int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
16462306a36Sopenharmony_ci			 struct lrd * lrd, struct tlock * tlck);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int lmNextPage(struct jfs_log * log);
16762306a36Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
16862306a36Sopenharmony_ci			   int activate);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int open_inline_log(struct super_block *sb);
17162306a36Sopenharmony_cistatic int open_dummy_log(struct super_block *sb);
17262306a36Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log);
17362306a36Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log);
17462306a36Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int);
17562306a36Sopenharmony_cistatic void lbmFree(struct lbuf * bp);
17662306a36Sopenharmony_cistatic void lbmfree(struct lbuf * bp);
17762306a36Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
17862306a36Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block);
17962306a36Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
18062306a36Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag);
18162306a36Sopenharmony_cistatic bio_end_io_t lbmIODone;
18262306a36Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp);
18362306a36Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_block);
18462306a36Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/*
18962306a36Sopenharmony_ci *	statistics
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS
19262306a36Sopenharmony_cistatic struct lmStat {
19362306a36Sopenharmony_ci	uint commit;		/* # of commit */
19462306a36Sopenharmony_ci	uint pagedone;		/* # of page written */
19562306a36Sopenharmony_ci	uint submitted;		/* # of pages submitted */
19662306a36Sopenharmony_ci	uint full_page;		/* # of full pages submitted */
19762306a36Sopenharmony_ci	uint partial_page;	/* # of partial pages submitted */
19862306a36Sopenharmony_ci} lmStat;
19962306a36Sopenharmony_ci#endif
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void write_special_inodes(struct jfs_log *log,
20262306a36Sopenharmony_ci				 int (*writer)(struct address_space *))
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct jfs_sb_info *sbi;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	list_for_each_entry(sbi, &log->sb_list, log_list) {
20762306a36Sopenharmony_ci		writer(sbi->ipbmap->i_mapping);
20862306a36Sopenharmony_ci		writer(sbi->ipimap->i_mapping);
20962306a36Sopenharmony_ci		writer(sbi->direct_inode->i_mapping);
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * NAME:	lmLog()
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * FUNCTION:	write a log record;
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * PARAMETER:
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * RETURN:	lsn - offset to the next log record to write (end-of-log);
22162306a36Sopenharmony_ci *		-1  - error;
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * note: todo: log error handler
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_ciint lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
22662306a36Sopenharmony_ci	  struct tlock * tlck)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	int lsn;
22962306a36Sopenharmony_ci	int diffp, difft;
23062306a36Sopenharmony_ci	struct metapage *mp = NULL;
23162306a36Sopenharmony_ci	unsigned long flags;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
23462306a36Sopenharmony_ci		 log, tblk, lrd, tlck);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	LOG_LOCK(log);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* log by (out-of-transaction) JFS ? */
23962306a36Sopenharmony_ci	if (tblk == NULL)
24062306a36Sopenharmony_ci		goto writeRecord;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* log from page ? */
24362306a36Sopenharmony_ci	if (tlck == NULL ||
24462306a36Sopenharmony_ci	    tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
24562306a36Sopenharmony_ci		goto writeRecord;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/*
24862306a36Sopenharmony_ci	 *	initialize/update page/transaction recovery lsn
24962306a36Sopenharmony_ci	 */
25062306a36Sopenharmony_ci	lsn = log->lsn;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	LOGSYNC_LOCK(log, flags);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/*
25562306a36Sopenharmony_ci	 * initialize page lsn if first log write of the page
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	if (mp->lsn == 0) {
25862306a36Sopenharmony_ci		mp->log = log;
25962306a36Sopenharmony_ci		mp->lsn = lsn;
26062306a36Sopenharmony_ci		log->count++;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		/* insert page at tail of logsynclist */
26362306a36Sopenharmony_ci		list_add_tail(&mp->synclist, &log->synclist);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/*
26762306a36Sopenharmony_ci	 *	initialize/update lsn of tblock of the page
26862306a36Sopenharmony_ci	 *
26962306a36Sopenharmony_ci	 * transaction inherits oldest lsn of pages associated
27062306a36Sopenharmony_ci	 * with allocation/deallocation of resources (their
27162306a36Sopenharmony_ci	 * log records are used to reconstruct allocation map
27262306a36Sopenharmony_ci	 * at recovery time: inode for inode allocation map,
27362306a36Sopenharmony_ci	 * B+-tree index of extent descriptors for block
27462306a36Sopenharmony_ci	 * allocation map);
27562306a36Sopenharmony_ci	 * allocation map pages inherit transaction lsn at
27662306a36Sopenharmony_ci	 * commit time to allow forwarding log syncpt past log
27762306a36Sopenharmony_ci	 * records associated with allocation/deallocation of
27862306a36Sopenharmony_ci	 * resources only after persistent map of these map pages
27962306a36Sopenharmony_ci	 * have been updated and propagated to home.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci	/*
28262306a36Sopenharmony_ci	 * initialize transaction lsn:
28362306a36Sopenharmony_ci	 */
28462306a36Sopenharmony_ci	if (tblk->lsn == 0) {
28562306a36Sopenharmony_ci		/* inherit lsn of its first page logged */
28662306a36Sopenharmony_ci		tblk->lsn = mp->lsn;
28762306a36Sopenharmony_ci		log->count++;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		/* insert tblock after the page on logsynclist */
29062306a36Sopenharmony_ci		list_add(&tblk->synclist, &mp->synclist);
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * update transaction lsn:
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	else {
29662306a36Sopenharmony_ci		/* inherit oldest/smallest lsn of page */
29762306a36Sopenharmony_ci		logdiff(diffp, mp->lsn, log);
29862306a36Sopenharmony_ci		logdiff(difft, tblk->lsn, log);
29962306a36Sopenharmony_ci		if (diffp < difft) {
30062306a36Sopenharmony_ci			/* update tblock lsn with page lsn */
30162306a36Sopenharmony_ci			tblk->lsn = mp->lsn;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci			/* move tblock after page on logsynclist */
30462306a36Sopenharmony_ci			list_move(&tblk->synclist, &mp->synclist);
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	LOGSYNC_UNLOCK(log, flags);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 *	write the log record
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci      writeRecord:
31462306a36Sopenharmony_ci	lsn = lmWriteRecord(log, tblk, lrd, tlck);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/*
31762306a36Sopenharmony_ci	 * forward log syncpt if log reached next syncpt trigger
31862306a36Sopenharmony_ci	 */
31962306a36Sopenharmony_ci	logdiff(diffp, lsn, log);
32062306a36Sopenharmony_ci	if (diffp >= log->nextsync)
32162306a36Sopenharmony_ci		lsn = lmLogSync(log, 0);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* update end-of-log lsn */
32462306a36Sopenharmony_ci	log->lsn = lsn;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	LOG_UNLOCK(log);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* return end-of-log address */
32962306a36Sopenharmony_ci	return lsn;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/*
33362306a36Sopenharmony_ci * NAME:	lmWriteRecord()
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * FUNCTION:	move the log record to current log page
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * PARAMETER:	cd	- commit descriptor
33862306a36Sopenharmony_ci *
33962306a36Sopenharmony_ci * RETURN:	end-of-log address
34062306a36Sopenharmony_ci *
34162306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_cistatic int
34462306a36Sopenharmony_cilmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
34562306a36Sopenharmony_ci	      struct tlock * tlck)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int lsn = 0;		/* end-of-log address */
34862306a36Sopenharmony_ci	struct lbuf *bp;	/* dst log page buffer */
34962306a36Sopenharmony_ci	struct logpage *lp;	/* dst log page */
35062306a36Sopenharmony_ci	caddr_t dst;		/* destination address in log page */
35162306a36Sopenharmony_ci	int dstoffset;		/* end-of-log offset in log page */
35262306a36Sopenharmony_ci	int freespace;		/* free space in log page */
35362306a36Sopenharmony_ci	caddr_t p;		/* src meta-data page */
35462306a36Sopenharmony_ci	caddr_t src;
35562306a36Sopenharmony_ci	int srclen;
35662306a36Sopenharmony_ci	int nbytes;		/* number of bytes to move */
35762306a36Sopenharmony_ci	int i;
35862306a36Sopenharmony_ci	int len;
35962306a36Sopenharmony_ci	struct linelock *linelock;
36062306a36Sopenharmony_ci	struct lv *lv;
36162306a36Sopenharmony_ci	struct lvd *lvd;
36262306a36Sopenharmony_ci	int l2linesize;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	len = 0;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* retrieve destination log page to write */
36762306a36Sopenharmony_ci	bp = (struct lbuf *) log->bp;
36862306a36Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
36962306a36Sopenharmony_ci	dstoffset = log->eor;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* any log data to write ? */
37262306a36Sopenharmony_ci	if (tlck == NULL)
37362306a36Sopenharmony_ci		goto moveLrd;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 *	move log record data
37762306a36Sopenharmony_ci	 */
37862306a36Sopenharmony_ci	/* retrieve source meta-data page to log */
37962306a36Sopenharmony_ci	if (tlck->flag & tlckPAGELOCK) {
38062306a36Sopenharmony_ci		p = (caddr_t) (tlck->mp->data);
38162306a36Sopenharmony_ci		linelock = (struct linelock *) & tlck->lock;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci	/* retrieve source in-memory inode to log */
38462306a36Sopenharmony_ci	else if (tlck->flag & tlckINODELOCK) {
38562306a36Sopenharmony_ci		if (tlck->type & tlckDTREE)
38662306a36Sopenharmony_ci			p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
38762306a36Sopenharmony_ci		else
38862306a36Sopenharmony_ci			p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
38962306a36Sopenharmony_ci		linelock = (struct linelock *) & tlck->lock;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	else {
39262306a36Sopenharmony_ci		jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck);
39362306a36Sopenharmony_ci		return 0;	/* Probably should trap */
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci	l2linesize = linelock->l2linesize;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci      moveData:
39862306a36Sopenharmony_ci	ASSERT(linelock->index <= linelock->maxcnt);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	lv = linelock->lv;
40162306a36Sopenharmony_ci	for (i = 0; i < linelock->index; i++, lv++) {
40262306a36Sopenharmony_ci		if (lv->length == 0)
40362306a36Sopenharmony_ci			continue;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		/* is page full ? */
40662306a36Sopenharmony_ci		if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
40762306a36Sopenharmony_ci			/* page become full: move on to next page */
40862306a36Sopenharmony_ci			lmNextPage(log);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci			bp = log->bp;
41162306a36Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
41262306a36Sopenharmony_ci			dstoffset = LOGPHDRSIZE;
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		/*
41662306a36Sopenharmony_ci		 * move log vector data
41762306a36Sopenharmony_ci		 */
41862306a36Sopenharmony_ci		src = (u8 *) p + (lv->offset << l2linesize);
41962306a36Sopenharmony_ci		srclen = lv->length << l2linesize;
42062306a36Sopenharmony_ci		len += srclen;
42162306a36Sopenharmony_ci		while (srclen > 0) {
42262306a36Sopenharmony_ci			freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
42362306a36Sopenharmony_ci			nbytes = min(freespace, srclen);
42462306a36Sopenharmony_ci			dst = (caddr_t) lp + dstoffset;
42562306a36Sopenharmony_ci			memcpy(dst, src, nbytes);
42662306a36Sopenharmony_ci			dstoffset += nbytes;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci			/* is page not full ? */
42962306a36Sopenharmony_ci			if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
43062306a36Sopenharmony_ci				break;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci			/* page become full: move on to next page */
43362306a36Sopenharmony_ci			lmNextPage(log);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci			bp = (struct lbuf *) log->bp;
43662306a36Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
43762306a36Sopenharmony_ci			dstoffset = LOGPHDRSIZE;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci			srclen -= nbytes;
44062306a36Sopenharmony_ci			src += nbytes;
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		/*
44462306a36Sopenharmony_ci		 * move log vector descriptor
44562306a36Sopenharmony_ci		 */
44662306a36Sopenharmony_ci		len += 4;
44762306a36Sopenharmony_ci		lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
44862306a36Sopenharmony_ci		lvd->offset = cpu_to_le16(lv->offset);
44962306a36Sopenharmony_ci		lvd->length = cpu_to_le16(lv->length);
45062306a36Sopenharmony_ci		dstoffset += 4;
45162306a36Sopenharmony_ci		jfs_info("lmWriteRecord: lv offset:%d length:%d",
45262306a36Sopenharmony_ci			 lv->offset, lv->length);
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if ((i = linelock->next)) {
45662306a36Sopenharmony_ci		linelock = (struct linelock *) lid_to_tlock(i);
45762306a36Sopenharmony_ci		goto moveData;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/*
46162306a36Sopenharmony_ci	 *	move log record descriptor
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci      moveLrd:
46462306a36Sopenharmony_ci	lrd->length = cpu_to_le16(len);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	src = (caddr_t) lrd;
46762306a36Sopenharmony_ci	srclen = LOGRDSIZE;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	while (srclen > 0) {
47062306a36Sopenharmony_ci		freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
47162306a36Sopenharmony_ci		nbytes = min(freespace, srclen);
47262306a36Sopenharmony_ci		dst = (caddr_t) lp + dstoffset;
47362306a36Sopenharmony_ci		memcpy(dst, src, nbytes);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		dstoffset += nbytes;
47662306a36Sopenharmony_ci		srclen -= nbytes;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		/* are there more to move than freespace of page ? */
47962306a36Sopenharmony_ci		if (srclen)
48062306a36Sopenharmony_ci			goto pageFull;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		/*
48362306a36Sopenharmony_ci		 * end of log record descriptor
48462306a36Sopenharmony_ci		 */
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		/* update last log record eor */
48762306a36Sopenharmony_ci		log->eor = dstoffset;
48862306a36Sopenharmony_ci		bp->l_eor = dstoffset;
48962306a36Sopenharmony_ci		lsn = (log->page << L2LOGPSIZE) + dstoffset;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
49262306a36Sopenharmony_ci			tblk->clsn = lsn;
49362306a36Sopenharmony_ci			jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn,
49462306a36Sopenharmony_ci				 bp->l_eor);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci			INCREMENT(lmStat.commit);	/* # of commit */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci			/*
49962306a36Sopenharmony_ci			 * enqueue tblock for group commit:
50062306a36Sopenharmony_ci			 *
50162306a36Sopenharmony_ci			 * enqueue tblock of non-trivial/synchronous COMMIT
50262306a36Sopenharmony_ci			 * at tail of group commit queue
50362306a36Sopenharmony_ci			 * (trivial/asynchronous COMMITs are ignored by
50462306a36Sopenharmony_ci			 * group commit.)
50562306a36Sopenharmony_ci			 */
50662306a36Sopenharmony_ci			LOGGC_LOCK(log);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci			/* init tblock gc state */
50962306a36Sopenharmony_ci			tblk->flag = tblkGC_QUEUE;
51062306a36Sopenharmony_ci			tblk->bp = log->bp;
51162306a36Sopenharmony_ci			tblk->pn = log->page;
51262306a36Sopenharmony_ci			tblk->eor = log->eor;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci			/* enqueue transaction to commit queue */
51562306a36Sopenharmony_ci			list_add_tail(&tblk->cqueue, &log->cqueue);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci			LOGGC_UNLOCK(log);
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x",
52162306a36Sopenharmony_ci			le16_to_cpu(lrd->type), log->bp, log->page, dstoffset);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		/* page not full ? */
52462306a36Sopenharmony_ci		if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
52562306a36Sopenharmony_ci			return lsn;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	      pageFull:
52862306a36Sopenharmony_ci		/* page become full: move on to next page */
52962306a36Sopenharmony_ci		lmNextPage(log);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		bp = (struct lbuf *) log->bp;
53262306a36Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
53362306a36Sopenharmony_ci		dstoffset = LOGPHDRSIZE;
53462306a36Sopenharmony_ci		src += nbytes;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return lsn;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/*
54262306a36Sopenharmony_ci * NAME:	lmNextPage()
54362306a36Sopenharmony_ci *
54462306a36Sopenharmony_ci * FUNCTION:	write current page and allocate next page.
54562306a36Sopenharmony_ci *
54662306a36Sopenharmony_ci * PARAMETER:	log
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * RETURN:	0
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_cistatic int lmNextPage(struct jfs_log * log)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct logpage *lp;
55562306a36Sopenharmony_ci	int lspn;		/* log sequence page number */
55662306a36Sopenharmony_ci	int pn;			/* current page number */
55762306a36Sopenharmony_ci	struct lbuf *bp;
55862306a36Sopenharmony_ci	struct lbuf *nextbp;
55962306a36Sopenharmony_ci	struct tblock *tblk;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* get current log page number and log sequence page number */
56262306a36Sopenharmony_ci	pn = log->page;
56362306a36Sopenharmony_ci	bp = log->bp;
56462306a36Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
56562306a36Sopenharmony_ci	lspn = le32_to_cpu(lp->h.page);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	LOGGC_LOCK(log);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/*
57062306a36Sopenharmony_ci	 *	write or queue the full page at the tail of write queue
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	/* get the tail tblk on commit queue */
57362306a36Sopenharmony_ci	if (list_empty(&log->cqueue))
57462306a36Sopenharmony_ci		tblk = NULL;
57562306a36Sopenharmony_ci	else
57662306a36Sopenharmony_ci		tblk = list_entry(log->cqueue.prev, struct tblock, cqueue);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* every tblk who has COMMIT record on the current page,
57962306a36Sopenharmony_ci	 * and has not been committed, must be on commit queue
58062306a36Sopenharmony_ci	 * since tblk is queued at commit queueu at the time
58162306a36Sopenharmony_ci	 * of writing its COMMIT record on the page before
58262306a36Sopenharmony_ci	 * page becomes full (even though the tblk thread
58362306a36Sopenharmony_ci	 * who wrote COMMIT record may have been suspended
58462306a36Sopenharmony_ci	 * currently);
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* is page bound with outstanding tail tblk ? */
58862306a36Sopenharmony_ci	if (tblk && tblk->pn == pn) {
58962306a36Sopenharmony_ci		/* mark tblk for end-of-page */
59062306a36Sopenharmony_ci		tblk->flag |= tblkGC_EOP;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		if (log->cflag & logGC_PAGEOUT) {
59362306a36Sopenharmony_ci			/* if page is not already on write queue,
59462306a36Sopenharmony_ci			 * just enqueue (no lbmWRITE to prevent redrive)
59562306a36Sopenharmony_ci			 * buffer to wqueue to ensure correct serial order
59662306a36Sopenharmony_ci			 * of the pages since log pages will be added
59762306a36Sopenharmony_ci			 * continuously
59862306a36Sopenharmony_ci			 */
59962306a36Sopenharmony_ci			if (bp->l_wqnext == NULL)
60062306a36Sopenharmony_ci				lbmWrite(log, bp, 0, 0);
60162306a36Sopenharmony_ci		} else {
60262306a36Sopenharmony_ci			/*
60362306a36Sopenharmony_ci			 * No current GC leader, initiate group commit
60462306a36Sopenharmony_ci			 */
60562306a36Sopenharmony_ci			log->cflag |= logGC_PAGEOUT;
60662306a36Sopenharmony_ci			lmGCwrite(log, 0);
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci	/* page is not bound with outstanding tblk:
61062306a36Sopenharmony_ci	 * init write or mark it to be redriven (lbmWRITE)
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	else {
61362306a36Sopenharmony_ci		/* finalize the page */
61462306a36Sopenharmony_ci		bp->l_ceor = bp->l_eor;
61562306a36Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
61662306a36Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	LOGGC_UNLOCK(log);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/*
62162306a36Sopenharmony_ci	 *	allocate/initialize next page
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	/* if log wraps, the first data page of log is 2
62462306a36Sopenharmony_ci	 * (0 never used, 1 is superblock).
62562306a36Sopenharmony_ci	 */
62662306a36Sopenharmony_ci	log->page = (pn == log->size - 1) ? 2 : pn + 1;
62762306a36Sopenharmony_ci	log->eor = LOGPHDRSIZE;	/* ? valid page empty/full at logRedo() */
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/* allocate/initialize next log page buffer */
63062306a36Sopenharmony_ci	nextbp = lbmAllocate(log, log->page);
63162306a36Sopenharmony_ci	nextbp->l_eor = log->eor;
63262306a36Sopenharmony_ci	log->bp = nextbp;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* initialize next log page */
63562306a36Sopenharmony_ci	lp = (struct logpage *) nextbp->l_ldata;
63662306a36Sopenharmony_ci	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
63762306a36Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return 0;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/*
64462306a36Sopenharmony_ci * NAME:	lmGroupCommit()
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * FUNCTION:	group commit
64762306a36Sopenharmony_ci *	initiate pageout of the pages with COMMIT in the order of
64862306a36Sopenharmony_ci *	page number - redrive pageout of the page at the head of
64962306a36Sopenharmony_ci *	pageout queue until full page has been written.
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci * RETURN:
65262306a36Sopenharmony_ci *
65362306a36Sopenharmony_ci * NOTE:
65462306a36Sopenharmony_ci *	LOGGC_LOCK serializes log group commit queue, and
65562306a36Sopenharmony_ci *	transaction blocks on the commit queue.
65662306a36Sopenharmony_ci *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
65762306a36Sopenharmony_ci */
65862306a36Sopenharmony_ciint lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	int rc = 0;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	LOGGC_LOCK(log);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* group committed already ? */
66562306a36Sopenharmony_ci	if (tblk->flag & tblkGC_COMMITTED) {
66662306a36Sopenharmony_ci		if (tblk->flag & tblkGC_ERROR)
66762306a36Sopenharmony_ci			rc = -EIO;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		LOGGC_UNLOCK(log);
67062306a36Sopenharmony_ci		return rc;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (tblk->xflag & COMMIT_LAZY)
67562306a36Sopenharmony_ci		tblk->flag |= tblkGC_LAZY;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) &&
67862306a36Sopenharmony_ci	    (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag)
67962306a36Sopenharmony_ci	     || jfs_tlocks_low)) {
68062306a36Sopenharmony_ci		/*
68162306a36Sopenharmony_ci		 * No pageout in progress
68262306a36Sopenharmony_ci		 *
68362306a36Sopenharmony_ci		 * start group commit as its group leader.
68462306a36Sopenharmony_ci		 */
68562306a36Sopenharmony_ci		log->cflag |= logGC_PAGEOUT;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		lmGCwrite(log, 0);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (tblk->xflag & COMMIT_LAZY) {
69162306a36Sopenharmony_ci		/*
69262306a36Sopenharmony_ci		 * Lazy transactions can leave now
69362306a36Sopenharmony_ci		 */
69462306a36Sopenharmony_ci		LOGGC_UNLOCK(log);
69562306a36Sopenharmony_ci		return 0;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* lmGCwrite gives up LOGGC_LOCK, check again */
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (tblk->flag & tblkGC_COMMITTED) {
70162306a36Sopenharmony_ci		if (tblk->flag & tblkGC_ERROR)
70262306a36Sopenharmony_ci			rc = -EIO;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		LOGGC_UNLOCK(log);
70562306a36Sopenharmony_ci		return rc;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* upcount transaction waiting for completion
70962306a36Sopenharmony_ci	 */
71062306a36Sopenharmony_ci	log->gcrtc++;
71162306a36Sopenharmony_ci	tblk->flag |= tblkGC_READY;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
71462306a36Sopenharmony_ci		     LOGGC_LOCK(log), LOGGC_UNLOCK(log));
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* removed from commit queue */
71762306a36Sopenharmony_ci	if (tblk->flag & tblkGC_ERROR)
71862306a36Sopenharmony_ci		rc = -EIO;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	LOGGC_UNLOCK(log);
72162306a36Sopenharmony_ci	return rc;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci/*
72562306a36Sopenharmony_ci * NAME:	lmGCwrite()
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci * FUNCTION:	group commit write
72862306a36Sopenharmony_ci *	initiate write of log page, building a group of all transactions
72962306a36Sopenharmony_ci *	with commit records on that page.
73062306a36Sopenharmony_ci *
73162306a36Sopenharmony_ci * RETURN:	None
73262306a36Sopenharmony_ci *
73362306a36Sopenharmony_ci * NOTE:
73462306a36Sopenharmony_ci *	LOGGC_LOCK must be held by caller.
73562306a36Sopenharmony_ci *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
73662306a36Sopenharmony_ci */
73762306a36Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_write)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct lbuf *bp;
74062306a36Sopenharmony_ci	struct logpage *lp;
74162306a36Sopenharmony_ci	int gcpn;		/* group commit page number */
74262306a36Sopenharmony_ci	struct tblock *tblk;
74362306a36Sopenharmony_ci	struct tblock *xtblk = NULL;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/*
74662306a36Sopenharmony_ci	 * build the commit group of a log page
74762306a36Sopenharmony_ci	 *
74862306a36Sopenharmony_ci	 * scan commit queue and make a commit group of all
74962306a36Sopenharmony_ci	 * transactions with COMMIT records on the same log page.
75062306a36Sopenharmony_ci	 */
75162306a36Sopenharmony_ci	/* get the head tblk on the commit queue */
75262306a36Sopenharmony_ci	gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	list_for_each_entry(tblk, &log->cqueue, cqueue) {
75562306a36Sopenharmony_ci		if (tblk->pn != gcpn)
75662306a36Sopenharmony_ci			break;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		xtblk = tblk;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		/* state transition: (QUEUE, READY) -> COMMIT */
76162306a36Sopenharmony_ci		tblk->flag |= tblkGC_COMMIT;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci	tblk = xtblk;		/* last tblk of the page */
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/*
76662306a36Sopenharmony_ci	 * pageout to commit transactions on the log page.
76762306a36Sopenharmony_ci	 */
76862306a36Sopenharmony_ci	bp = (struct lbuf *) tblk->bp;
76962306a36Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
77062306a36Sopenharmony_ci	/* is page already full ? */
77162306a36Sopenharmony_ci	if (tblk->flag & tblkGC_EOP) {
77262306a36Sopenharmony_ci		/* mark page to free at end of group commit of the page */
77362306a36Sopenharmony_ci		tblk->flag &= ~tblkGC_EOP;
77462306a36Sopenharmony_ci		tblk->flag |= tblkGC_FREE;
77562306a36Sopenharmony_ci		bp->l_ceor = bp->l_eor;
77662306a36Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
77762306a36Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
77862306a36Sopenharmony_ci			 cant_write);
77962306a36Sopenharmony_ci		INCREMENT(lmStat.full_page);
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci	/* page is not yet full */
78262306a36Sopenharmony_ci	else {
78362306a36Sopenharmony_ci		bp->l_ceor = tblk->eor;	/* ? bp->l_ceor = bp->l_eor; */
78462306a36Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
78562306a36Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
78662306a36Sopenharmony_ci		INCREMENT(lmStat.partial_page);
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci/*
79162306a36Sopenharmony_ci * NAME:	lmPostGC()
79262306a36Sopenharmony_ci *
79362306a36Sopenharmony_ci * FUNCTION:	group commit post-processing
79462306a36Sopenharmony_ci *	Processes transactions after their commit records have been written
79562306a36Sopenharmony_ci *	to disk, redriving log I/O if necessary.
79662306a36Sopenharmony_ci *
79762306a36Sopenharmony_ci * RETURN:	None
79862306a36Sopenharmony_ci *
79962306a36Sopenharmony_ci * NOTE:
80062306a36Sopenharmony_ci *	This routine is called a interrupt time by lbmIODone
80162306a36Sopenharmony_ci */
80262306a36Sopenharmony_cistatic void lmPostGC(struct lbuf * bp)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	unsigned long flags;
80562306a36Sopenharmony_ci	struct jfs_log *log = bp->l_log;
80662306a36Sopenharmony_ci	struct logpage *lp;
80762306a36Sopenharmony_ci	struct tblock *tblk, *temp;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	//LOGGC_LOCK(log);
81062306a36Sopenharmony_ci	spin_lock_irqsave(&log->gclock, flags);
81162306a36Sopenharmony_ci	/*
81262306a36Sopenharmony_ci	 * current pageout of group commit completed.
81362306a36Sopenharmony_ci	 *
81462306a36Sopenharmony_ci	 * remove/wakeup transactions from commit queue who were
81562306a36Sopenharmony_ci	 * group committed with the current log page
81662306a36Sopenharmony_ci	 */
81762306a36Sopenharmony_ci	list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
81862306a36Sopenharmony_ci		if (!(tblk->flag & tblkGC_COMMIT))
81962306a36Sopenharmony_ci			break;
82062306a36Sopenharmony_ci		/* if transaction was marked GC_COMMIT then
82162306a36Sopenharmony_ci		 * it has been shipped in the current pageout
82262306a36Sopenharmony_ci		 * and made it to disk - it is committed.
82362306a36Sopenharmony_ci		 */
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		if (bp->l_flag & lbmERROR)
82662306a36Sopenharmony_ci			tblk->flag |= tblkGC_ERROR;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		/* remove it from the commit queue */
82962306a36Sopenharmony_ci		list_del(&tblk->cqueue);
83062306a36Sopenharmony_ci		tblk->flag &= ~tblkGC_QUEUE;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		if (tblk == log->flush_tblk) {
83362306a36Sopenharmony_ci			/* we can stop flushing the log now */
83462306a36Sopenharmony_ci			clear_bit(log_FLUSH, &log->flag);
83562306a36Sopenharmony_ci			log->flush_tblk = NULL;
83662306a36Sopenharmony_ci		}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
83962306a36Sopenharmony_ci			 tblk->flag);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		if (!(tblk->xflag & COMMIT_FORCE))
84262306a36Sopenharmony_ci			/*
84362306a36Sopenharmony_ci			 * Hand tblk over to lazy commit thread
84462306a36Sopenharmony_ci			 */
84562306a36Sopenharmony_ci			txLazyUnlock(tblk);
84662306a36Sopenharmony_ci		else {
84762306a36Sopenharmony_ci			/* state transition: COMMIT -> COMMITTED */
84862306a36Sopenharmony_ci			tblk->flag |= tblkGC_COMMITTED;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci			if (tblk->flag & tblkGC_READY)
85162306a36Sopenharmony_ci				log->gcrtc--;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci			LOGGC_WAKEUP(tblk);
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		/* was page full before pageout ?
85762306a36Sopenharmony_ci		 * (and this is the last tblk bound with the page)
85862306a36Sopenharmony_ci		 */
85962306a36Sopenharmony_ci		if (tblk->flag & tblkGC_FREE)
86062306a36Sopenharmony_ci			lbmFree(bp);
86162306a36Sopenharmony_ci		/* did page become full after pageout ?
86262306a36Sopenharmony_ci		 * (and this is the last tblk bound with the page)
86362306a36Sopenharmony_ci		 */
86462306a36Sopenharmony_ci		else if (tblk->flag & tblkGC_EOP) {
86562306a36Sopenharmony_ci			/* finalize the page */
86662306a36Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
86762306a36Sopenharmony_ci			bp->l_ceor = bp->l_eor;
86862306a36Sopenharmony_ci			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
86962306a36Sopenharmony_ci			jfs_info("lmPostGC: calling lbmWrite");
87062306a36Sopenharmony_ci			lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
87162306a36Sopenharmony_ci				 1);
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* are there any transactions who have entered lnGroupCommit()
87762306a36Sopenharmony_ci	 * (whose COMMITs are after that of the last log page written.
87862306a36Sopenharmony_ci	 * They are waiting for new group commit (above at (SLEEP 1))
87962306a36Sopenharmony_ci	 * or lazy transactions are on a full (queued) log page,
88062306a36Sopenharmony_ci	 * select the latest ready transaction as new group leader and
88162306a36Sopenharmony_ci	 * wake her up to lead her group.
88262306a36Sopenharmony_ci	 */
88362306a36Sopenharmony_ci	if ((!list_empty(&log->cqueue)) &&
88462306a36Sopenharmony_ci	    ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
88562306a36Sopenharmony_ci	     test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
88662306a36Sopenharmony_ci		/*
88762306a36Sopenharmony_ci		 * Call lmGCwrite with new group leader
88862306a36Sopenharmony_ci		 */
88962306a36Sopenharmony_ci		lmGCwrite(log, 1);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	/* no transaction are ready yet (transactions are only just
89262306a36Sopenharmony_ci	 * queued (GC_QUEUE) and not entered for group commit yet).
89362306a36Sopenharmony_ci	 * the first transaction entering group commit
89462306a36Sopenharmony_ci	 * will elect herself as new group leader.
89562306a36Sopenharmony_ci	 */
89662306a36Sopenharmony_ci	else
89762306a36Sopenharmony_ci		log->cflag &= ~logGC_PAGEOUT;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	//LOGGC_UNLOCK(log);
90062306a36Sopenharmony_ci	spin_unlock_irqrestore(&log->gclock, flags);
90162306a36Sopenharmony_ci	return;
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/*
90562306a36Sopenharmony_ci * NAME:	lmLogSync()
90662306a36Sopenharmony_ci *
90762306a36Sopenharmony_ci * FUNCTION:	write log SYNCPT record for specified log
90862306a36Sopenharmony_ci *	if new sync address is available
90962306a36Sopenharmony_ci *	(normally the case if sync() is executed by back-ground
91062306a36Sopenharmony_ci *	process).
91162306a36Sopenharmony_ci *	calculate new value of i_nextsync which determines when
91262306a36Sopenharmony_ci *	this code is called again.
91362306a36Sopenharmony_ci *
91462306a36Sopenharmony_ci * PARAMETERS:	log	- log structure
91562306a36Sopenharmony_ci *		hard_sync - 1 to force all metadata to be written
91662306a36Sopenharmony_ci *
91762306a36Sopenharmony_ci * RETURN:	0
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
92062306a36Sopenharmony_ci */
92162306a36Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	int logsize;
92462306a36Sopenharmony_ci	int written;		/* written since last syncpt */
92562306a36Sopenharmony_ci	int free;		/* free space left available */
92662306a36Sopenharmony_ci	int delta;		/* additional delta to write normally */
92762306a36Sopenharmony_ci	int more;		/* additional write granted */
92862306a36Sopenharmony_ci	struct lrd lrd;
92962306a36Sopenharmony_ci	int lsn;
93062306a36Sopenharmony_ci	struct logsyncblk *lp;
93162306a36Sopenharmony_ci	unsigned long flags;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* push dirty metapages out to disk */
93462306a36Sopenharmony_ci	if (hard_sync)
93562306a36Sopenharmony_ci		write_special_inodes(log, filemap_fdatawrite);
93662306a36Sopenharmony_ci	else
93762306a36Sopenharmony_ci		write_special_inodes(log, filemap_flush);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/*
94062306a36Sopenharmony_ci	 *	forward syncpt
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	/* if last sync is same as last syncpt,
94362306a36Sopenharmony_ci	 * invoke sync point forward processing to update sync.
94462306a36Sopenharmony_ci	 */
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (log->sync == log->syncpt) {
94762306a36Sopenharmony_ci		LOGSYNC_LOCK(log, flags);
94862306a36Sopenharmony_ci		if (list_empty(&log->synclist))
94962306a36Sopenharmony_ci			log->sync = log->lsn;
95062306a36Sopenharmony_ci		else {
95162306a36Sopenharmony_ci			lp = list_entry(log->synclist.next,
95262306a36Sopenharmony_ci					struct logsyncblk, synclist);
95362306a36Sopenharmony_ci			log->sync = lp->lsn;
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci		LOGSYNC_UNLOCK(log, flags);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* if sync is different from last syncpt,
96062306a36Sopenharmony_ci	 * write a SYNCPT record with syncpt = sync.
96162306a36Sopenharmony_ci	 * reset syncpt = sync
96262306a36Sopenharmony_ci	 */
96362306a36Sopenharmony_ci	if (log->sync != log->syncpt) {
96462306a36Sopenharmony_ci		lrd.logtid = 0;
96562306a36Sopenharmony_ci		lrd.backchain = 0;
96662306a36Sopenharmony_ci		lrd.type = cpu_to_le16(LOG_SYNCPT);
96762306a36Sopenharmony_ci		lrd.length = 0;
96862306a36Sopenharmony_ci		lrd.log.syncpt.sync = cpu_to_le32(log->sync);
96962306a36Sopenharmony_ci		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		log->syncpt = log->sync;
97262306a36Sopenharmony_ci	} else
97362306a36Sopenharmony_ci		lsn = log->lsn;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/*
97662306a36Sopenharmony_ci	 *	setup next syncpt trigger (SWAG)
97762306a36Sopenharmony_ci	 */
97862306a36Sopenharmony_ci	logsize = log->logsize;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	logdiff(written, lsn, log);
98162306a36Sopenharmony_ci	free = logsize - written;
98262306a36Sopenharmony_ci	delta = LOGSYNC_DELTA(logsize);
98362306a36Sopenharmony_ci	more = min(free / 2, delta);
98462306a36Sopenharmony_ci	if (more < 2 * LOGPSIZE) {
98562306a36Sopenharmony_ci		jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
98662306a36Sopenharmony_ci		/*
98762306a36Sopenharmony_ci		 *	log wrapping
98862306a36Sopenharmony_ci		 *
98962306a36Sopenharmony_ci		 * option 1 - panic ? No.!
99062306a36Sopenharmony_ci		 * option 2 - shutdown file systems
99162306a36Sopenharmony_ci		 *	      associated with log ?
99262306a36Sopenharmony_ci		 * option 3 - extend log ?
99362306a36Sopenharmony_ci		 * option 4 - second chance
99462306a36Sopenharmony_ci		 *
99562306a36Sopenharmony_ci		 * mark log wrapped, and continue.
99662306a36Sopenharmony_ci		 * when all active transactions are completed,
99762306a36Sopenharmony_ci		 * mark log valid for recovery.
99862306a36Sopenharmony_ci		 * if crashed during invalid state, log state
99962306a36Sopenharmony_ci		 * implies invalid log, forcing fsck().
100062306a36Sopenharmony_ci		 */
100162306a36Sopenharmony_ci		/* mark log state log wrap in log superblock */
100262306a36Sopenharmony_ci		/* log->state = LOGWRAP; */
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		/* reset sync point computation */
100562306a36Sopenharmony_ci		log->syncpt = log->sync = lsn;
100662306a36Sopenharmony_ci		log->nextsync = delta;
100762306a36Sopenharmony_ci	} else
100862306a36Sopenharmony_ci		/* next syncpt trigger = written + more */
100962306a36Sopenharmony_ci		log->nextsync = written + more;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* if number of bytes written from last sync point is more
101262306a36Sopenharmony_ci	 * than 1/4 of the log size, stop new transactions from
101362306a36Sopenharmony_ci	 * starting until all current transactions are completed
101462306a36Sopenharmony_ci	 * by setting syncbarrier flag.
101562306a36Sopenharmony_ci	 */
101662306a36Sopenharmony_ci	if (!test_bit(log_SYNCBARRIER, &log->flag) &&
101762306a36Sopenharmony_ci	    (written > LOGSYNC_BARRIER(logsize)) && log->active) {
101862306a36Sopenharmony_ci		set_bit(log_SYNCBARRIER, &log->flag);
101962306a36Sopenharmony_ci		jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn,
102062306a36Sopenharmony_ci			 log->syncpt);
102162306a36Sopenharmony_ci		/*
102262306a36Sopenharmony_ci		 * We may have to initiate group commit
102362306a36Sopenharmony_ci		 */
102462306a36Sopenharmony_ci		jfs_flush_journal(log, 0);
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return lsn;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci/*
103162306a36Sopenharmony_ci * NAME:	jfs_syncpt
103262306a36Sopenharmony_ci *
103362306a36Sopenharmony_ci * FUNCTION:	write log SYNCPT record for specified log
103462306a36Sopenharmony_ci *
103562306a36Sopenharmony_ci * PARAMETERS:	log	  - log structure
103662306a36Sopenharmony_ci *		hard_sync - set to 1 to force metadata to be written
103762306a36Sopenharmony_ci */
103862306a36Sopenharmony_civoid jfs_syncpt(struct jfs_log *log, int hard_sync)
103962306a36Sopenharmony_ci{	LOG_LOCK(log);
104062306a36Sopenharmony_ci	if (!test_bit(log_QUIESCE, &log->flag))
104162306a36Sopenharmony_ci		lmLogSync(log, hard_sync);
104262306a36Sopenharmony_ci	LOG_UNLOCK(log);
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci/*
104662306a36Sopenharmony_ci * NAME:	lmLogOpen()
104762306a36Sopenharmony_ci *
104862306a36Sopenharmony_ci * FUNCTION:	open the log on first open;
104962306a36Sopenharmony_ci *	insert filesystem in the active list of the log.
105062306a36Sopenharmony_ci *
105162306a36Sopenharmony_ci * PARAMETER:	ipmnt	- file system mount inode
105262306a36Sopenharmony_ci *		iplog	- log inode (out)
105362306a36Sopenharmony_ci *
105462306a36Sopenharmony_ci * RETURN:
105562306a36Sopenharmony_ci *
105662306a36Sopenharmony_ci * serialization:
105762306a36Sopenharmony_ci */
105862306a36Sopenharmony_ciint lmLogOpen(struct super_block *sb)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	int rc;
106162306a36Sopenharmony_ci	struct block_device *bdev;
106262306a36Sopenharmony_ci	struct jfs_log *log;
106362306a36Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (sbi->flag & JFS_NOINTEGRITY)
106662306a36Sopenharmony_ci		return open_dummy_log(sb);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (sbi->mntflag & JFS_INLINELOG)
106962306a36Sopenharmony_ci		return open_inline_log(sb);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
107262306a36Sopenharmony_ci	list_for_each_entry(log, &jfs_external_logs, journal_list) {
107362306a36Sopenharmony_ci		if (log->bdev->bd_dev == sbi->logdev) {
107462306a36Sopenharmony_ci			if (!uuid_equal(&log->uuid, &sbi->loguuid)) {
107562306a36Sopenharmony_ci				jfs_warn("wrong uuid on JFS journal");
107662306a36Sopenharmony_ci				mutex_unlock(&jfs_log_mutex);
107762306a36Sopenharmony_ci				return -EINVAL;
107862306a36Sopenharmony_ci			}
107962306a36Sopenharmony_ci			/*
108062306a36Sopenharmony_ci			 * add file system to log active file system list
108162306a36Sopenharmony_ci			 */
108262306a36Sopenharmony_ci			if ((rc = lmLogFileSystem(log, sbi, 1))) {
108362306a36Sopenharmony_ci				mutex_unlock(&jfs_log_mutex);
108462306a36Sopenharmony_ci				return rc;
108562306a36Sopenharmony_ci			}
108662306a36Sopenharmony_ci			goto journal_found;
108762306a36Sopenharmony_ci		}
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
109162306a36Sopenharmony_ci		mutex_unlock(&jfs_log_mutex);
109262306a36Sopenharmony_ci		return -ENOMEM;
109362306a36Sopenharmony_ci	}
109462306a36Sopenharmony_ci	INIT_LIST_HEAD(&log->sb_list);
109562306a36Sopenharmony_ci	init_waitqueue_head(&log->syncwait);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/*
109862306a36Sopenharmony_ci	 *	external log as separate logical volume
109962306a36Sopenharmony_ci	 *
110062306a36Sopenharmony_ci	 * file systems to log may have n-to-1 relationship;
110162306a36Sopenharmony_ci	 */
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	bdev = blkdev_get_by_dev(sbi->logdev, BLK_OPEN_READ | BLK_OPEN_WRITE,
110462306a36Sopenharmony_ci				 log, NULL);
110562306a36Sopenharmony_ci	if (IS_ERR(bdev)) {
110662306a36Sopenharmony_ci		rc = PTR_ERR(bdev);
110762306a36Sopenharmony_ci		goto free;
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	log->bdev = bdev;
111162306a36Sopenharmony_ci	uuid_copy(&log->uuid, &sbi->loguuid);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	/*
111462306a36Sopenharmony_ci	 * initialize log:
111562306a36Sopenharmony_ci	 */
111662306a36Sopenharmony_ci	if ((rc = lmLogInit(log)))
111762306a36Sopenharmony_ci		goto close;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	list_add(&log->journal_list, &jfs_external_logs);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/*
112262306a36Sopenharmony_ci	 * add file system to log active file system list
112362306a36Sopenharmony_ci	 */
112462306a36Sopenharmony_ci	if ((rc = lmLogFileSystem(log, sbi, 1)))
112562306a36Sopenharmony_ci		goto shutdown;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_cijournal_found:
112862306a36Sopenharmony_ci	LOG_LOCK(log);
112962306a36Sopenharmony_ci	list_add(&sbi->log_list, &log->sb_list);
113062306a36Sopenharmony_ci	sbi->log = log;
113162306a36Sopenharmony_ci	LOG_UNLOCK(log);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
113462306a36Sopenharmony_ci	return 0;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	/*
113762306a36Sopenharmony_ci	 *	unwind on error
113862306a36Sopenharmony_ci	 */
113962306a36Sopenharmony_ci      shutdown:		/* unwind lbmLogInit() */
114062306a36Sopenharmony_ci	list_del(&log->journal_list);
114162306a36Sopenharmony_ci	lbmLogShutdown(log);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci      close:		/* close external log device */
114462306a36Sopenharmony_ci	blkdev_put(bdev, log);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci      free:		/* free log descriptor */
114762306a36Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
114862306a36Sopenharmony_ci	kfree(log);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	jfs_warn("lmLogOpen: exit(%d)", rc);
115162306a36Sopenharmony_ci	return rc;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic int open_inline_log(struct super_block *sb)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	struct jfs_log *log;
115762306a36Sopenharmony_ci	int rc;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL)))
116062306a36Sopenharmony_ci		return -ENOMEM;
116162306a36Sopenharmony_ci	INIT_LIST_HEAD(&log->sb_list);
116262306a36Sopenharmony_ci	init_waitqueue_head(&log->syncwait);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	set_bit(log_INLINELOG, &log->flag);
116562306a36Sopenharmony_ci	log->bdev = sb->s_bdev;
116662306a36Sopenharmony_ci	log->base = addressPXD(&JFS_SBI(sb)->logpxd);
116762306a36Sopenharmony_ci	log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
116862306a36Sopenharmony_ci	    (L2LOGPSIZE - sb->s_blocksize_bits);
116962306a36Sopenharmony_ci	log->l2bsize = sb->s_blocksize_bits;
117062306a36Sopenharmony_ci	ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	/*
117362306a36Sopenharmony_ci	 * initialize log.
117462306a36Sopenharmony_ci	 */
117562306a36Sopenharmony_ci	if ((rc = lmLogInit(log))) {
117662306a36Sopenharmony_ci		kfree(log);
117762306a36Sopenharmony_ci		jfs_warn("lmLogOpen: exit(%d)", rc);
117862306a36Sopenharmony_ci		return rc;
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	list_add(&JFS_SBI(sb)->log_list, &log->sb_list);
118262306a36Sopenharmony_ci	JFS_SBI(sb)->log = log;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return rc;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int open_dummy_log(struct super_block *sb)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	int rc;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
119262306a36Sopenharmony_ci	if (!dummy_log) {
119362306a36Sopenharmony_ci		dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL);
119462306a36Sopenharmony_ci		if (!dummy_log) {
119562306a36Sopenharmony_ci			mutex_unlock(&jfs_log_mutex);
119662306a36Sopenharmony_ci			return -ENOMEM;
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci		INIT_LIST_HEAD(&dummy_log->sb_list);
119962306a36Sopenharmony_ci		init_waitqueue_head(&dummy_log->syncwait);
120062306a36Sopenharmony_ci		dummy_log->no_integrity = 1;
120162306a36Sopenharmony_ci		/* Make up some stuff */
120262306a36Sopenharmony_ci		dummy_log->base = 0;
120362306a36Sopenharmony_ci		dummy_log->size = 1024;
120462306a36Sopenharmony_ci		rc = lmLogInit(dummy_log);
120562306a36Sopenharmony_ci		if (rc) {
120662306a36Sopenharmony_ci			kfree(dummy_log);
120762306a36Sopenharmony_ci			dummy_log = NULL;
120862306a36Sopenharmony_ci			mutex_unlock(&jfs_log_mutex);
120962306a36Sopenharmony_ci			return rc;
121062306a36Sopenharmony_ci		}
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	LOG_LOCK(dummy_log);
121462306a36Sopenharmony_ci	list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
121562306a36Sopenharmony_ci	JFS_SBI(sb)->log = dummy_log;
121662306a36Sopenharmony_ci	LOG_UNLOCK(dummy_log);
121762306a36Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci/*
122362306a36Sopenharmony_ci * NAME:	lmLogInit()
122462306a36Sopenharmony_ci *
122562306a36Sopenharmony_ci * FUNCTION:	log initialization at first log open.
122662306a36Sopenharmony_ci *
122762306a36Sopenharmony_ci *	logredo() (or logformat()) should have been run previously.
122862306a36Sopenharmony_ci *	initialize the log from log superblock.
122962306a36Sopenharmony_ci *	set the log state in the superblock to LOGMOUNT and
123062306a36Sopenharmony_ci *	write SYNCPT log record.
123162306a36Sopenharmony_ci *
123262306a36Sopenharmony_ci * PARAMETER:	log	- log structure
123362306a36Sopenharmony_ci *
123462306a36Sopenharmony_ci * RETURN:	0	- if ok
123562306a36Sopenharmony_ci *		-EINVAL	- bad log magic number or superblock dirty
123662306a36Sopenharmony_ci *		error returned from logwait()
123762306a36Sopenharmony_ci *
123862306a36Sopenharmony_ci * serialization: single first open thread
123962306a36Sopenharmony_ci */
124062306a36Sopenharmony_ciint lmLogInit(struct jfs_log * log)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	int rc = 0;
124362306a36Sopenharmony_ci	struct lrd lrd;
124462306a36Sopenharmony_ci	struct logsuper *logsuper;
124562306a36Sopenharmony_ci	struct lbuf *bpsuper;
124662306a36Sopenharmony_ci	struct lbuf *bp;
124762306a36Sopenharmony_ci	struct logpage *lp;
124862306a36Sopenharmony_ci	int lsn = 0;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	jfs_info("lmLogInit: log:0x%p", log);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* initialize the group commit serialization lock */
125362306a36Sopenharmony_ci	LOGGC_LOCK_INIT(log);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* allocate/initialize the log write serialization lock */
125662306a36Sopenharmony_ci	LOG_LOCK_INIT(log);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	LOGSYNC_LOCK_INIT(log);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	INIT_LIST_HEAD(&log->synclist);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	INIT_LIST_HEAD(&log->cqueue);
126362306a36Sopenharmony_ci	log->flush_tblk = NULL;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	log->count = 0;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	/*
126862306a36Sopenharmony_ci	 * initialize log i/o
126962306a36Sopenharmony_ci	 */
127062306a36Sopenharmony_ci	if ((rc = lbmLogInit(log)))
127162306a36Sopenharmony_ci		return rc;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (!test_bit(log_INLINELOG, &log->flag))
127462306a36Sopenharmony_ci		log->l2bsize = L2LOGPSIZE;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* check for disabled journaling to disk */
127762306a36Sopenharmony_ci	if (log->no_integrity) {
127862306a36Sopenharmony_ci		/*
127962306a36Sopenharmony_ci		 * Journal pages will still be filled.  When the time comes
128062306a36Sopenharmony_ci		 * to actually do the I/O, the write is not done, and the
128162306a36Sopenharmony_ci		 * endio routine is called directly.
128262306a36Sopenharmony_ci		 */
128362306a36Sopenharmony_ci		bp = lbmAllocate(log , 0);
128462306a36Sopenharmony_ci		log->bp = bp;
128562306a36Sopenharmony_ci		bp->l_pn = bp->l_eor = 0;
128662306a36Sopenharmony_ci	} else {
128762306a36Sopenharmony_ci		/*
128862306a36Sopenharmony_ci		 * validate log superblock
128962306a36Sopenharmony_ci		 */
129062306a36Sopenharmony_ci		if ((rc = lbmRead(log, 1, &bpsuper)))
129162306a36Sopenharmony_ci			goto errout10;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci		logsuper = (struct logsuper *) bpsuper->l_ldata;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
129662306a36Sopenharmony_ci			jfs_warn("*** Log Format Error ! ***");
129762306a36Sopenharmony_ci			rc = -EINVAL;
129862306a36Sopenharmony_ci			goto errout20;
129962306a36Sopenharmony_ci		}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		/* logredo() should have been run successfully. */
130262306a36Sopenharmony_ci		if (logsuper->state != cpu_to_le32(LOGREDONE)) {
130362306a36Sopenharmony_ci			jfs_warn("*** Log Is Dirty ! ***");
130462306a36Sopenharmony_ci			rc = -EINVAL;
130562306a36Sopenharmony_ci			goto errout20;
130662306a36Sopenharmony_ci		}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci		/* initialize log from log superblock */
130962306a36Sopenharmony_ci		if (test_bit(log_INLINELOG,&log->flag)) {
131062306a36Sopenharmony_ci			if (log->size != le32_to_cpu(logsuper->size)) {
131162306a36Sopenharmony_ci				rc = -EINVAL;
131262306a36Sopenharmony_ci				goto errout20;
131362306a36Sopenharmony_ci			}
131462306a36Sopenharmony_ci			jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x",
131562306a36Sopenharmony_ci				 log, (unsigned long long)log->base, log->size);
131662306a36Sopenharmony_ci		} else {
131762306a36Sopenharmony_ci			if (!uuid_equal(&logsuper->uuid, &log->uuid)) {
131862306a36Sopenharmony_ci				jfs_warn("wrong uuid on JFS log device");
131962306a36Sopenharmony_ci				rc = -EINVAL;
132062306a36Sopenharmony_ci				goto errout20;
132162306a36Sopenharmony_ci			}
132262306a36Sopenharmony_ci			log->size = le32_to_cpu(logsuper->size);
132362306a36Sopenharmony_ci			log->l2bsize = le32_to_cpu(logsuper->l2bsize);
132462306a36Sopenharmony_ci			jfs_info("lmLogInit: external log:0x%p base:0x%Lx size:0x%x",
132562306a36Sopenharmony_ci				 log, (unsigned long long)log->base, log->size);
132662306a36Sopenharmony_ci		}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci		log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
132962306a36Sopenharmony_ci		log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		/*
133262306a36Sopenharmony_ci		 * initialize for log append write mode
133362306a36Sopenharmony_ci		 */
133462306a36Sopenharmony_ci		/* establish current/end-of-log page/buffer */
133562306a36Sopenharmony_ci		if ((rc = lbmRead(log, log->page, &bp)))
133662306a36Sopenharmony_ci			goto errout20;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		jfs_info("lmLogInit: lsn:0x%x page:%d eor:%d:%d",
134162306a36Sopenharmony_ci			 le32_to_cpu(logsuper->end), log->page, log->eor,
134262306a36Sopenharmony_ci			 le16_to_cpu(lp->h.eor));
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci		log->bp = bp;
134562306a36Sopenharmony_ci		bp->l_pn = log->page;
134662306a36Sopenharmony_ci		bp->l_eor = log->eor;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		/* if current page is full, move on to next page */
134962306a36Sopenharmony_ci		if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
135062306a36Sopenharmony_ci			lmNextPage(log);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci		/*
135362306a36Sopenharmony_ci		 * initialize log syncpoint
135462306a36Sopenharmony_ci		 */
135562306a36Sopenharmony_ci		/*
135662306a36Sopenharmony_ci		 * write the first SYNCPT record with syncpoint = 0
135762306a36Sopenharmony_ci		 * (i.e., log redo up to HERE !);
135862306a36Sopenharmony_ci		 * remove current page from lbm write queue at end of pageout
135962306a36Sopenharmony_ci		 * (to write log superblock update), but do not release to
136062306a36Sopenharmony_ci		 * freelist;
136162306a36Sopenharmony_ci		 */
136262306a36Sopenharmony_ci		lrd.logtid = 0;
136362306a36Sopenharmony_ci		lrd.backchain = 0;
136462306a36Sopenharmony_ci		lrd.type = cpu_to_le16(LOG_SYNCPT);
136562306a36Sopenharmony_ci		lrd.length = 0;
136662306a36Sopenharmony_ci		lrd.log.syncpt.sync = 0;
136762306a36Sopenharmony_ci		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
136862306a36Sopenharmony_ci		bp = log->bp;
136962306a36Sopenharmony_ci		bp->l_ceor = bp->l_eor;
137062306a36Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
137162306a36Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
137262306a36Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0);
137362306a36Sopenharmony_ci		if ((rc = lbmIOWait(bp, 0)))
137462306a36Sopenharmony_ci			goto errout30;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci		/*
137762306a36Sopenharmony_ci		 * update/write superblock
137862306a36Sopenharmony_ci		 */
137962306a36Sopenharmony_ci		logsuper->state = cpu_to_le32(LOGMOUNT);
138062306a36Sopenharmony_ci		log->serial = le32_to_cpu(logsuper->serial) + 1;
138162306a36Sopenharmony_ci		logsuper->serial = cpu_to_le32(log->serial);
138262306a36Sopenharmony_ci		lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
138362306a36Sopenharmony_ci		if ((rc = lbmIOWait(bpsuper, lbmFREE)))
138462306a36Sopenharmony_ci			goto errout30;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	/* initialize logsync parameters */
138862306a36Sopenharmony_ci	log->logsize = (log->size - 2) << L2LOGPSIZE;
138962306a36Sopenharmony_ci	log->lsn = lsn;
139062306a36Sopenharmony_ci	log->syncpt = lsn;
139162306a36Sopenharmony_ci	log->sync = log->syncpt;
139262306a36Sopenharmony_ci	log->nextsync = LOGSYNC_DELTA(log->logsize);
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	jfs_info("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x",
139562306a36Sopenharmony_ci		 log->lsn, log->syncpt, log->sync);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	/*
139862306a36Sopenharmony_ci	 * initialize for lazy/group commit
139962306a36Sopenharmony_ci	 */
140062306a36Sopenharmony_ci	log->clsn = lsn;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return 0;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/*
140562306a36Sopenharmony_ci	 *	unwind on error
140662306a36Sopenharmony_ci	 */
140762306a36Sopenharmony_ci      errout30:		/* release log page */
140862306a36Sopenharmony_ci	log->wqueue = NULL;
140962306a36Sopenharmony_ci	bp->l_wqnext = NULL;
141062306a36Sopenharmony_ci	lbmFree(bp);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci      errout20:		/* release log superblock */
141362306a36Sopenharmony_ci	lbmFree(bpsuper);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci      errout10:		/* unwind lbmLogInit() */
141662306a36Sopenharmony_ci	lbmLogShutdown(log);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	jfs_warn("lmLogInit: exit(%d)", rc);
141962306a36Sopenharmony_ci	return rc;
142062306a36Sopenharmony_ci}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci/*
142462306a36Sopenharmony_ci * NAME:	lmLogClose()
142562306a36Sopenharmony_ci *
142662306a36Sopenharmony_ci * FUNCTION:	remove file system <ipmnt> from active list of log <iplog>
142762306a36Sopenharmony_ci *		and close it on last close.
142862306a36Sopenharmony_ci *
142962306a36Sopenharmony_ci * PARAMETER:	sb	- superblock
143062306a36Sopenharmony_ci *
143162306a36Sopenharmony_ci * RETURN:	errors from subroutines
143262306a36Sopenharmony_ci *
143362306a36Sopenharmony_ci * serialization:
143462306a36Sopenharmony_ci */
143562306a36Sopenharmony_ciint lmLogClose(struct super_block *sb)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
143862306a36Sopenharmony_ci	struct jfs_log *log = sbi->log;
143962306a36Sopenharmony_ci	struct block_device *bdev;
144062306a36Sopenharmony_ci	int rc = 0;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	jfs_info("lmLogClose: log:0x%p", log);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
144562306a36Sopenharmony_ci	LOG_LOCK(log);
144662306a36Sopenharmony_ci	list_del(&sbi->log_list);
144762306a36Sopenharmony_ci	LOG_UNLOCK(log);
144862306a36Sopenharmony_ci	sbi->log = NULL;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/*
145162306a36Sopenharmony_ci	 * We need to make sure all of the "written" metapages
145262306a36Sopenharmony_ci	 * actually make it to disk
145362306a36Sopenharmony_ci	 */
145462306a36Sopenharmony_ci	sync_blockdev(sb->s_bdev);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	if (test_bit(log_INLINELOG, &log->flag)) {
145762306a36Sopenharmony_ci		/*
145862306a36Sopenharmony_ci		 *	in-line log in host file system
145962306a36Sopenharmony_ci		 */
146062306a36Sopenharmony_ci		rc = lmLogShutdown(log);
146162306a36Sopenharmony_ci		kfree(log);
146262306a36Sopenharmony_ci		goto out;
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	if (!log->no_integrity)
146662306a36Sopenharmony_ci		lmLogFileSystem(log, sbi, 0);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (!list_empty(&log->sb_list))
146962306a36Sopenharmony_ci		goto out;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	/*
147262306a36Sopenharmony_ci	 * TODO: ensure that the dummy_log is in a state to allow
147362306a36Sopenharmony_ci	 * lbmLogShutdown to deallocate all the buffers and call
147462306a36Sopenharmony_ci	 * kfree against dummy_log.  For now, leave dummy_log & its
147562306a36Sopenharmony_ci	 * buffers in memory, and resuse if another no-integrity mount
147662306a36Sopenharmony_ci	 * is requested.
147762306a36Sopenharmony_ci	 */
147862306a36Sopenharmony_ci	if (log->no_integrity)
147962306a36Sopenharmony_ci		goto out;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/*
148262306a36Sopenharmony_ci	 *	external log as separate logical volume
148362306a36Sopenharmony_ci	 */
148462306a36Sopenharmony_ci	list_del(&log->journal_list);
148562306a36Sopenharmony_ci	bdev = log->bdev;
148662306a36Sopenharmony_ci	rc = lmLogShutdown(log);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	blkdev_put(bdev, log);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	kfree(log);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci      out:
149362306a36Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
149462306a36Sopenharmony_ci	jfs_info("lmLogClose: exit(%d)", rc);
149562306a36Sopenharmony_ci	return rc;
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci/*
150062306a36Sopenharmony_ci * NAME:	jfs_flush_journal()
150162306a36Sopenharmony_ci *
150262306a36Sopenharmony_ci * FUNCTION:	initiate write of any outstanding transactions to the journal
150362306a36Sopenharmony_ci *		and optionally wait until they are all written to disk
150462306a36Sopenharmony_ci *
150562306a36Sopenharmony_ci *		wait == 0  flush until latest txn is committed, don't wait
150662306a36Sopenharmony_ci *		wait == 1  flush until latest txn is committed, wait
150762306a36Sopenharmony_ci *		wait > 1   flush until all txn's are complete, wait
150862306a36Sopenharmony_ci */
150962306a36Sopenharmony_civoid jfs_flush_journal(struct jfs_log *log, int wait)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	int i;
151262306a36Sopenharmony_ci	struct tblock *target = NULL;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* jfs_write_inode may call us during read-only mount */
151562306a36Sopenharmony_ci	if (!log)
151662306a36Sopenharmony_ci		return;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	LOGGC_LOCK(log);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (!list_empty(&log->cqueue)) {
152362306a36Sopenharmony_ci		/*
152462306a36Sopenharmony_ci		 * This ensures that we will keep writing to the journal as long
152562306a36Sopenharmony_ci		 * as there are unwritten commit records
152662306a36Sopenharmony_ci		 */
152762306a36Sopenharmony_ci		target = list_entry(log->cqueue.prev, struct tblock, cqueue);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci		if (test_bit(log_FLUSH, &log->flag)) {
153062306a36Sopenharmony_ci			/*
153162306a36Sopenharmony_ci			 * We're already flushing.
153262306a36Sopenharmony_ci			 * if flush_tblk is NULL, we are flushing everything,
153362306a36Sopenharmony_ci			 * so leave it that way.  Otherwise, update it to the
153462306a36Sopenharmony_ci			 * latest transaction
153562306a36Sopenharmony_ci			 */
153662306a36Sopenharmony_ci			if (log->flush_tblk)
153762306a36Sopenharmony_ci				log->flush_tblk = target;
153862306a36Sopenharmony_ci		} else {
153962306a36Sopenharmony_ci			/* Only flush until latest transaction is committed */
154062306a36Sopenharmony_ci			log->flush_tblk = target;
154162306a36Sopenharmony_ci			set_bit(log_FLUSH, &log->flag);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci			/*
154462306a36Sopenharmony_ci			 * Initiate I/O on outstanding transactions
154562306a36Sopenharmony_ci			 */
154662306a36Sopenharmony_ci			if (!(log->cflag & logGC_PAGEOUT)) {
154762306a36Sopenharmony_ci				log->cflag |= logGC_PAGEOUT;
154862306a36Sopenharmony_ci				lmGCwrite(log, 0);
154962306a36Sopenharmony_ci			}
155062306a36Sopenharmony_ci		}
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci	if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
155362306a36Sopenharmony_ci		/* Flush until all activity complete */
155462306a36Sopenharmony_ci		set_bit(log_FLUSH, &log->flag);
155562306a36Sopenharmony_ci		log->flush_tblk = NULL;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
155962306a36Sopenharmony_ci		DECLARE_WAITQUEUE(__wait, current);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		add_wait_queue(&target->gcwait, &__wait);
156262306a36Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
156362306a36Sopenharmony_ci		LOGGC_UNLOCK(log);
156462306a36Sopenharmony_ci		schedule();
156562306a36Sopenharmony_ci		LOGGC_LOCK(log);
156662306a36Sopenharmony_ci		remove_wait_queue(&target->gcwait, &__wait);
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci	LOGGC_UNLOCK(log);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	if (wait < 2)
157162306a36Sopenharmony_ci		return;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	write_special_inodes(log, filemap_fdatawrite);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	/*
157662306a36Sopenharmony_ci	 * If there was recent activity, we may need to wait
157762306a36Sopenharmony_ci	 * for the lazycommit thread to catch up
157862306a36Sopenharmony_ci	 */
157962306a36Sopenharmony_ci	if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
158062306a36Sopenharmony_ci		for (i = 0; i < 200; i++) {	/* Too much? */
158162306a36Sopenharmony_ci			msleep(250);
158262306a36Sopenharmony_ci			write_special_inodes(log, filemap_fdatawrite);
158362306a36Sopenharmony_ci			if (list_empty(&log->cqueue) &&
158462306a36Sopenharmony_ci			    list_empty(&log->synclist))
158562306a36Sopenharmony_ci				break;
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci	assert(list_empty(&log->cqueue));
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci#ifdef CONFIG_JFS_DEBUG
159162306a36Sopenharmony_ci	if (!list_empty(&log->synclist)) {
159262306a36Sopenharmony_ci		struct logsyncblk *lp;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
159562306a36Sopenharmony_ci		list_for_each_entry(lp, &log->synclist, synclist) {
159662306a36Sopenharmony_ci			if (lp->xflag & COMMIT_PAGE) {
159762306a36Sopenharmony_ci				struct metapage *mp = (struct metapage *)lp;
159862306a36Sopenharmony_ci				print_hex_dump(KERN_ERR, "metapage: ",
159962306a36Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16, 4,
160062306a36Sopenharmony_ci					       mp, sizeof(struct metapage), 0);
160162306a36Sopenharmony_ci				print_hex_dump(KERN_ERR, "page: ",
160262306a36Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16,
160362306a36Sopenharmony_ci					       sizeof(long), mp->page,
160462306a36Sopenharmony_ci					       sizeof(struct page), 0);
160562306a36Sopenharmony_ci			} else
160662306a36Sopenharmony_ci				print_hex_dump(KERN_ERR, "tblock:",
160762306a36Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16, 4,
160862306a36Sopenharmony_ci					       lp, sizeof(struct tblock), 0);
160962306a36Sopenharmony_ci		}
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci#else
161262306a36Sopenharmony_ci	WARN_ON(!list_empty(&log->synclist));
161362306a36Sopenharmony_ci#endif
161462306a36Sopenharmony_ci	clear_bit(log_FLUSH, &log->flag);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/*
161862306a36Sopenharmony_ci * NAME:	lmLogShutdown()
161962306a36Sopenharmony_ci *
162062306a36Sopenharmony_ci * FUNCTION:	log shutdown at last LogClose().
162162306a36Sopenharmony_ci *
162262306a36Sopenharmony_ci *		write log syncpt record.
162362306a36Sopenharmony_ci *		update super block to set redone flag to 0.
162462306a36Sopenharmony_ci *
162562306a36Sopenharmony_ci * PARAMETER:	log	- log inode
162662306a36Sopenharmony_ci *
162762306a36Sopenharmony_ci * RETURN:	0	- success
162862306a36Sopenharmony_ci *
162962306a36Sopenharmony_ci * serialization: single last close thread
163062306a36Sopenharmony_ci */
163162306a36Sopenharmony_ciint lmLogShutdown(struct jfs_log * log)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	int rc;
163462306a36Sopenharmony_ci	struct lrd lrd;
163562306a36Sopenharmony_ci	int lsn;
163662306a36Sopenharmony_ci	struct logsuper *logsuper;
163762306a36Sopenharmony_ci	struct lbuf *bpsuper;
163862306a36Sopenharmony_ci	struct lbuf *bp;
163962306a36Sopenharmony_ci	struct logpage *lp;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	jfs_info("lmLogShutdown: log:0x%p", log);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	jfs_flush_journal(log, 2);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	/*
164662306a36Sopenharmony_ci	 * write the last SYNCPT record with syncpoint = 0
164762306a36Sopenharmony_ci	 * (i.e., log redo up to HERE !)
164862306a36Sopenharmony_ci	 */
164962306a36Sopenharmony_ci	lrd.logtid = 0;
165062306a36Sopenharmony_ci	lrd.backchain = 0;
165162306a36Sopenharmony_ci	lrd.type = cpu_to_le16(LOG_SYNCPT);
165262306a36Sopenharmony_ci	lrd.length = 0;
165362306a36Sopenharmony_ci	lrd.log.syncpt.sync = 0;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
165662306a36Sopenharmony_ci	bp = log->bp;
165762306a36Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
165862306a36Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
165962306a36Sopenharmony_ci	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
166062306a36Sopenharmony_ci	lbmIOWait(log->bp, lbmFREE);
166162306a36Sopenharmony_ci	log->bp = NULL;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/*
166462306a36Sopenharmony_ci	 * synchronous update log superblock
166562306a36Sopenharmony_ci	 * mark log state as shutdown cleanly
166662306a36Sopenharmony_ci	 * (i.e., Log does not need to be replayed).
166762306a36Sopenharmony_ci	 */
166862306a36Sopenharmony_ci	if ((rc = lbmRead(log, 1, &bpsuper)))
166962306a36Sopenharmony_ci		goto out;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	logsuper = (struct logsuper *) bpsuper->l_ldata;
167262306a36Sopenharmony_ci	logsuper->state = cpu_to_le32(LOGREDONE);
167362306a36Sopenharmony_ci	logsuper->end = cpu_to_le32(lsn);
167462306a36Sopenharmony_ci	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
167562306a36Sopenharmony_ci	rc = lbmIOWait(bpsuper, lbmFREE);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
167862306a36Sopenharmony_ci		 lsn, log->page, log->eor);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci      out:
168162306a36Sopenharmony_ci	/*
168262306a36Sopenharmony_ci	 * shutdown per log i/o
168362306a36Sopenharmony_ci	 */
168462306a36Sopenharmony_ci	lbmLogShutdown(log);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	if (rc) {
168762306a36Sopenharmony_ci		jfs_warn("lmLogShutdown: exit(%d)", rc);
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci	return rc;
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci/*
169462306a36Sopenharmony_ci * NAME:	lmLogFileSystem()
169562306a36Sopenharmony_ci *
169662306a36Sopenharmony_ci * FUNCTION:	insert (<activate> = true)/remove (<activate> = false)
169762306a36Sopenharmony_ci *	file system into/from log active file system list.
169862306a36Sopenharmony_ci *
169962306a36Sopenharmony_ci * PARAMETE:	log	- pointer to logs inode.
170062306a36Sopenharmony_ci *		fsdev	- kdev_t of filesystem.
170162306a36Sopenharmony_ci *		serial	- pointer to returned log serial number
170262306a36Sopenharmony_ci *		activate - insert/remove device from active list.
170362306a36Sopenharmony_ci *
170462306a36Sopenharmony_ci * RETURN:	0	- success
170562306a36Sopenharmony_ci *		errors returned by vms_iowait().
170662306a36Sopenharmony_ci */
170762306a36Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
170862306a36Sopenharmony_ci			   int activate)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	int rc = 0;
171162306a36Sopenharmony_ci	int i;
171262306a36Sopenharmony_ci	struct logsuper *logsuper;
171362306a36Sopenharmony_ci	struct lbuf *bpsuper;
171462306a36Sopenharmony_ci	uuid_t *uuid = &sbi->uuid;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	/*
171762306a36Sopenharmony_ci	 * insert/remove file system device to log active file system list.
171862306a36Sopenharmony_ci	 */
171962306a36Sopenharmony_ci	if ((rc = lbmRead(log, 1, &bpsuper)))
172062306a36Sopenharmony_ci		return rc;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	logsuper = (struct logsuper *) bpsuper->l_ldata;
172362306a36Sopenharmony_ci	if (activate) {
172462306a36Sopenharmony_ci		for (i = 0; i < MAX_ACTIVE; i++)
172562306a36Sopenharmony_ci			if (uuid_is_null(&logsuper->active[i].uuid)) {
172662306a36Sopenharmony_ci				uuid_copy(&logsuper->active[i].uuid, uuid);
172762306a36Sopenharmony_ci				sbi->aggregate = i;
172862306a36Sopenharmony_ci				break;
172962306a36Sopenharmony_ci			}
173062306a36Sopenharmony_ci		if (i == MAX_ACTIVE) {
173162306a36Sopenharmony_ci			jfs_warn("Too many file systems sharing journal!");
173262306a36Sopenharmony_ci			lbmFree(bpsuper);
173362306a36Sopenharmony_ci			return -EMFILE;	/* Is there a better rc? */
173462306a36Sopenharmony_ci		}
173562306a36Sopenharmony_ci	} else {
173662306a36Sopenharmony_ci		for (i = 0; i < MAX_ACTIVE; i++)
173762306a36Sopenharmony_ci			if (uuid_equal(&logsuper->active[i].uuid, uuid)) {
173862306a36Sopenharmony_ci				uuid_copy(&logsuper->active[i].uuid,
173962306a36Sopenharmony_ci					  &uuid_null);
174062306a36Sopenharmony_ci				break;
174162306a36Sopenharmony_ci			}
174262306a36Sopenharmony_ci		if (i == MAX_ACTIVE) {
174362306a36Sopenharmony_ci			jfs_warn("Somebody stomped on the journal!");
174462306a36Sopenharmony_ci			lbmFree(bpsuper);
174562306a36Sopenharmony_ci			return -EIO;
174662306a36Sopenharmony_ci		}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	/*
175162306a36Sopenharmony_ci	 * synchronous write log superblock:
175262306a36Sopenharmony_ci	 *
175362306a36Sopenharmony_ci	 * write sidestream bypassing write queue:
175462306a36Sopenharmony_ci	 * at file system mount, log super block is updated for
175562306a36Sopenharmony_ci	 * activation of the file system before any log record
175662306a36Sopenharmony_ci	 * (MOUNT record) of the file system, and at file system
175762306a36Sopenharmony_ci	 * unmount, all meta data for the file system has been
175862306a36Sopenharmony_ci	 * flushed before log super block is updated for deactivation
175962306a36Sopenharmony_ci	 * of the file system.
176062306a36Sopenharmony_ci	 */
176162306a36Sopenharmony_ci	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
176262306a36Sopenharmony_ci	rc = lbmIOWait(bpsuper, lbmFREE);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	return rc;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci/*
176862306a36Sopenharmony_ci *		log buffer manager (lbm)
176962306a36Sopenharmony_ci *		------------------------
177062306a36Sopenharmony_ci *
177162306a36Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements.
177262306a36Sopenharmony_ci *
177362306a36Sopenharmony_ci * per log write queue:
177462306a36Sopenharmony_ci * log pageout occurs in serial order by fifo write queue and
177562306a36Sopenharmony_ci * restricting to a single i/o in pregress at any one time.
177662306a36Sopenharmony_ci * a circular singly-linked list
177762306a36Sopenharmony_ci * (log->wrqueue points to the tail, and buffers are linked via
177862306a36Sopenharmony_ci * bp->wrqueue field), and
177962306a36Sopenharmony_ci * maintains log page in pageout ot waiting for pageout in serial pageout.
178062306a36Sopenharmony_ci */
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci/*
178362306a36Sopenharmony_ci *	lbmLogInit()
178462306a36Sopenharmony_ci *
178562306a36Sopenharmony_ci * initialize per log I/O setup at lmLogInit()
178662306a36Sopenharmony_ci */
178762306a36Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log)
178862306a36Sopenharmony_ci{				/* log inode */
178962306a36Sopenharmony_ci	int i;
179062306a36Sopenharmony_ci	struct lbuf *lbuf;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	jfs_info("lbmLogInit: log:0x%p", log);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	/* initialize current buffer cursor */
179562306a36Sopenharmony_ci	log->bp = NULL;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* initialize log device write queue */
179862306a36Sopenharmony_ci	log->wqueue = NULL;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	/*
180162306a36Sopenharmony_ci	 * Each log has its own buffer pages allocated to it.  These are
180262306a36Sopenharmony_ci	 * not managed by the page cache.  This ensures that a transaction
180362306a36Sopenharmony_ci	 * writing to the log does not block trying to allocate a page from
180462306a36Sopenharmony_ci	 * the page cache (for the log).  This would be bad, since page
180562306a36Sopenharmony_ci	 * allocation waits on the kswapd thread that may be committing inodes
180662306a36Sopenharmony_ci	 * which would cause log activity.  Was that clear?  I'm trying to
180762306a36Sopenharmony_ci	 * avoid deadlock here.
180862306a36Sopenharmony_ci	 */
180962306a36Sopenharmony_ci	init_waitqueue_head(&log->free_wait);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	log->lbuf_free = NULL;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	for (i = 0; i < LOGPAGES;) {
181462306a36Sopenharmony_ci		char *buffer;
181562306a36Sopenharmony_ci		uint offset;
181662306a36Sopenharmony_ci		struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		if (!page)
181962306a36Sopenharmony_ci			goto error;
182062306a36Sopenharmony_ci		buffer = page_address(page);
182162306a36Sopenharmony_ci		for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
182262306a36Sopenharmony_ci			lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
182362306a36Sopenharmony_ci			if (lbuf == NULL) {
182462306a36Sopenharmony_ci				if (offset == 0)
182562306a36Sopenharmony_ci					__free_page(page);
182662306a36Sopenharmony_ci				goto error;
182762306a36Sopenharmony_ci			}
182862306a36Sopenharmony_ci			if (offset) /* we already have one reference */
182962306a36Sopenharmony_ci				get_page(page);
183062306a36Sopenharmony_ci			lbuf->l_offset = offset;
183162306a36Sopenharmony_ci			lbuf->l_ldata = buffer + offset;
183262306a36Sopenharmony_ci			lbuf->l_page = page;
183362306a36Sopenharmony_ci			lbuf->l_log = log;
183462306a36Sopenharmony_ci			init_waitqueue_head(&lbuf->l_ioevent);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci			lbuf->l_freelist = log->lbuf_free;
183762306a36Sopenharmony_ci			log->lbuf_free = lbuf;
183862306a36Sopenharmony_ci			i++;
183962306a36Sopenharmony_ci		}
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	return (0);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci      error:
184562306a36Sopenharmony_ci	lbmLogShutdown(log);
184662306a36Sopenharmony_ci	return -ENOMEM;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci/*
185162306a36Sopenharmony_ci *	lbmLogShutdown()
185262306a36Sopenharmony_ci *
185362306a36Sopenharmony_ci * finalize per log I/O setup at lmLogShutdown()
185462306a36Sopenharmony_ci */
185562306a36Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log)
185662306a36Sopenharmony_ci{
185762306a36Sopenharmony_ci	struct lbuf *lbuf;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	jfs_info("lbmLogShutdown: log:0x%p", log);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	lbuf = log->lbuf_free;
186262306a36Sopenharmony_ci	while (lbuf) {
186362306a36Sopenharmony_ci		struct lbuf *next = lbuf->l_freelist;
186462306a36Sopenharmony_ci		__free_page(lbuf->l_page);
186562306a36Sopenharmony_ci		kfree(lbuf);
186662306a36Sopenharmony_ci		lbuf = next;
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci/*
187262306a36Sopenharmony_ci *	lbmAllocate()
187362306a36Sopenharmony_ci *
187462306a36Sopenharmony_ci * allocate an empty log buffer
187562306a36Sopenharmony_ci */
187662306a36Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int pn)
187762306a36Sopenharmony_ci{
187862306a36Sopenharmony_ci	struct lbuf *bp;
187962306a36Sopenharmony_ci	unsigned long flags;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	/*
188262306a36Sopenharmony_ci	 * recycle from log buffer freelist if any
188362306a36Sopenharmony_ci	 */
188462306a36Sopenharmony_ci	LCACHE_LOCK(flags);
188562306a36Sopenharmony_ci	LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags);
188662306a36Sopenharmony_ci	log->lbuf_free = bp->l_freelist;
188762306a36Sopenharmony_ci	LCACHE_UNLOCK(flags);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	bp->l_flag = 0;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	bp->l_wqnext = NULL;
189262306a36Sopenharmony_ci	bp->l_freelist = NULL;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	bp->l_pn = pn;
189562306a36Sopenharmony_ci	bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize));
189662306a36Sopenharmony_ci	bp->l_ceor = 0;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	return bp;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci/*
190362306a36Sopenharmony_ci *	lbmFree()
190462306a36Sopenharmony_ci *
190562306a36Sopenharmony_ci * release a log buffer to freelist
190662306a36Sopenharmony_ci */
190762306a36Sopenharmony_cistatic void lbmFree(struct lbuf * bp)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	unsigned long flags;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	LCACHE_LOCK(flags);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	lbmfree(bp);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	LCACHE_UNLOCK(flags);
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_cistatic void lbmfree(struct lbuf * bp)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct jfs_log *log = bp->l_log;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	assert(bp->l_wqnext == NULL);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	/*
192562306a36Sopenharmony_ci	 * return the buffer to head of freelist
192662306a36Sopenharmony_ci	 */
192762306a36Sopenharmony_ci	bp->l_freelist = log->lbuf_free;
192862306a36Sopenharmony_ci	log->lbuf_free = bp;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	wake_up(&log->free_wait);
193162306a36Sopenharmony_ci	return;
193262306a36Sopenharmony_ci}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci/*
193662306a36Sopenharmony_ci * NAME:	lbmRedrive
193762306a36Sopenharmony_ci *
193862306a36Sopenharmony_ci * FUNCTION:	add a log buffer to the log redrive list
193962306a36Sopenharmony_ci *
194062306a36Sopenharmony_ci * PARAMETER:
194162306a36Sopenharmony_ci *	bp	- log buffer
194262306a36Sopenharmony_ci *
194362306a36Sopenharmony_ci * NOTES:
194462306a36Sopenharmony_ci *	Takes log_redrive_lock.
194562306a36Sopenharmony_ci */
194662306a36Sopenharmony_cistatic inline void lbmRedrive(struct lbuf *bp)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	unsigned long flags;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	spin_lock_irqsave(&log_redrive_lock, flags);
195162306a36Sopenharmony_ci	bp->l_redrive_next = log_redrive_list;
195262306a36Sopenharmony_ci	log_redrive_list = bp;
195362306a36Sopenharmony_ci	spin_unlock_irqrestore(&log_redrive_lock, flags);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	wake_up_process(jfsIOthread);
195662306a36Sopenharmony_ci}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci/*
196062306a36Sopenharmony_ci *	lbmRead()
196162306a36Sopenharmony_ci */
196262306a36Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	struct bio *bio;
196562306a36Sopenharmony_ci	struct lbuf *bp;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	/*
196862306a36Sopenharmony_ci	 * allocate a log buffer
196962306a36Sopenharmony_ci	 */
197062306a36Sopenharmony_ci	*bpp = bp = lbmAllocate(log, pn);
197162306a36Sopenharmony_ci	jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	bp->l_flag |= lbmREAD;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	bio = bio_alloc(log->bdev, 1, REQ_OP_READ, GFP_NOFS);
197662306a36Sopenharmony_ci	bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
197762306a36Sopenharmony_ci	__bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset);
197862306a36Sopenharmony_ci	BUG_ON(bio->bi_iter.bi_size != LOGPSIZE);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	bio->bi_end_io = lbmIODone;
198162306a36Sopenharmony_ci	bio->bi_private = bp;
198262306a36Sopenharmony_ci	/*check if journaling to disk has been disabled*/
198362306a36Sopenharmony_ci	if (log->no_integrity) {
198462306a36Sopenharmony_ci		bio->bi_iter.bi_size = 0;
198562306a36Sopenharmony_ci		lbmIODone(bio);
198662306a36Sopenharmony_ci	} else {
198762306a36Sopenharmony_ci		submit_bio(bio);
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return 0;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci/*
199762306a36Sopenharmony_ci *	lbmWrite()
199862306a36Sopenharmony_ci *
199962306a36Sopenharmony_ci * buffer at head of pageout queue stays after completion of
200062306a36Sopenharmony_ci * partial-page pageout and redriven by explicit initiation of
200162306a36Sopenharmony_ci * pageout by caller until full-page pageout is completed and
200262306a36Sopenharmony_ci * released.
200362306a36Sopenharmony_ci *
200462306a36Sopenharmony_ci * device driver i/o done redrives pageout of new buffer at
200562306a36Sopenharmony_ci * head of pageout queue when current buffer at head of pageout
200662306a36Sopenharmony_ci * queue is released at the completion of its full-page pageout.
200762306a36Sopenharmony_ci *
200862306a36Sopenharmony_ci * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit().
200962306a36Sopenharmony_ci * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone()
201062306a36Sopenharmony_ci */
201162306a36Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
201262306a36Sopenharmony_ci		     int cant_block)
201362306a36Sopenharmony_ci{
201462306a36Sopenharmony_ci	struct lbuf *tail;
201562306a36Sopenharmony_ci	unsigned long flags;
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	jfs_info("lbmWrite: bp:0x%p flag:0x%x pn:0x%x", bp, flag, bp->l_pn);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	/* map the logical block address to physical block address */
202062306a36Sopenharmony_ci	bp->l_blkno =
202162306a36Sopenharmony_ci	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	/*
202662306a36Sopenharmony_ci	 * initialize buffer for device driver
202762306a36Sopenharmony_ci	 */
202862306a36Sopenharmony_ci	bp->l_flag = flag;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	/*
203162306a36Sopenharmony_ci	 *	insert bp at tail of write queue associated with log
203262306a36Sopenharmony_ci	 *
203362306a36Sopenharmony_ci	 * (request is either for bp already/currently at head of queue
203462306a36Sopenharmony_ci	 * or new bp to be inserted at tail)
203562306a36Sopenharmony_ci	 */
203662306a36Sopenharmony_ci	tail = log->wqueue;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	/* is buffer not already on write queue ? */
203962306a36Sopenharmony_ci	if (bp->l_wqnext == NULL) {
204062306a36Sopenharmony_ci		/* insert at tail of wqueue */
204162306a36Sopenharmony_ci		if (tail == NULL) {
204262306a36Sopenharmony_ci			log->wqueue = bp;
204362306a36Sopenharmony_ci			bp->l_wqnext = bp;
204462306a36Sopenharmony_ci		} else {
204562306a36Sopenharmony_ci			log->wqueue = bp;
204662306a36Sopenharmony_ci			bp->l_wqnext = tail->l_wqnext;
204762306a36Sopenharmony_ci			tail->l_wqnext = bp;
204862306a36Sopenharmony_ci		}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci		tail = bp;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	/* is buffer at head of wqueue and for write ? */
205462306a36Sopenharmony_ci	if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) {
205562306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
205662306a36Sopenharmony_ci		return;
205762306a36Sopenharmony_ci	}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	LCACHE_UNLOCK(flags);	/* unlock+enable */
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (cant_block)
206262306a36Sopenharmony_ci		lbmRedrive(bp);
206362306a36Sopenharmony_ci	else if (flag & lbmSYNC)
206462306a36Sopenharmony_ci		lbmStartIO(bp);
206562306a36Sopenharmony_ci	else {
206662306a36Sopenharmony_ci		LOGGC_UNLOCK(log);
206762306a36Sopenharmony_ci		lbmStartIO(bp);
206862306a36Sopenharmony_ci		LOGGC_LOCK(log);
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci/*
207462306a36Sopenharmony_ci *	lbmDirectWrite()
207562306a36Sopenharmony_ci *
207662306a36Sopenharmony_ci * initiate pageout bypassing write queue for sidestream
207762306a36Sopenharmony_ci * (e.g., log superblock) write;
207862306a36Sopenharmony_ci */
207962306a36Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	jfs_info("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x",
208262306a36Sopenharmony_ci		 bp, flag, bp->l_pn);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/*
208562306a36Sopenharmony_ci	 * initialize buffer for device driver
208662306a36Sopenharmony_ci	 */
208762306a36Sopenharmony_ci	bp->l_flag = flag | lbmDIRECT;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	/* map the logical block address to physical block address */
209062306a36Sopenharmony_ci	bp->l_blkno =
209162306a36Sopenharmony_ci	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/*
209462306a36Sopenharmony_ci	 *	initiate pageout of the page
209562306a36Sopenharmony_ci	 */
209662306a36Sopenharmony_ci	lbmStartIO(bp);
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci/*
210162306a36Sopenharmony_ci * NAME:	lbmStartIO()
210262306a36Sopenharmony_ci *
210362306a36Sopenharmony_ci * FUNCTION:	Interface to DD strategy routine
210462306a36Sopenharmony_ci *
210562306a36Sopenharmony_ci * RETURN:	none
210662306a36Sopenharmony_ci *
210762306a36Sopenharmony_ci * serialization: LCACHE_LOCK() is NOT held during log i/o;
210862306a36Sopenharmony_ci */
210962306a36Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	struct bio *bio;
211262306a36Sopenharmony_ci	struct jfs_log *log = bp->l_log;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	jfs_info("lbmStartIO");
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	bio = bio_alloc(log->bdev, 1, REQ_OP_WRITE | REQ_SYNC, GFP_NOFS);
211762306a36Sopenharmony_ci	bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
211862306a36Sopenharmony_ci	__bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset);
211962306a36Sopenharmony_ci	BUG_ON(bio->bi_iter.bi_size != LOGPSIZE);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	bio->bi_end_io = lbmIODone;
212262306a36Sopenharmony_ci	bio->bi_private = bp;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/* check if journaling to disk has been disabled */
212562306a36Sopenharmony_ci	if (log->no_integrity) {
212662306a36Sopenharmony_ci		bio->bi_iter.bi_size = 0;
212762306a36Sopenharmony_ci		lbmIODone(bio);
212862306a36Sopenharmony_ci	} else {
212962306a36Sopenharmony_ci		submit_bio(bio);
213062306a36Sopenharmony_ci		INCREMENT(lmStat.submitted);
213162306a36Sopenharmony_ci	}
213262306a36Sopenharmony_ci}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci/*
213662306a36Sopenharmony_ci *	lbmIOWait()
213762306a36Sopenharmony_ci */
213862306a36Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag)
213962306a36Sopenharmony_ci{
214062306a36Sopenharmony_ci	unsigned long flags;
214162306a36Sopenharmony_ci	int rc = 0;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	jfs_info("lbmIOWait1: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	rc = (bp->l_flag & lbmERROR) ? -EIO : 0;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	if (flag & lbmFREE)
215262306a36Sopenharmony_ci		lbmfree(bp);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	LCACHE_UNLOCK(flags);	/* unlock+enable */
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	jfs_info("lbmIOWait2: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
215762306a36Sopenharmony_ci	return rc;
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci/*
216162306a36Sopenharmony_ci *	lbmIODone()
216262306a36Sopenharmony_ci *
216362306a36Sopenharmony_ci * executed at INTIODONE level
216462306a36Sopenharmony_ci */
216562306a36Sopenharmony_cistatic void lbmIODone(struct bio *bio)
216662306a36Sopenharmony_ci{
216762306a36Sopenharmony_ci	struct lbuf *bp = bio->bi_private;
216862306a36Sopenharmony_ci	struct lbuf *nextbp, *tail;
216962306a36Sopenharmony_ci	struct jfs_log *log;
217062306a36Sopenharmony_ci	unsigned long flags;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/*
217362306a36Sopenharmony_ci	 * get back jfs buffer bound to the i/o buffer
217462306a36Sopenharmony_ci	 */
217562306a36Sopenharmony_ci	jfs_info("lbmIODone: bp:0x%p flag:0x%x", bp, bp->l_flag);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	bp->l_flag |= lbmDONE;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	if (bio->bi_status) {
218262306a36Sopenharmony_ci		bp->l_flag |= lbmERROR;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci		jfs_err("lbmIODone: I/O error in JFS log");
218562306a36Sopenharmony_ci	}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	bio_put(bio);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	/*
219062306a36Sopenharmony_ci	 *	pagein completion
219162306a36Sopenharmony_ci	 */
219262306a36Sopenharmony_ci	if (bp->l_flag & lbmREAD) {
219362306a36Sopenharmony_ci		bp->l_flag &= ~lbmREAD;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci		/* wakeup I/O initiator */
219862306a36Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci		return;
220162306a36Sopenharmony_ci	}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/*
220462306a36Sopenharmony_ci	 *	pageout completion
220562306a36Sopenharmony_ci	 *
220662306a36Sopenharmony_ci	 * the bp at the head of write queue has completed pageout.
220762306a36Sopenharmony_ci	 *
220862306a36Sopenharmony_ci	 * if single-commit/full-page pageout, remove the current buffer
220962306a36Sopenharmony_ci	 * from head of pageout queue, and redrive pageout with
221062306a36Sopenharmony_ci	 * the new buffer at head of pageout queue;
221162306a36Sopenharmony_ci	 * otherwise, the partial-page pageout buffer stays at
221262306a36Sopenharmony_ci	 * the head of pageout queue to be redriven for pageout
221362306a36Sopenharmony_ci	 * by lmGroupCommit() until full-page pageout is completed.
221462306a36Sopenharmony_ci	 */
221562306a36Sopenharmony_ci	bp->l_flag &= ~lbmWRITE;
221662306a36Sopenharmony_ci	INCREMENT(lmStat.pagedone);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	/* update committed lsn */
221962306a36Sopenharmony_ci	log = bp->l_log;
222062306a36Sopenharmony_ci	log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (bp->l_flag & lbmDIRECT) {
222362306a36Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
222462306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);
222562306a36Sopenharmony_ci		return;
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	tail = log->wqueue;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	/* single element queue */
223162306a36Sopenharmony_ci	if (bp == tail) {
223262306a36Sopenharmony_ci		/* remove head buffer of full-page pageout
223362306a36Sopenharmony_ci		 * from log device write queue
223462306a36Sopenharmony_ci		 */
223562306a36Sopenharmony_ci		if (bp->l_flag & lbmRELEASE) {
223662306a36Sopenharmony_ci			log->wqueue = NULL;
223762306a36Sopenharmony_ci			bp->l_wqnext = NULL;
223862306a36Sopenharmony_ci		}
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci	/* multi element queue */
224162306a36Sopenharmony_ci	else {
224262306a36Sopenharmony_ci		/* remove head buffer of full-page pageout
224362306a36Sopenharmony_ci		 * from log device write queue
224462306a36Sopenharmony_ci		 */
224562306a36Sopenharmony_ci		if (bp->l_flag & lbmRELEASE) {
224662306a36Sopenharmony_ci			nextbp = tail->l_wqnext = bp->l_wqnext;
224762306a36Sopenharmony_ci			bp->l_wqnext = NULL;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci			/*
225062306a36Sopenharmony_ci			 * redrive pageout of next page at head of write queue:
225162306a36Sopenharmony_ci			 * redrive next page without any bound tblk
225262306a36Sopenharmony_ci			 * (i.e., page w/o any COMMIT records), or
225362306a36Sopenharmony_ci			 * first page of new group commit which has been
225462306a36Sopenharmony_ci			 * queued after current page (subsequent pageout
225562306a36Sopenharmony_ci			 * is performed synchronously, except page without
225662306a36Sopenharmony_ci			 * any COMMITs) by lmGroupCommit() as indicated
225762306a36Sopenharmony_ci			 * by lbmWRITE flag;
225862306a36Sopenharmony_ci			 */
225962306a36Sopenharmony_ci			if (nextbp->l_flag & lbmWRITE) {
226062306a36Sopenharmony_ci				/*
226162306a36Sopenharmony_ci				 * We can't do the I/O at interrupt time.
226262306a36Sopenharmony_ci				 * The jfsIO thread can do it
226362306a36Sopenharmony_ci				 */
226462306a36Sopenharmony_ci				lbmRedrive(nextbp);
226562306a36Sopenharmony_ci			}
226662306a36Sopenharmony_ci		}
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	/*
227062306a36Sopenharmony_ci	 *	synchronous pageout:
227162306a36Sopenharmony_ci	 *
227262306a36Sopenharmony_ci	 * buffer has not necessarily been removed from write queue
227362306a36Sopenharmony_ci	 * (e.g., synchronous write of partial-page with COMMIT):
227462306a36Sopenharmony_ci	 * leave buffer for i/o initiator to dispose
227562306a36Sopenharmony_ci	 */
227662306a36Sopenharmony_ci	if (bp->l_flag & lbmSYNC) {
227762306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci		/* wakeup I/O initiator */
228062306a36Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	/*
228462306a36Sopenharmony_ci	 *	Group Commit pageout:
228562306a36Sopenharmony_ci	 */
228662306a36Sopenharmony_ci	else if (bp->l_flag & lbmGC) {
228762306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);
228862306a36Sopenharmony_ci		lmPostGC(bp);
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/*
229262306a36Sopenharmony_ci	 *	asynchronous pageout:
229362306a36Sopenharmony_ci	 *
229462306a36Sopenharmony_ci	 * buffer must have been removed from write queue:
229562306a36Sopenharmony_ci	 * insert buffer at head of freelist where it can be recycled
229662306a36Sopenharmony_ci	 */
229762306a36Sopenharmony_ci	else {
229862306a36Sopenharmony_ci		assert(bp->l_flag & lbmRELEASE);
229962306a36Sopenharmony_ci		assert(bp->l_flag & lbmFREE);
230062306a36Sopenharmony_ci		lbmfree(bp);
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
230362306a36Sopenharmony_ci	}
230462306a36Sopenharmony_ci}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ciint jfsIOWait(void *arg)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	struct lbuf *bp;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	do {
231162306a36Sopenharmony_ci		spin_lock_irq(&log_redrive_lock);
231262306a36Sopenharmony_ci		while ((bp = log_redrive_list)) {
231362306a36Sopenharmony_ci			log_redrive_list = bp->l_redrive_next;
231462306a36Sopenharmony_ci			bp->l_redrive_next = NULL;
231562306a36Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
231662306a36Sopenharmony_ci			lbmStartIO(bp);
231762306a36Sopenharmony_ci			spin_lock_irq(&log_redrive_lock);
231862306a36Sopenharmony_ci		}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		if (freezing(current)) {
232162306a36Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
232262306a36Sopenharmony_ci			try_to_freeze();
232362306a36Sopenharmony_ci		} else {
232462306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
232562306a36Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
232662306a36Sopenharmony_ci			schedule();
232762306a36Sopenharmony_ci		}
232862306a36Sopenharmony_ci	} while (!kthread_should_stop());
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	jfs_info("jfsIOWait being killed!");
233162306a36Sopenharmony_ci	return 0;
233262306a36Sopenharmony_ci}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci/*
233562306a36Sopenharmony_ci * NAME:	lmLogFormat()/jfs_logform()
233662306a36Sopenharmony_ci *
233762306a36Sopenharmony_ci * FUNCTION:	format file system log
233862306a36Sopenharmony_ci *
233962306a36Sopenharmony_ci * PARAMETERS:
234062306a36Sopenharmony_ci *	log	- volume log
234162306a36Sopenharmony_ci *	logAddress - start address of log space in FS block
234262306a36Sopenharmony_ci *	logSize	- length of log space in FS block;
234362306a36Sopenharmony_ci *
234462306a36Sopenharmony_ci * RETURN:	0	- success
234562306a36Sopenharmony_ci *		-EIO	- i/o error
234662306a36Sopenharmony_ci *
234762306a36Sopenharmony_ci * XXX: We're synchronously writing one page at a time.  This needs to
234862306a36Sopenharmony_ci *	be improved by writing multiple pages at once.
234962306a36Sopenharmony_ci */
235062306a36Sopenharmony_ciint lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	int rc = -EIO;
235362306a36Sopenharmony_ci	struct jfs_sb_info *sbi;
235462306a36Sopenharmony_ci	struct logsuper *logsuper;
235562306a36Sopenharmony_ci	struct logpage *lp;
235662306a36Sopenharmony_ci	int lspn;		/* log sequence page number */
235762306a36Sopenharmony_ci	struct lrd *lrd_ptr;
235862306a36Sopenharmony_ci	int npages = 0;
235962306a36Sopenharmony_ci	struct lbuf *bp;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	jfs_info("lmLogFormat: logAddress:%Ld logSize:%d",
236262306a36Sopenharmony_ci		 (long long)logAddress, logSize);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	sbi = list_entry(log->sb_list.next, struct jfs_sb_info, log_list);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	/* allocate a log buffer */
236762306a36Sopenharmony_ci	bp = lbmAllocate(log, 1);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	npages = logSize >> sbi->l2nbperpage;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/*
237262306a36Sopenharmony_ci	 *	log space:
237362306a36Sopenharmony_ci	 *
237462306a36Sopenharmony_ci	 * page 0 - reserved;
237562306a36Sopenharmony_ci	 * page 1 - log superblock;
237662306a36Sopenharmony_ci	 * page 2 - log data page: A SYNC log record is written
237762306a36Sopenharmony_ci	 *	    into this page at logform time;
237862306a36Sopenharmony_ci	 * pages 3-N - log data page: set to empty log data pages;
237962306a36Sopenharmony_ci	 */
238062306a36Sopenharmony_ci	/*
238162306a36Sopenharmony_ci	 *	init log superblock: log page 1
238262306a36Sopenharmony_ci	 */
238362306a36Sopenharmony_ci	logsuper = (struct logsuper *) bp->l_ldata;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	logsuper->magic = cpu_to_le32(LOGMAGIC);
238662306a36Sopenharmony_ci	logsuper->version = cpu_to_le32(LOGVERSION);
238762306a36Sopenharmony_ci	logsuper->state = cpu_to_le32(LOGREDONE);
238862306a36Sopenharmony_ci	logsuper->flag = cpu_to_le32(sbi->mntflag);	/* ? */
238962306a36Sopenharmony_ci	logsuper->size = cpu_to_le32(npages);
239062306a36Sopenharmony_ci	logsuper->bsize = cpu_to_le32(sbi->bsize);
239162306a36Sopenharmony_ci	logsuper->l2bsize = cpu_to_le32(sbi->l2bsize);
239262306a36Sopenharmony_ci	logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE);
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
239562306a36Sopenharmony_ci	bp->l_blkno = logAddress + sbi->nbperpage;
239662306a36Sopenharmony_ci	lbmStartIO(bp);
239762306a36Sopenharmony_ci	if ((rc = lbmIOWait(bp, 0)))
239862306a36Sopenharmony_ci		goto exit;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	/*
240162306a36Sopenharmony_ci	 *	init pages 2 to npages-1 as log data pages:
240262306a36Sopenharmony_ci	 *
240362306a36Sopenharmony_ci	 * log page sequence number (lpsn) initialization:
240462306a36Sopenharmony_ci	 *
240562306a36Sopenharmony_ci	 * pn:   0     1     2     3                 n-1
240662306a36Sopenharmony_ci	 *       +-----+-----+=====+=====+===.....===+=====+
240762306a36Sopenharmony_ci	 * lspn:             N-1   0     1           N-2
240862306a36Sopenharmony_ci	 *                   <--- N page circular file ---->
240962306a36Sopenharmony_ci	 *
241062306a36Sopenharmony_ci	 * the N (= npages-2) data pages of the log is maintained as
241162306a36Sopenharmony_ci	 * a circular file for the log records;
241262306a36Sopenharmony_ci	 * lpsn grows by 1 monotonically as each log page is written
241362306a36Sopenharmony_ci	 * to the circular file of the log;
241462306a36Sopenharmony_ci	 * and setLogpage() will not reset the page number even if
241562306a36Sopenharmony_ci	 * the eor is equal to LOGPHDRSIZE. In order for binary search
241662306a36Sopenharmony_ci	 * still work in find log end process, we have to simulate the
241762306a36Sopenharmony_ci	 * log wrap situation at the log format time.
241862306a36Sopenharmony_ci	 * The 1st log page written will have the highest lpsn. Then
241962306a36Sopenharmony_ci	 * the succeeding log pages will have ascending order of
242062306a36Sopenharmony_ci	 * the lspn starting from 0, ... (N-2)
242162306a36Sopenharmony_ci	 */
242262306a36Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
242362306a36Sopenharmony_ci	/*
242462306a36Sopenharmony_ci	 * initialize 1st log page to be written: lpsn = N - 1,
242562306a36Sopenharmony_ci	 * write a SYNCPT log record is written to this page
242662306a36Sopenharmony_ci	 */
242762306a36Sopenharmony_ci	lp->h.page = lp->t.page = cpu_to_le32(npages - 3);
242862306a36Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	lrd_ptr = (struct lrd *) &lp->data;
243162306a36Sopenharmony_ci	lrd_ptr->logtid = 0;
243262306a36Sopenharmony_ci	lrd_ptr->backchain = 0;
243362306a36Sopenharmony_ci	lrd_ptr->type = cpu_to_le16(LOG_SYNCPT);
243462306a36Sopenharmony_ci	lrd_ptr->length = 0;
243562306a36Sopenharmony_ci	lrd_ptr->log.syncpt.sync = 0;
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	bp->l_blkno += sbi->nbperpage;
243862306a36Sopenharmony_ci	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
243962306a36Sopenharmony_ci	lbmStartIO(bp);
244062306a36Sopenharmony_ci	if ((rc = lbmIOWait(bp, 0)))
244162306a36Sopenharmony_ci		goto exit;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	/*
244462306a36Sopenharmony_ci	 *	initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
244562306a36Sopenharmony_ci	 */
244662306a36Sopenharmony_ci	for (lspn = 0; lspn < npages - 3; lspn++) {
244762306a36Sopenharmony_ci		lp->h.page = lp->t.page = cpu_to_le32(lspn);
244862306a36Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci		bp->l_blkno += sbi->nbperpage;
245162306a36Sopenharmony_ci		bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
245262306a36Sopenharmony_ci		lbmStartIO(bp);
245362306a36Sopenharmony_ci		if ((rc = lbmIOWait(bp, 0)))
245462306a36Sopenharmony_ci			goto exit;
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	rc = 0;
245862306a36Sopenharmony_ciexit:
245962306a36Sopenharmony_ci	/*
246062306a36Sopenharmony_ci	 *	finalize log
246162306a36Sopenharmony_ci	 */
246262306a36Sopenharmony_ci	/* release the buffer */
246362306a36Sopenharmony_ci	lbmFree(bp);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	return rc;
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS
246962306a36Sopenharmony_ciint jfs_lmstats_proc_show(struct seq_file *m, void *v)
247062306a36Sopenharmony_ci{
247162306a36Sopenharmony_ci	seq_printf(m,
247262306a36Sopenharmony_ci		       "JFS Logmgr stats\n"
247362306a36Sopenharmony_ci		       "================\n"
247462306a36Sopenharmony_ci		       "commits = %d\n"
247562306a36Sopenharmony_ci		       "writes submitted = %d\n"
247662306a36Sopenharmony_ci		       "writes completed = %d\n"
247762306a36Sopenharmony_ci		       "full pages submitted = %d\n"
247862306a36Sopenharmony_ci		       "partial pages submitted = %d\n",
247962306a36Sopenharmony_ci		       lmStat.commit,
248062306a36Sopenharmony_ci		       lmStat.submitted,
248162306a36Sopenharmony_ci		       lmStat.pagedone,
248262306a36Sopenharmony_ci		       lmStat.full_page,
248362306a36Sopenharmony_ci		       lmStat.partial_page);
248462306a36Sopenharmony_ci	return 0;
248562306a36Sopenharmony_ci}
248662306a36Sopenharmony_ci#endif /* CONFIG_JFS_STATISTICS */
2487