18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
48c2ecf20Sopenharmony_ci *   Portions Copyright (C) Christoph Hellwig, 2001-2002
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci *	jfs_logmgr.c: log manager
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * for related information, see transaction manager (jfs_txnmgr.c), and
118c2ecf20Sopenharmony_ci * recovery manager (jfs_logredo.c).
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * note: for detail, RTFS.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *	log buffer manager:
168c2ecf20Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements.
178c2ecf20Sopenharmony_ci * per log serial pageout of logpage
188c2ecf20Sopenharmony_ci * queuing i/o requests and redrive i/o at iodone
198c2ecf20Sopenharmony_ci * maintain current logpage buffer
208c2ecf20Sopenharmony_ci * no caching since append only
218c2ecf20Sopenharmony_ci * appropriate jfs buffer cache buffers as needed
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *	group commit:
248c2ecf20Sopenharmony_ci * transactions which wrote COMMIT records in the same in-memory
258c2ecf20Sopenharmony_ci * log page during the pageout of previous/current log page(s) are
268c2ecf20Sopenharmony_ci * committed together by the pageout of the page.
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci *	TBD lazy commit:
298c2ecf20Sopenharmony_ci * transactions are committed asynchronously when the log page
308c2ecf20Sopenharmony_ci * containing it COMMIT is paged out when it becomes full;
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci *	serialization:
338c2ecf20Sopenharmony_ci * . a per log lock serialize log write.
348c2ecf20Sopenharmony_ci * . a per log lock serialize group commit.
358c2ecf20Sopenharmony_ci * . a per log lock serialize log open/close;
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci *	TBD log integrity:
388c2ecf20Sopenharmony_ci * careful-write (ping-pong) of last logpage to recover from crash
398c2ecf20Sopenharmony_ci * in overwrite.
408c2ecf20Sopenharmony_ci * detection of split (out-of-order) write of physical sectors
418c2ecf20Sopenharmony_ci * of last logpage via timestamp at end of each sector
428c2ecf20Sopenharmony_ci * with its mirror data array at trailer).
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci *	alternatives:
458c2ecf20Sopenharmony_ci * lsn - 64-bit monotonically increasing integer vs
468c2ecf20Sopenharmony_ci * 32-bit lspn and page eor.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include <linux/fs.h>
508c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
518c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
528c2ecf20Sopenharmony_ci#include <linux/completion.h>
538c2ecf20Sopenharmony_ci#include <linux/kthread.h>
548c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>		/* for sync_blockdev() */
558c2ecf20Sopenharmony_ci#include <linux/bio.h>
568c2ecf20Sopenharmony_ci#include <linux/freezer.h>
578c2ecf20Sopenharmony_ci#include <linux/export.h>
588c2ecf20Sopenharmony_ci#include <linux/delay.h>
598c2ecf20Sopenharmony_ci#include <linux/mutex.h>
608c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
618c2ecf20Sopenharmony_ci#include <linux/slab.h>
628c2ecf20Sopenharmony_ci#include "jfs_incore.h"
638c2ecf20Sopenharmony_ci#include "jfs_filsys.h"
648c2ecf20Sopenharmony_ci#include "jfs_metapage.h"
658c2ecf20Sopenharmony_ci#include "jfs_superblock.h"
668c2ecf20Sopenharmony_ci#include "jfs_txnmgr.h"
678c2ecf20Sopenharmony_ci#include "jfs_debug.h"
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*
718c2ecf20Sopenharmony_ci * lbuf's ready to be redriven.  Protected by log_redrive_lock (jfsIO thread)
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic struct lbuf *log_redrive_list;
748c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(log_redrive_lock);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci *	log read/write serialization (per log)
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ci#define LOG_LOCK_INIT(log)	mutex_init(&(log)->loglock)
818c2ecf20Sopenharmony_ci#define LOG_LOCK(log)		mutex_lock(&((log)->loglock))
828c2ecf20Sopenharmony_ci#define LOG_UNLOCK(log)		mutex_unlock(&((log)->loglock))
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/*
868c2ecf20Sopenharmony_ci *	log group commit serialization (per log)
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define LOGGC_LOCK_INIT(log)	spin_lock_init(&(log)->gclock)
908c2ecf20Sopenharmony_ci#define LOGGC_LOCK(log)		spin_lock_irq(&(log)->gclock)
918c2ecf20Sopenharmony_ci#define LOGGC_UNLOCK(log)	spin_unlock_irq(&(log)->gclock)
928c2ecf20Sopenharmony_ci#define LOGGC_WAKEUP(tblk)	wake_up_all(&(tblk)->gcwait)
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci *	log sync serialization (per log)
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci#define	LOGSYNC_DELTA(logsize)		min((logsize)/8, 128*LOGPSIZE)
988c2ecf20Sopenharmony_ci#define	LOGSYNC_BARRIER(logsize)	((logsize)/4)
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci#define	LOGSYNC_DELTA(logsize)		min((logsize)/4, 256*LOGPSIZE)
1018c2ecf20Sopenharmony_ci#define	LOGSYNC_BARRIER(logsize)	((logsize)/2)
1028c2ecf20Sopenharmony_ci*/
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/*
1068c2ecf20Sopenharmony_ci *	log buffer cache synchronization
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(jfsLCacheLock);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define	LCACHE_LOCK(flags)	spin_lock_irqsave(&jfsLCacheLock, flags)
1118c2ecf20Sopenharmony_ci#define	LCACHE_UNLOCK(flags)	spin_unlock_irqrestore(&jfsLCacheLock, flags)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/*
1148c2ecf20Sopenharmony_ci * See __SLEEP_COND in jfs_locks.h
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_ci#define LCACHE_SLEEP_COND(wq, cond, flags)	\
1178c2ecf20Sopenharmony_cido {						\
1188c2ecf20Sopenharmony_ci	if (cond)				\
1198c2ecf20Sopenharmony_ci		break;				\
1208c2ecf20Sopenharmony_ci	__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
1218c2ecf20Sopenharmony_ci} while (0)
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci#define	LCACHE_WAKEUP(event)	wake_up(event)
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/*
1278c2ecf20Sopenharmony_ci *	lbuf buffer cache (lCache) control
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_ci/* log buffer manager pageout control (cumulative, inclusive) */
1308c2ecf20Sopenharmony_ci#define	lbmREAD		0x0001
1318c2ecf20Sopenharmony_ci#define	lbmWRITE	0x0002	/* enqueue at tail of write queue;
1328c2ecf20Sopenharmony_ci				 * init pageout if at head of queue;
1338c2ecf20Sopenharmony_ci				 */
1348c2ecf20Sopenharmony_ci#define	lbmRELEASE	0x0004	/* remove from write queue
1358c2ecf20Sopenharmony_ci				 * at completion of pageout;
1368c2ecf20Sopenharmony_ci				 * do not free/recycle it yet:
1378c2ecf20Sopenharmony_ci				 * caller will free it;
1388c2ecf20Sopenharmony_ci				 */
1398c2ecf20Sopenharmony_ci#define	lbmSYNC		0x0008	/* do not return to freelist
1408c2ecf20Sopenharmony_ci				 * when removed from write queue;
1418c2ecf20Sopenharmony_ci				 */
1428c2ecf20Sopenharmony_ci#define lbmFREE		0x0010	/* return to freelist
1438c2ecf20Sopenharmony_ci				 * at completion of pageout;
1448c2ecf20Sopenharmony_ci				 * the buffer may be recycled;
1458c2ecf20Sopenharmony_ci				 */
1468c2ecf20Sopenharmony_ci#define	lbmDONE		0x0020
1478c2ecf20Sopenharmony_ci#define	lbmERROR	0x0040
1488c2ecf20Sopenharmony_ci#define lbmGC		0x0080	/* lbmIODone to perform post-GC processing
1498c2ecf20Sopenharmony_ci				 * of log page
1508c2ecf20Sopenharmony_ci				 */
1518c2ecf20Sopenharmony_ci#define lbmDIRECT	0x0100
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * Global list of active external journals
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_cistatic LIST_HEAD(jfs_external_logs);
1578c2ecf20Sopenharmony_cistatic struct jfs_log *dummy_log;
1588c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(jfs_log_mutex);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * forward references
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_cistatic int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
1648c2ecf20Sopenharmony_ci			 struct lrd * lrd, struct tlock * tlck);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int lmNextPage(struct jfs_log * log);
1678c2ecf20Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
1688c2ecf20Sopenharmony_ci			   int activate);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int open_inline_log(struct super_block *sb);
1718c2ecf20Sopenharmony_cistatic int open_dummy_log(struct super_block *sb);
1728c2ecf20Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log);
1738c2ecf20Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log);
1748c2ecf20Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int);
1758c2ecf20Sopenharmony_cistatic void lbmFree(struct lbuf * bp);
1768c2ecf20Sopenharmony_cistatic void lbmfree(struct lbuf * bp);
1778c2ecf20Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
1788c2ecf20Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block);
1798c2ecf20Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
1808c2ecf20Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag);
1818c2ecf20Sopenharmony_cistatic bio_end_io_t lbmIODone;
1828c2ecf20Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp);
1838c2ecf20Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_block);
1848c2ecf20Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/*
1898c2ecf20Sopenharmony_ci *	statistics
1908c2ecf20Sopenharmony_ci */
1918c2ecf20Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS
1928c2ecf20Sopenharmony_cistatic struct lmStat {
1938c2ecf20Sopenharmony_ci	uint commit;		/* # of commit */
1948c2ecf20Sopenharmony_ci	uint pagedone;		/* # of page written */
1958c2ecf20Sopenharmony_ci	uint submitted;		/* # of pages submitted */
1968c2ecf20Sopenharmony_ci	uint full_page;		/* # of full pages submitted */
1978c2ecf20Sopenharmony_ci	uint partial_page;	/* # of partial pages submitted */
1988c2ecf20Sopenharmony_ci} lmStat;
1998c2ecf20Sopenharmony_ci#endif
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void write_special_inodes(struct jfs_log *log,
2028c2ecf20Sopenharmony_ci				 int (*writer)(struct address_space *))
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	list_for_each_entry(sbi, &log->sb_list, log_list) {
2078c2ecf20Sopenharmony_ci		writer(sbi->ipbmap->i_mapping);
2088c2ecf20Sopenharmony_ci		writer(sbi->ipimap->i_mapping);
2098c2ecf20Sopenharmony_ci		writer(sbi->direct_inode->i_mapping);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * NAME:	lmLog()
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * FUNCTION:	write a log record;
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci * PARAMETER:
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * RETURN:	lsn - offset to the next log record to write (end-of-log);
2218c2ecf20Sopenharmony_ci *		-1  - error;
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * note: todo: log error handler
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_ciint lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
2268c2ecf20Sopenharmony_ci	  struct tlock * tlck)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	int lsn;
2298c2ecf20Sopenharmony_ci	int diffp, difft;
2308c2ecf20Sopenharmony_ci	struct metapage *mp = NULL;
2318c2ecf20Sopenharmony_ci	unsigned long flags;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
2348c2ecf20Sopenharmony_ci		 log, tblk, lrd, tlck);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	LOG_LOCK(log);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* log by (out-of-transaction) JFS ? */
2398c2ecf20Sopenharmony_ci	if (tblk == NULL)
2408c2ecf20Sopenharmony_ci		goto writeRecord;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* log from page ? */
2438c2ecf20Sopenharmony_ci	if (tlck == NULL ||
2448c2ecf20Sopenharmony_ci	    tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
2458c2ecf20Sopenharmony_ci		goto writeRecord;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/*
2488c2ecf20Sopenharmony_ci	 *	initialize/update page/transaction recovery lsn
2498c2ecf20Sopenharmony_ci	 */
2508c2ecf20Sopenharmony_ci	lsn = log->lsn;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	LOGSYNC_LOCK(log, flags);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * initialize page lsn if first log write of the page
2568c2ecf20Sopenharmony_ci	 */
2578c2ecf20Sopenharmony_ci	if (mp->lsn == 0) {
2588c2ecf20Sopenharmony_ci		mp->log = log;
2598c2ecf20Sopenharmony_ci		mp->lsn = lsn;
2608c2ecf20Sopenharmony_ci		log->count++;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		/* insert page at tail of logsynclist */
2638c2ecf20Sopenharmony_ci		list_add_tail(&mp->synclist, &log->synclist);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/*
2678c2ecf20Sopenharmony_ci	 *	initialize/update lsn of tblock of the page
2688c2ecf20Sopenharmony_ci	 *
2698c2ecf20Sopenharmony_ci	 * transaction inherits oldest lsn of pages associated
2708c2ecf20Sopenharmony_ci	 * with allocation/deallocation of resources (their
2718c2ecf20Sopenharmony_ci	 * log records are used to reconstruct allocation map
2728c2ecf20Sopenharmony_ci	 * at recovery time: inode for inode allocation map,
2738c2ecf20Sopenharmony_ci	 * B+-tree index of extent descriptors for block
2748c2ecf20Sopenharmony_ci	 * allocation map);
2758c2ecf20Sopenharmony_ci	 * allocation map pages inherit transaction lsn at
2768c2ecf20Sopenharmony_ci	 * commit time to allow forwarding log syncpt past log
2778c2ecf20Sopenharmony_ci	 * records associated with allocation/deallocation of
2788c2ecf20Sopenharmony_ci	 * resources only after persistent map of these map pages
2798c2ecf20Sopenharmony_ci	 * have been updated and propagated to home.
2808c2ecf20Sopenharmony_ci	 */
2818c2ecf20Sopenharmony_ci	/*
2828c2ecf20Sopenharmony_ci	 * initialize transaction lsn:
2838c2ecf20Sopenharmony_ci	 */
2848c2ecf20Sopenharmony_ci	if (tblk->lsn == 0) {
2858c2ecf20Sopenharmony_ci		/* inherit lsn of its first page logged */
2868c2ecf20Sopenharmony_ci		tblk->lsn = mp->lsn;
2878c2ecf20Sopenharmony_ci		log->count++;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		/* insert tblock after the page on logsynclist */
2908c2ecf20Sopenharmony_ci		list_add(&tblk->synclist, &mp->synclist);
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	/*
2938c2ecf20Sopenharmony_ci	 * update transaction lsn:
2948c2ecf20Sopenharmony_ci	 */
2958c2ecf20Sopenharmony_ci	else {
2968c2ecf20Sopenharmony_ci		/* inherit oldest/smallest lsn of page */
2978c2ecf20Sopenharmony_ci		logdiff(diffp, mp->lsn, log);
2988c2ecf20Sopenharmony_ci		logdiff(difft, tblk->lsn, log);
2998c2ecf20Sopenharmony_ci		if (diffp < difft) {
3008c2ecf20Sopenharmony_ci			/* update tblock lsn with page lsn */
3018c2ecf20Sopenharmony_ci			tblk->lsn = mp->lsn;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci			/* move tblock after page on logsynclist */
3048c2ecf20Sopenharmony_ci			list_move(&tblk->synclist, &mp->synclist);
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	LOGSYNC_UNLOCK(log, flags);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 *	write the log record
3128c2ecf20Sopenharmony_ci	 */
3138c2ecf20Sopenharmony_ci      writeRecord:
3148c2ecf20Sopenharmony_ci	lsn = lmWriteRecord(log, tblk, lrd, tlck);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/*
3178c2ecf20Sopenharmony_ci	 * forward log syncpt if log reached next syncpt trigger
3188c2ecf20Sopenharmony_ci	 */
3198c2ecf20Sopenharmony_ci	logdiff(diffp, lsn, log);
3208c2ecf20Sopenharmony_ci	if (diffp >= log->nextsync)
3218c2ecf20Sopenharmony_ci		lsn = lmLogSync(log, 0);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	/* update end-of-log lsn */
3248c2ecf20Sopenharmony_ci	log->lsn = lsn;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	LOG_UNLOCK(log);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* return end-of-log address */
3298c2ecf20Sopenharmony_ci	return lsn;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/*
3338c2ecf20Sopenharmony_ci * NAME:	lmWriteRecord()
3348c2ecf20Sopenharmony_ci *
3358c2ecf20Sopenharmony_ci * FUNCTION:	move the log record to current log page
3368c2ecf20Sopenharmony_ci *
3378c2ecf20Sopenharmony_ci * PARAMETER:	cd	- commit descriptor
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * RETURN:	end-of-log address
3408c2ecf20Sopenharmony_ci *
3418c2ecf20Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_cistatic int
3448c2ecf20Sopenharmony_cilmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
3458c2ecf20Sopenharmony_ci	      struct tlock * tlck)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	int lsn = 0;		/* end-of-log address */
3488c2ecf20Sopenharmony_ci	struct lbuf *bp;	/* dst log page buffer */
3498c2ecf20Sopenharmony_ci	struct logpage *lp;	/* dst log page */
3508c2ecf20Sopenharmony_ci	caddr_t dst;		/* destination address in log page */
3518c2ecf20Sopenharmony_ci	int dstoffset;		/* end-of-log offset in log page */
3528c2ecf20Sopenharmony_ci	int freespace;		/* free space in log page */
3538c2ecf20Sopenharmony_ci	caddr_t p;		/* src meta-data page */
3548c2ecf20Sopenharmony_ci	caddr_t src;
3558c2ecf20Sopenharmony_ci	int srclen;
3568c2ecf20Sopenharmony_ci	int nbytes;		/* number of bytes to move */
3578c2ecf20Sopenharmony_ci	int i;
3588c2ecf20Sopenharmony_ci	int len;
3598c2ecf20Sopenharmony_ci	struct linelock *linelock;
3608c2ecf20Sopenharmony_ci	struct lv *lv;
3618c2ecf20Sopenharmony_ci	struct lvd *lvd;
3628c2ecf20Sopenharmony_ci	int l2linesize;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	len = 0;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/* retrieve destination log page to write */
3678c2ecf20Sopenharmony_ci	bp = (struct lbuf *) log->bp;
3688c2ecf20Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
3698c2ecf20Sopenharmony_ci	dstoffset = log->eor;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* any log data to write ? */
3728c2ecf20Sopenharmony_ci	if (tlck == NULL)
3738c2ecf20Sopenharmony_ci		goto moveLrd;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/*
3768c2ecf20Sopenharmony_ci	 *	move log record data
3778c2ecf20Sopenharmony_ci	 */
3788c2ecf20Sopenharmony_ci	/* retrieve source meta-data page to log */
3798c2ecf20Sopenharmony_ci	if (tlck->flag & tlckPAGELOCK) {
3808c2ecf20Sopenharmony_ci		p = (caddr_t) (tlck->mp->data);
3818c2ecf20Sopenharmony_ci		linelock = (struct linelock *) & tlck->lock;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	/* retrieve source in-memory inode to log */
3848c2ecf20Sopenharmony_ci	else if (tlck->flag & tlckINODELOCK) {
3858c2ecf20Sopenharmony_ci		if (tlck->type & tlckDTREE)
3868c2ecf20Sopenharmony_ci			p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
3878c2ecf20Sopenharmony_ci		else
3888c2ecf20Sopenharmony_ci			p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
3898c2ecf20Sopenharmony_ci		linelock = (struct linelock *) & tlck->lock;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci#ifdef	_JFS_WIP
3928c2ecf20Sopenharmony_ci	else if (tlck->flag & tlckINLINELOCK) {
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		inlinelock = (struct inlinelock *) & tlck;
3958c2ecf20Sopenharmony_ci		p = (caddr_t) & inlinelock->pxd;
3968c2ecf20Sopenharmony_ci		linelock = (struct linelock *) & tlck;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci#endif				/* _JFS_WIP */
3998c2ecf20Sopenharmony_ci	else {
4008c2ecf20Sopenharmony_ci		jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck);
4018c2ecf20Sopenharmony_ci		return 0;	/* Probably should trap */
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci	l2linesize = linelock->l2linesize;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci      moveData:
4068c2ecf20Sopenharmony_ci	ASSERT(linelock->index <= linelock->maxcnt);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	lv = linelock->lv;
4098c2ecf20Sopenharmony_ci	for (i = 0; i < linelock->index; i++, lv++) {
4108c2ecf20Sopenharmony_ci		if (lv->length == 0)
4118c2ecf20Sopenharmony_ci			continue;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		/* is page full ? */
4148c2ecf20Sopenharmony_ci		if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
4158c2ecf20Sopenharmony_ci			/* page become full: move on to next page */
4168c2ecf20Sopenharmony_ci			lmNextPage(log);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			bp = log->bp;
4198c2ecf20Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
4208c2ecf20Sopenharmony_ci			dstoffset = LOGPHDRSIZE;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		/*
4248c2ecf20Sopenharmony_ci		 * move log vector data
4258c2ecf20Sopenharmony_ci		 */
4268c2ecf20Sopenharmony_ci		src = (u8 *) p + (lv->offset << l2linesize);
4278c2ecf20Sopenharmony_ci		srclen = lv->length << l2linesize;
4288c2ecf20Sopenharmony_ci		len += srclen;
4298c2ecf20Sopenharmony_ci		while (srclen > 0) {
4308c2ecf20Sopenharmony_ci			freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
4318c2ecf20Sopenharmony_ci			nbytes = min(freespace, srclen);
4328c2ecf20Sopenharmony_ci			dst = (caddr_t) lp + dstoffset;
4338c2ecf20Sopenharmony_ci			memcpy(dst, src, nbytes);
4348c2ecf20Sopenharmony_ci			dstoffset += nbytes;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci			/* is page not full ? */
4378c2ecf20Sopenharmony_ci			if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
4388c2ecf20Sopenharmony_ci				break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci			/* page become full: move on to next page */
4418c2ecf20Sopenharmony_ci			lmNextPage(log);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci			bp = (struct lbuf *) log->bp;
4448c2ecf20Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
4458c2ecf20Sopenharmony_ci			dstoffset = LOGPHDRSIZE;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci			srclen -= nbytes;
4488c2ecf20Sopenharmony_ci			src += nbytes;
4498c2ecf20Sopenharmony_ci		}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		/*
4528c2ecf20Sopenharmony_ci		 * move log vector descriptor
4538c2ecf20Sopenharmony_ci		 */
4548c2ecf20Sopenharmony_ci		len += 4;
4558c2ecf20Sopenharmony_ci		lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
4568c2ecf20Sopenharmony_ci		lvd->offset = cpu_to_le16(lv->offset);
4578c2ecf20Sopenharmony_ci		lvd->length = cpu_to_le16(lv->length);
4588c2ecf20Sopenharmony_ci		dstoffset += 4;
4598c2ecf20Sopenharmony_ci		jfs_info("lmWriteRecord: lv offset:%d length:%d",
4608c2ecf20Sopenharmony_ci			 lv->offset, lv->length);
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if ((i = linelock->next)) {
4648c2ecf20Sopenharmony_ci		linelock = (struct linelock *) lid_to_tlock(i);
4658c2ecf20Sopenharmony_ci		goto moveData;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/*
4698c2ecf20Sopenharmony_ci	 *	move log record descriptor
4708c2ecf20Sopenharmony_ci	 */
4718c2ecf20Sopenharmony_ci      moveLrd:
4728c2ecf20Sopenharmony_ci	lrd->length = cpu_to_le16(len);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	src = (caddr_t) lrd;
4758c2ecf20Sopenharmony_ci	srclen = LOGRDSIZE;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	while (srclen > 0) {
4788c2ecf20Sopenharmony_ci		freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
4798c2ecf20Sopenharmony_ci		nbytes = min(freespace, srclen);
4808c2ecf20Sopenharmony_ci		dst = (caddr_t) lp + dstoffset;
4818c2ecf20Sopenharmony_ci		memcpy(dst, src, nbytes);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		dstoffset += nbytes;
4848c2ecf20Sopenharmony_ci		srclen -= nbytes;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		/* are there more to move than freespace of page ? */
4878c2ecf20Sopenharmony_ci		if (srclen)
4888c2ecf20Sopenharmony_ci			goto pageFull;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		/*
4918c2ecf20Sopenharmony_ci		 * end of log record descriptor
4928c2ecf20Sopenharmony_ci		 */
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		/* update last log record eor */
4958c2ecf20Sopenharmony_ci		log->eor = dstoffset;
4968c2ecf20Sopenharmony_ci		bp->l_eor = dstoffset;
4978c2ecf20Sopenharmony_ci		lsn = (log->page << L2LOGPSIZE) + dstoffset;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
5008c2ecf20Sopenharmony_ci			tblk->clsn = lsn;
5018c2ecf20Sopenharmony_ci			jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn,
5028c2ecf20Sopenharmony_ci				 bp->l_eor);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci			INCREMENT(lmStat.commit);	/* # of commit */
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci			/*
5078c2ecf20Sopenharmony_ci			 * enqueue tblock for group commit:
5088c2ecf20Sopenharmony_ci			 *
5098c2ecf20Sopenharmony_ci			 * enqueue tblock of non-trivial/synchronous COMMIT
5108c2ecf20Sopenharmony_ci			 * at tail of group commit queue
5118c2ecf20Sopenharmony_ci			 * (trivial/asynchronous COMMITs are ignored by
5128c2ecf20Sopenharmony_ci			 * group commit.)
5138c2ecf20Sopenharmony_ci			 */
5148c2ecf20Sopenharmony_ci			LOGGC_LOCK(log);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci			/* init tblock gc state */
5178c2ecf20Sopenharmony_ci			tblk->flag = tblkGC_QUEUE;
5188c2ecf20Sopenharmony_ci			tblk->bp = log->bp;
5198c2ecf20Sopenharmony_ci			tblk->pn = log->page;
5208c2ecf20Sopenharmony_ci			tblk->eor = log->eor;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci			/* enqueue transaction to commit queue */
5238c2ecf20Sopenharmony_ci			list_add_tail(&tblk->cqueue, &log->cqueue);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci			LOGGC_UNLOCK(log);
5268c2ecf20Sopenharmony_ci		}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x",
5298c2ecf20Sopenharmony_ci			le16_to_cpu(lrd->type), log->bp, log->page, dstoffset);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci		/* page not full ? */
5328c2ecf20Sopenharmony_ci		if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
5338c2ecf20Sopenharmony_ci			return lsn;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	      pageFull:
5368c2ecf20Sopenharmony_ci		/* page become full: move on to next page */
5378c2ecf20Sopenharmony_ci		lmNextPage(log);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		bp = (struct lbuf *) log->bp;
5408c2ecf20Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
5418c2ecf20Sopenharmony_ci		dstoffset = LOGPHDRSIZE;
5428c2ecf20Sopenharmony_ci		src += nbytes;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return lsn;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/*
5508c2ecf20Sopenharmony_ci * NAME:	lmNextPage()
5518c2ecf20Sopenharmony_ci *
5528c2ecf20Sopenharmony_ci * FUNCTION:	write current page and allocate next page.
5538c2ecf20Sopenharmony_ci *
5548c2ecf20Sopenharmony_ci * PARAMETER:	log
5558c2ecf20Sopenharmony_ci *
5568c2ecf20Sopenharmony_ci * RETURN:	0
5578c2ecf20Sopenharmony_ci *
5588c2ecf20Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_cistatic int lmNextPage(struct jfs_log * log)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct logpage *lp;
5638c2ecf20Sopenharmony_ci	int lspn;		/* log sequence page number */
5648c2ecf20Sopenharmony_ci	int pn;			/* current page number */
5658c2ecf20Sopenharmony_ci	struct lbuf *bp;
5668c2ecf20Sopenharmony_ci	struct lbuf *nextbp;
5678c2ecf20Sopenharmony_ci	struct tblock *tblk;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* get current log page number and log sequence page number */
5708c2ecf20Sopenharmony_ci	pn = log->page;
5718c2ecf20Sopenharmony_ci	bp = log->bp;
5728c2ecf20Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
5738c2ecf20Sopenharmony_ci	lspn = le32_to_cpu(lp->h.page);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	LOGGC_LOCK(log);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/*
5788c2ecf20Sopenharmony_ci	 *	write or queue the full page at the tail of write queue
5798c2ecf20Sopenharmony_ci	 */
5808c2ecf20Sopenharmony_ci	/* get the tail tblk on commit queue */
5818c2ecf20Sopenharmony_ci	if (list_empty(&log->cqueue))
5828c2ecf20Sopenharmony_ci		tblk = NULL;
5838c2ecf20Sopenharmony_ci	else
5848c2ecf20Sopenharmony_ci		tblk = list_entry(log->cqueue.prev, struct tblock, cqueue);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* every tblk who has COMMIT record on the current page,
5878c2ecf20Sopenharmony_ci	 * and has not been committed, must be on commit queue
5888c2ecf20Sopenharmony_ci	 * since tblk is queued at commit queueu at the time
5898c2ecf20Sopenharmony_ci	 * of writing its COMMIT record on the page before
5908c2ecf20Sopenharmony_ci	 * page becomes full (even though the tblk thread
5918c2ecf20Sopenharmony_ci	 * who wrote COMMIT record may have been suspended
5928c2ecf20Sopenharmony_ci	 * currently);
5938c2ecf20Sopenharmony_ci	 */
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/* is page bound with outstanding tail tblk ? */
5968c2ecf20Sopenharmony_ci	if (tblk && tblk->pn == pn) {
5978c2ecf20Sopenharmony_ci		/* mark tblk for end-of-page */
5988c2ecf20Sopenharmony_ci		tblk->flag |= tblkGC_EOP;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		if (log->cflag & logGC_PAGEOUT) {
6018c2ecf20Sopenharmony_ci			/* if page is not already on write queue,
6028c2ecf20Sopenharmony_ci			 * just enqueue (no lbmWRITE to prevent redrive)
6038c2ecf20Sopenharmony_ci			 * buffer to wqueue to ensure correct serial order
6048c2ecf20Sopenharmony_ci			 * of the pages since log pages will be added
6058c2ecf20Sopenharmony_ci			 * continuously
6068c2ecf20Sopenharmony_ci			 */
6078c2ecf20Sopenharmony_ci			if (bp->l_wqnext == NULL)
6088c2ecf20Sopenharmony_ci				lbmWrite(log, bp, 0, 0);
6098c2ecf20Sopenharmony_ci		} else {
6108c2ecf20Sopenharmony_ci			/*
6118c2ecf20Sopenharmony_ci			 * No current GC leader, initiate group commit
6128c2ecf20Sopenharmony_ci			 */
6138c2ecf20Sopenharmony_ci			log->cflag |= logGC_PAGEOUT;
6148c2ecf20Sopenharmony_ci			lmGCwrite(log, 0);
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci	/* page is not bound with outstanding tblk:
6188c2ecf20Sopenharmony_ci	 * init write or mark it to be redriven (lbmWRITE)
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	else {
6218c2ecf20Sopenharmony_ci		/* finalize the page */
6228c2ecf20Sopenharmony_ci		bp->l_ceor = bp->l_eor;
6238c2ecf20Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
6248c2ecf20Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci	LOGGC_UNLOCK(log);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/*
6298c2ecf20Sopenharmony_ci	 *	allocate/initialize next page
6308c2ecf20Sopenharmony_ci	 */
6318c2ecf20Sopenharmony_ci	/* if log wraps, the first data page of log is 2
6328c2ecf20Sopenharmony_ci	 * (0 never used, 1 is superblock).
6338c2ecf20Sopenharmony_ci	 */
6348c2ecf20Sopenharmony_ci	log->page = (pn == log->size - 1) ? 2 : pn + 1;
6358c2ecf20Sopenharmony_ci	log->eor = LOGPHDRSIZE;	/* ? valid page empty/full at logRedo() */
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* allocate/initialize next log page buffer */
6388c2ecf20Sopenharmony_ci	nextbp = lbmAllocate(log, log->page);
6398c2ecf20Sopenharmony_ci	nextbp->l_eor = log->eor;
6408c2ecf20Sopenharmony_ci	log->bp = nextbp;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	/* initialize next log page */
6438c2ecf20Sopenharmony_ci	lp = (struct logpage *) nextbp->l_ldata;
6448c2ecf20Sopenharmony_ci	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
6458c2ecf20Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci/*
6528c2ecf20Sopenharmony_ci * NAME:	lmGroupCommit()
6538c2ecf20Sopenharmony_ci *
6548c2ecf20Sopenharmony_ci * FUNCTION:	group commit
6558c2ecf20Sopenharmony_ci *	initiate pageout of the pages with COMMIT in the order of
6568c2ecf20Sopenharmony_ci *	page number - redrive pageout of the page at the head of
6578c2ecf20Sopenharmony_ci *	pageout queue until full page has been written.
6588c2ecf20Sopenharmony_ci *
6598c2ecf20Sopenharmony_ci * RETURN:
6608c2ecf20Sopenharmony_ci *
6618c2ecf20Sopenharmony_ci * NOTE:
6628c2ecf20Sopenharmony_ci *	LOGGC_LOCK serializes log group commit queue, and
6638c2ecf20Sopenharmony_ci *	transaction blocks on the commit queue.
6648c2ecf20Sopenharmony_ci *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
6658c2ecf20Sopenharmony_ci */
6668c2ecf20Sopenharmony_ciint lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	int rc = 0;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	LOGGC_LOCK(log);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* group committed already ? */
6738c2ecf20Sopenharmony_ci	if (tblk->flag & tblkGC_COMMITTED) {
6748c2ecf20Sopenharmony_ci		if (tblk->flag & tblkGC_ERROR)
6758c2ecf20Sopenharmony_ci			rc = -EIO;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		LOGGC_UNLOCK(log);
6788c2ecf20Sopenharmony_ci		return rc;
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci	jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (tblk->xflag & COMMIT_LAZY)
6838c2ecf20Sopenharmony_ci		tblk->flag |= tblkGC_LAZY;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) &&
6868c2ecf20Sopenharmony_ci	    (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag)
6878c2ecf20Sopenharmony_ci	     || jfs_tlocks_low)) {
6888c2ecf20Sopenharmony_ci		/*
6898c2ecf20Sopenharmony_ci		 * No pageout in progress
6908c2ecf20Sopenharmony_ci		 *
6918c2ecf20Sopenharmony_ci		 * start group commit as its group leader.
6928c2ecf20Sopenharmony_ci		 */
6938c2ecf20Sopenharmony_ci		log->cflag |= logGC_PAGEOUT;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		lmGCwrite(log, 0);
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	if (tblk->xflag & COMMIT_LAZY) {
6998c2ecf20Sopenharmony_ci		/*
7008c2ecf20Sopenharmony_ci		 * Lazy transactions can leave now
7018c2ecf20Sopenharmony_ci		 */
7028c2ecf20Sopenharmony_ci		LOGGC_UNLOCK(log);
7038c2ecf20Sopenharmony_ci		return 0;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* lmGCwrite gives up LOGGC_LOCK, check again */
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (tblk->flag & tblkGC_COMMITTED) {
7098c2ecf20Sopenharmony_ci		if (tblk->flag & tblkGC_ERROR)
7108c2ecf20Sopenharmony_ci			rc = -EIO;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		LOGGC_UNLOCK(log);
7138c2ecf20Sopenharmony_ci		return rc;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	/* upcount transaction waiting for completion
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	log->gcrtc++;
7198c2ecf20Sopenharmony_ci	tblk->flag |= tblkGC_READY;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
7228c2ecf20Sopenharmony_ci		     LOGGC_LOCK(log), LOGGC_UNLOCK(log));
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	/* removed from commit queue */
7258c2ecf20Sopenharmony_ci	if (tblk->flag & tblkGC_ERROR)
7268c2ecf20Sopenharmony_ci		rc = -EIO;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	LOGGC_UNLOCK(log);
7298c2ecf20Sopenharmony_ci	return rc;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci/*
7338c2ecf20Sopenharmony_ci * NAME:	lmGCwrite()
7348c2ecf20Sopenharmony_ci *
7358c2ecf20Sopenharmony_ci * FUNCTION:	group commit write
7368c2ecf20Sopenharmony_ci *	initiate write of log page, building a group of all transactions
7378c2ecf20Sopenharmony_ci *	with commit records on that page.
7388c2ecf20Sopenharmony_ci *
7398c2ecf20Sopenharmony_ci * RETURN:	None
7408c2ecf20Sopenharmony_ci *
7418c2ecf20Sopenharmony_ci * NOTE:
7428c2ecf20Sopenharmony_ci *	LOGGC_LOCK must be held by caller.
7438c2ecf20Sopenharmony_ci *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
7448c2ecf20Sopenharmony_ci */
7458c2ecf20Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_write)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct lbuf *bp;
7488c2ecf20Sopenharmony_ci	struct logpage *lp;
7498c2ecf20Sopenharmony_ci	int gcpn;		/* group commit page number */
7508c2ecf20Sopenharmony_ci	struct tblock *tblk;
7518c2ecf20Sopenharmony_ci	struct tblock *xtblk = NULL;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/*
7548c2ecf20Sopenharmony_ci	 * build the commit group of a log page
7558c2ecf20Sopenharmony_ci	 *
7568c2ecf20Sopenharmony_ci	 * scan commit queue and make a commit group of all
7578c2ecf20Sopenharmony_ci	 * transactions with COMMIT records on the same log page.
7588c2ecf20Sopenharmony_ci	 */
7598c2ecf20Sopenharmony_ci	/* get the head tblk on the commit queue */
7608c2ecf20Sopenharmony_ci	gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	list_for_each_entry(tblk, &log->cqueue, cqueue) {
7638c2ecf20Sopenharmony_ci		if (tblk->pn != gcpn)
7648c2ecf20Sopenharmony_ci			break;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		xtblk = tblk;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		/* state transition: (QUEUE, READY) -> COMMIT */
7698c2ecf20Sopenharmony_ci		tblk->flag |= tblkGC_COMMIT;
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci	tblk = xtblk;		/* last tblk of the page */
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	/*
7748c2ecf20Sopenharmony_ci	 * pageout to commit transactions on the log page.
7758c2ecf20Sopenharmony_ci	 */
7768c2ecf20Sopenharmony_ci	bp = (struct lbuf *) tblk->bp;
7778c2ecf20Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
7788c2ecf20Sopenharmony_ci	/* is page already full ? */
7798c2ecf20Sopenharmony_ci	if (tblk->flag & tblkGC_EOP) {
7808c2ecf20Sopenharmony_ci		/* mark page to free at end of group commit of the page */
7818c2ecf20Sopenharmony_ci		tblk->flag &= ~tblkGC_EOP;
7828c2ecf20Sopenharmony_ci		tblk->flag |= tblkGC_FREE;
7838c2ecf20Sopenharmony_ci		bp->l_ceor = bp->l_eor;
7848c2ecf20Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
7858c2ecf20Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
7868c2ecf20Sopenharmony_ci			 cant_write);
7878c2ecf20Sopenharmony_ci		INCREMENT(lmStat.full_page);
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci	/* page is not yet full */
7908c2ecf20Sopenharmony_ci	else {
7918c2ecf20Sopenharmony_ci		bp->l_ceor = tblk->eor;	/* ? bp->l_ceor = bp->l_eor; */
7928c2ecf20Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
7938c2ecf20Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
7948c2ecf20Sopenharmony_ci		INCREMENT(lmStat.partial_page);
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/*
7998c2ecf20Sopenharmony_ci * NAME:	lmPostGC()
8008c2ecf20Sopenharmony_ci *
8018c2ecf20Sopenharmony_ci * FUNCTION:	group commit post-processing
8028c2ecf20Sopenharmony_ci *	Processes transactions after their commit records have been written
8038c2ecf20Sopenharmony_ci *	to disk, redriving log I/O if necessary.
8048c2ecf20Sopenharmony_ci *
8058c2ecf20Sopenharmony_ci * RETURN:	None
8068c2ecf20Sopenharmony_ci *
8078c2ecf20Sopenharmony_ci * NOTE:
8088c2ecf20Sopenharmony_ci *	This routine is called a interrupt time by lbmIODone
8098c2ecf20Sopenharmony_ci */
8108c2ecf20Sopenharmony_cistatic void lmPostGC(struct lbuf * bp)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	unsigned long flags;
8138c2ecf20Sopenharmony_ci	struct jfs_log *log = bp->l_log;
8148c2ecf20Sopenharmony_ci	struct logpage *lp;
8158c2ecf20Sopenharmony_ci	struct tblock *tblk, *temp;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	//LOGGC_LOCK(log);
8188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&log->gclock, flags);
8198c2ecf20Sopenharmony_ci	/*
8208c2ecf20Sopenharmony_ci	 * current pageout of group commit completed.
8218c2ecf20Sopenharmony_ci	 *
8228c2ecf20Sopenharmony_ci	 * remove/wakeup transactions from commit queue who were
8238c2ecf20Sopenharmony_ci	 * group committed with the current log page
8248c2ecf20Sopenharmony_ci	 */
8258c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
8268c2ecf20Sopenharmony_ci		if (!(tblk->flag & tblkGC_COMMIT))
8278c2ecf20Sopenharmony_ci			break;
8288c2ecf20Sopenharmony_ci		/* if transaction was marked GC_COMMIT then
8298c2ecf20Sopenharmony_ci		 * it has been shipped in the current pageout
8308c2ecf20Sopenharmony_ci		 * and made it to disk - it is committed.
8318c2ecf20Sopenharmony_ci		 */
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci		if (bp->l_flag & lbmERROR)
8348c2ecf20Sopenharmony_ci			tblk->flag |= tblkGC_ERROR;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		/* remove it from the commit queue */
8378c2ecf20Sopenharmony_ci		list_del(&tblk->cqueue);
8388c2ecf20Sopenharmony_ci		tblk->flag &= ~tblkGC_QUEUE;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		if (tblk == log->flush_tblk) {
8418c2ecf20Sopenharmony_ci			/* we can stop flushing the log now */
8428c2ecf20Sopenharmony_ci			clear_bit(log_FLUSH, &log->flag);
8438c2ecf20Sopenharmony_ci			log->flush_tblk = NULL;
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
8478c2ecf20Sopenharmony_ci			 tblk->flag);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci		if (!(tblk->xflag & COMMIT_FORCE))
8508c2ecf20Sopenharmony_ci			/*
8518c2ecf20Sopenharmony_ci			 * Hand tblk over to lazy commit thread
8528c2ecf20Sopenharmony_ci			 */
8538c2ecf20Sopenharmony_ci			txLazyUnlock(tblk);
8548c2ecf20Sopenharmony_ci		else {
8558c2ecf20Sopenharmony_ci			/* state transition: COMMIT -> COMMITTED */
8568c2ecf20Sopenharmony_ci			tblk->flag |= tblkGC_COMMITTED;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci			if (tblk->flag & tblkGC_READY)
8598c2ecf20Sopenharmony_ci				log->gcrtc--;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci			LOGGC_WAKEUP(tblk);
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		/* was page full before pageout ?
8658c2ecf20Sopenharmony_ci		 * (and this is the last tblk bound with the page)
8668c2ecf20Sopenharmony_ci		 */
8678c2ecf20Sopenharmony_ci		if (tblk->flag & tblkGC_FREE)
8688c2ecf20Sopenharmony_ci			lbmFree(bp);
8698c2ecf20Sopenharmony_ci		/* did page become full after pageout ?
8708c2ecf20Sopenharmony_ci		 * (and this is the last tblk bound with the page)
8718c2ecf20Sopenharmony_ci		 */
8728c2ecf20Sopenharmony_ci		else if (tblk->flag & tblkGC_EOP) {
8738c2ecf20Sopenharmony_ci			/* finalize the page */
8748c2ecf20Sopenharmony_ci			lp = (struct logpage *) bp->l_ldata;
8758c2ecf20Sopenharmony_ci			bp->l_ceor = bp->l_eor;
8768c2ecf20Sopenharmony_ci			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
8778c2ecf20Sopenharmony_ci			jfs_info("lmPostGC: calling lbmWrite");
8788c2ecf20Sopenharmony_ci			lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
8798c2ecf20Sopenharmony_ci				 1);
8808c2ecf20Sopenharmony_ci		}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	/* are there any transactions who have entered lnGroupCommit()
8858c2ecf20Sopenharmony_ci	 * (whose COMMITs are after that of the last log page written.
8868c2ecf20Sopenharmony_ci	 * They are waiting for new group commit (above at (SLEEP 1))
8878c2ecf20Sopenharmony_ci	 * or lazy transactions are on a full (queued) log page,
8888c2ecf20Sopenharmony_ci	 * select the latest ready transaction as new group leader and
8898c2ecf20Sopenharmony_ci	 * wake her up to lead her group.
8908c2ecf20Sopenharmony_ci	 */
8918c2ecf20Sopenharmony_ci	if ((!list_empty(&log->cqueue)) &&
8928c2ecf20Sopenharmony_ci	    ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
8938c2ecf20Sopenharmony_ci	     test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
8948c2ecf20Sopenharmony_ci		/*
8958c2ecf20Sopenharmony_ci		 * Call lmGCwrite with new group leader
8968c2ecf20Sopenharmony_ci		 */
8978c2ecf20Sopenharmony_ci		lmGCwrite(log, 1);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* no transaction are ready yet (transactions are only just
9008c2ecf20Sopenharmony_ci	 * queued (GC_QUEUE) and not entered for group commit yet).
9018c2ecf20Sopenharmony_ci	 * the first transaction entering group commit
9028c2ecf20Sopenharmony_ci	 * will elect herself as new group leader.
9038c2ecf20Sopenharmony_ci	 */
9048c2ecf20Sopenharmony_ci	else
9058c2ecf20Sopenharmony_ci		log->cflag &= ~logGC_PAGEOUT;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	//LOGGC_UNLOCK(log);
9088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&log->gclock, flags);
9098c2ecf20Sopenharmony_ci	return;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci/*
9138c2ecf20Sopenharmony_ci * NAME:	lmLogSync()
9148c2ecf20Sopenharmony_ci *
9158c2ecf20Sopenharmony_ci * FUNCTION:	write log SYNCPT record for specified log
9168c2ecf20Sopenharmony_ci *	if new sync address is available
9178c2ecf20Sopenharmony_ci *	(normally the case if sync() is executed by back-ground
9188c2ecf20Sopenharmony_ci *	process).
9198c2ecf20Sopenharmony_ci *	calculate new value of i_nextsync which determines when
9208c2ecf20Sopenharmony_ci *	this code is called again.
9218c2ecf20Sopenharmony_ci *
9228c2ecf20Sopenharmony_ci * PARAMETERS:	log	- log structure
9238c2ecf20Sopenharmony_ci *		hard_sync - 1 to force all metadata to be written
9248c2ecf20Sopenharmony_ci *
9258c2ecf20Sopenharmony_ci * RETURN:	0
9268c2ecf20Sopenharmony_ci *
9278c2ecf20Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit
9288c2ecf20Sopenharmony_ci */
9298c2ecf20Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	int logsize;
9328c2ecf20Sopenharmony_ci	int written;		/* written since last syncpt */
9338c2ecf20Sopenharmony_ci	int free;		/* free space left available */
9348c2ecf20Sopenharmony_ci	int delta;		/* additional delta to write normally */
9358c2ecf20Sopenharmony_ci	int more;		/* additional write granted */
9368c2ecf20Sopenharmony_ci	struct lrd lrd;
9378c2ecf20Sopenharmony_ci	int lsn;
9388c2ecf20Sopenharmony_ci	struct logsyncblk *lp;
9398c2ecf20Sopenharmony_ci	unsigned long flags;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	/* push dirty metapages out to disk */
9428c2ecf20Sopenharmony_ci	if (hard_sync)
9438c2ecf20Sopenharmony_ci		write_special_inodes(log, filemap_fdatawrite);
9448c2ecf20Sopenharmony_ci	else
9458c2ecf20Sopenharmony_ci		write_special_inodes(log, filemap_flush);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/*
9488c2ecf20Sopenharmony_ci	 *	forward syncpt
9498c2ecf20Sopenharmony_ci	 */
9508c2ecf20Sopenharmony_ci	/* if last sync is same as last syncpt,
9518c2ecf20Sopenharmony_ci	 * invoke sync point forward processing to update sync.
9528c2ecf20Sopenharmony_ci	 */
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (log->sync == log->syncpt) {
9558c2ecf20Sopenharmony_ci		LOGSYNC_LOCK(log, flags);
9568c2ecf20Sopenharmony_ci		if (list_empty(&log->synclist))
9578c2ecf20Sopenharmony_ci			log->sync = log->lsn;
9588c2ecf20Sopenharmony_ci		else {
9598c2ecf20Sopenharmony_ci			lp = list_entry(log->synclist.next,
9608c2ecf20Sopenharmony_ci					struct logsyncblk, synclist);
9618c2ecf20Sopenharmony_ci			log->sync = lp->lsn;
9628c2ecf20Sopenharmony_ci		}
9638c2ecf20Sopenharmony_ci		LOGSYNC_UNLOCK(log, flags);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/* if sync is different from last syncpt,
9688c2ecf20Sopenharmony_ci	 * write a SYNCPT record with syncpt = sync.
9698c2ecf20Sopenharmony_ci	 * reset syncpt = sync
9708c2ecf20Sopenharmony_ci	 */
9718c2ecf20Sopenharmony_ci	if (log->sync != log->syncpt) {
9728c2ecf20Sopenharmony_ci		lrd.logtid = 0;
9738c2ecf20Sopenharmony_ci		lrd.backchain = 0;
9748c2ecf20Sopenharmony_ci		lrd.type = cpu_to_le16(LOG_SYNCPT);
9758c2ecf20Sopenharmony_ci		lrd.length = 0;
9768c2ecf20Sopenharmony_ci		lrd.log.syncpt.sync = cpu_to_le32(log->sync);
9778c2ecf20Sopenharmony_ci		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		log->syncpt = log->sync;
9808c2ecf20Sopenharmony_ci	} else
9818c2ecf20Sopenharmony_ci		lsn = log->lsn;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	/*
9848c2ecf20Sopenharmony_ci	 *	setup next syncpt trigger (SWAG)
9858c2ecf20Sopenharmony_ci	 */
9868c2ecf20Sopenharmony_ci	logsize = log->logsize;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	logdiff(written, lsn, log);
9898c2ecf20Sopenharmony_ci	free = logsize - written;
9908c2ecf20Sopenharmony_ci	delta = LOGSYNC_DELTA(logsize);
9918c2ecf20Sopenharmony_ci	more = min(free / 2, delta);
9928c2ecf20Sopenharmony_ci	if (more < 2 * LOGPSIZE) {
9938c2ecf20Sopenharmony_ci		jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
9948c2ecf20Sopenharmony_ci		/*
9958c2ecf20Sopenharmony_ci		 *	log wrapping
9968c2ecf20Sopenharmony_ci		 *
9978c2ecf20Sopenharmony_ci		 * option 1 - panic ? No.!
9988c2ecf20Sopenharmony_ci		 * option 2 - shutdown file systems
9998c2ecf20Sopenharmony_ci		 *	      associated with log ?
10008c2ecf20Sopenharmony_ci		 * option 3 - extend log ?
10018c2ecf20Sopenharmony_ci		 * option 4 - second chance
10028c2ecf20Sopenharmony_ci		 *
10038c2ecf20Sopenharmony_ci		 * mark log wrapped, and continue.
10048c2ecf20Sopenharmony_ci		 * when all active transactions are completed,
10058c2ecf20Sopenharmony_ci		 * mark log valid for recovery.
10068c2ecf20Sopenharmony_ci		 * if crashed during invalid state, log state
10078c2ecf20Sopenharmony_ci		 * implies invalid log, forcing fsck().
10088c2ecf20Sopenharmony_ci		 */
10098c2ecf20Sopenharmony_ci		/* mark log state log wrap in log superblock */
10108c2ecf20Sopenharmony_ci		/* log->state = LOGWRAP; */
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci		/* reset sync point computation */
10138c2ecf20Sopenharmony_ci		log->syncpt = log->sync = lsn;
10148c2ecf20Sopenharmony_ci		log->nextsync = delta;
10158c2ecf20Sopenharmony_ci	} else
10168c2ecf20Sopenharmony_ci		/* next syncpt trigger = written + more */
10178c2ecf20Sopenharmony_ci		log->nextsync = written + more;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	/* if number of bytes written from last sync point is more
10208c2ecf20Sopenharmony_ci	 * than 1/4 of the log size, stop new transactions from
10218c2ecf20Sopenharmony_ci	 * starting until all current transactions are completed
10228c2ecf20Sopenharmony_ci	 * by setting syncbarrier flag.
10238c2ecf20Sopenharmony_ci	 */
10248c2ecf20Sopenharmony_ci	if (!test_bit(log_SYNCBARRIER, &log->flag) &&
10258c2ecf20Sopenharmony_ci	    (written > LOGSYNC_BARRIER(logsize)) && log->active) {
10268c2ecf20Sopenharmony_ci		set_bit(log_SYNCBARRIER, &log->flag);
10278c2ecf20Sopenharmony_ci		jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn,
10288c2ecf20Sopenharmony_ci			 log->syncpt);
10298c2ecf20Sopenharmony_ci		/*
10308c2ecf20Sopenharmony_ci		 * We may have to initiate group commit
10318c2ecf20Sopenharmony_ci		 */
10328c2ecf20Sopenharmony_ci		jfs_flush_journal(log, 0);
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return lsn;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci/*
10398c2ecf20Sopenharmony_ci * NAME:	jfs_syncpt
10408c2ecf20Sopenharmony_ci *
10418c2ecf20Sopenharmony_ci * FUNCTION:	write log SYNCPT record for specified log
10428c2ecf20Sopenharmony_ci *
10438c2ecf20Sopenharmony_ci * PARAMETERS:	log	  - log structure
10448c2ecf20Sopenharmony_ci *		hard_sync - set to 1 to force metadata to be written
10458c2ecf20Sopenharmony_ci */
10468c2ecf20Sopenharmony_civoid jfs_syncpt(struct jfs_log *log, int hard_sync)
10478c2ecf20Sopenharmony_ci{	LOG_LOCK(log);
10488c2ecf20Sopenharmony_ci	if (!test_bit(log_QUIESCE, &log->flag))
10498c2ecf20Sopenharmony_ci		lmLogSync(log, hard_sync);
10508c2ecf20Sopenharmony_ci	LOG_UNLOCK(log);
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci/*
10548c2ecf20Sopenharmony_ci * NAME:	lmLogOpen()
10558c2ecf20Sopenharmony_ci *
10568c2ecf20Sopenharmony_ci * FUNCTION:	open the log on first open;
10578c2ecf20Sopenharmony_ci *	insert filesystem in the active list of the log.
10588c2ecf20Sopenharmony_ci *
10598c2ecf20Sopenharmony_ci * PARAMETER:	ipmnt	- file system mount inode
10608c2ecf20Sopenharmony_ci *		iplog	- log inode (out)
10618c2ecf20Sopenharmony_ci *
10628c2ecf20Sopenharmony_ci * RETURN:
10638c2ecf20Sopenharmony_ci *
10648c2ecf20Sopenharmony_ci * serialization:
10658c2ecf20Sopenharmony_ci */
10668c2ecf20Sopenharmony_ciint lmLogOpen(struct super_block *sb)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	int rc;
10698c2ecf20Sopenharmony_ci	struct block_device *bdev;
10708c2ecf20Sopenharmony_ci	struct jfs_log *log;
10718c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	if (sbi->flag & JFS_NOINTEGRITY)
10748c2ecf20Sopenharmony_ci		return open_dummy_log(sb);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (sbi->mntflag & JFS_INLINELOG)
10778c2ecf20Sopenharmony_ci		return open_inline_log(sb);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
10808c2ecf20Sopenharmony_ci	list_for_each_entry(log, &jfs_external_logs, journal_list) {
10818c2ecf20Sopenharmony_ci		if (log->bdev->bd_dev == sbi->logdev) {
10828c2ecf20Sopenharmony_ci			if (!uuid_equal(&log->uuid, &sbi->loguuid)) {
10838c2ecf20Sopenharmony_ci				jfs_warn("wrong uuid on JFS journal");
10848c2ecf20Sopenharmony_ci				mutex_unlock(&jfs_log_mutex);
10858c2ecf20Sopenharmony_ci				return -EINVAL;
10868c2ecf20Sopenharmony_ci			}
10878c2ecf20Sopenharmony_ci			/*
10888c2ecf20Sopenharmony_ci			 * add file system to log active file system list
10898c2ecf20Sopenharmony_ci			 */
10908c2ecf20Sopenharmony_ci			if ((rc = lmLogFileSystem(log, sbi, 1))) {
10918c2ecf20Sopenharmony_ci				mutex_unlock(&jfs_log_mutex);
10928c2ecf20Sopenharmony_ci				return rc;
10938c2ecf20Sopenharmony_ci			}
10948c2ecf20Sopenharmony_ci			goto journal_found;
10958c2ecf20Sopenharmony_ci		}
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
10998c2ecf20Sopenharmony_ci		mutex_unlock(&jfs_log_mutex);
11008c2ecf20Sopenharmony_ci		return -ENOMEM;
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&log->sb_list);
11038c2ecf20Sopenharmony_ci	init_waitqueue_head(&log->syncwait);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/*
11068c2ecf20Sopenharmony_ci	 *	external log as separate logical volume
11078c2ecf20Sopenharmony_ci	 *
11088c2ecf20Sopenharmony_ci	 * file systems to log may have n-to-1 relationship;
11098c2ecf20Sopenharmony_ci	 */
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
11128c2ecf20Sopenharmony_ci				 log);
11138c2ecf20Sopenharmony_ci	if (IS_ERR(bdev)) {
11148c2ecf20Sopenharmony_ci		rc = PTR_ERR(bdev);
11158c2ecf20Sopenharmony_ci		goto free;
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	log->bdev = bdev;
11198c2ecf20Sopenharmony_ci	uuid_copy(&log->uuid, &sbi->loguuid);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/*
11228c2ecf20Sopenharmony_ci	 * initialize log:
11238c2ecf20Sopenharmony_ci	 */
11248c2ecf20Sopenharmony_ci	if ((rc = lmLogInit(log)))
11258c2ecf20Sopenharmony_ci		goto close;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	list_add(&log->journal_list, &jfs_external_logs);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/*
11308c2ecf20Sopenharmony_ci	 * add file system to log active file system list
11318c2ecf20Sopenharmony_ci	 */
11328c2ecf20Sopenharmony_ci	if ((rc = lmLogFileSystem(log, sbi, 1)))
11338c2ecf20Sopenharmony_ci		goto shutdown;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_cijournal_found:
11368c2ecf20Sopenharmony_ci	LOG_LOCK(log);
11378c2ecf20Sopenharmony_ci	list_add(&sbi->log_list, &log->sb_list);
11388c2ecf20Sopenharmony_ci	sbi->log = log;
11398c2ecf20Sopenharmony_ci	LOG_UNLOCK(log);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
11428c2ecf20Sopenharmony_ci	return 0;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/*
11458c2ecf20Sopenharmony_ci	 *	unwind on error
11468c2ecf20Sopenharmony_ci	 */
11478c2ecf20Sopenharmony_ci      shutdown:		/* unwind lbmLogInit() */
11488c2ecf20Sopenharmony_ci	list_del(&log->journal_list);
11498c2ecf20Sopenharmony_ci	lbmLogShutdown(log);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci      close:		/* close external log device */
11528c2ecf20Sopenharmony_ci	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci      free:		/* free log descriptor */
11558c2ecf20Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
11568c2ecf20Sopenharmony_ci	kfree(log);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	jfs_warn("lmLogOpen: exit(%d)", rc);
11598c2ecf20Sopenharmony_ci	return rc;
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_cistatic int open_inline_log(struct super_block *sb)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci	struct jfs_log *log;
11658c2ecf20Sopenharmony_ci	int rc;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL)))
11688c2ecf20Sopenharmony_ci		return -ENOMEM;
11698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&log->sb_list);
11708c2ecf20Sopenharmony_ci	init_waitqueue_head(&log->syncwait);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	set_bit(log_INLINELOG, &log->flag);
11738c2ecf20Sopenharmony_ci	log->bdev = sb->s_bdev;
11748c2ecf20Sopenharmony_ci	log->base = addressPXD(&JFS_SBI(sb)->logpxd);
11758c2ecf20Sopenharmony_ci	log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
11768c2ecf20Sopenharmony_ci	    (L2LOGPSIZE - sb->s_blocksize_bits);
11778c2ecf20Sopenharmony_ci	log->l2bsize = sb->s_blocksize_bits;
11788c2ecf20Sopenharmony_ci	ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	/*
11818c2ecf20Sopenharmony_ci	 * initialize log.
11828c2ecf20Sopenharmony_ci	 */
11838c2ecf20Sopenharmony_ci	if ((rc = lmLogInit(log))) {
11848c2ecf20Sopenharmony_ci		kfree(log);
11858c2ecf20Sopenharmony_ci		jfs_warn("lmLogOpen: exit(%d)", rc);
11868c2ecf20Sopenharmony_ci		return rc;
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	list_add(&JFS_SBI(sb)->log_list, &log->sb_list);
11908c2ecf20Sopenharmony_ci	JFS_SBI(sb)->log = log;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	return rc;
11938c2ecf20Sopenharmony_ci}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_cistatic int open_dummy_log(struct super_block *sb)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	int rc;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
12008c2ecf20Sopenharmony_ci	if (!dummy_log) {
12018c2ecf20Sopenharmony_ci		dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL);
12028c2ecf20Sopenharmony_ci		if (!dummy_log) {
12038c2ecf20Sopenharmony_ci			mutex_unlock(&jfs_log_mutex);
12048c2ecf20Sopenharmony_ci			return -ENOMEM;
12058c2ecf20Sopenharmony_ci		}
12068c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dummy_log->sb_list);
12078c2ecf20Sopenharmony_ci		init_waitqueue_head(&dummy_log->syncwait);
12088c2ecf20Sopenharmony_ci		dummy_log->no_integrity = 1;
12098c2ecf20Sopenharmony_ci		/* Make up some stuff */
12108c2ecf20Sopenharmony_ci		dummy_log->base = 0;
12118c2ecf20Sopenharmony_ci		dummy_log->size = 1024;
12128c2ecf20Sopenharmony_ci		rc = lmLogInit(dummy_log);
12138c2ecf20Sopenharmony_ci		if (rc) {
12148c2ecf20Sopenharmony_ci			kfree(dummy_log);
12158c2ecf20Sopenharmony_ci			dummy_log = NULL;
12168c2ecf20Sopenharmony_ci			mutex_unlock(&jfs_log_mutex);
12178c2ecf20Sopenharmony_ci			return rc;
12188c2ecf20Sopenharmony_ci		}
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	LOG_LOCK(dummy_log);
12228c2ecf20Sopenharmony_ci	list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
12238c2ecf20Sopenharmony_ci	JFS_SBI(sb)->log = dummy_log;
12248c2ecf20Sopenharmony_ci	LOG_UNLOCK(dummy_log);
12258c2ecf20Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	return 0;
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci/*
12318c2ecf20Sopenharmony_ci * NAME:	lmLogInit()
12328c2ecf20Sopenharmony_ci *
12338c2ecf20Sopenharmony_ci * FUNCTION:	log initialization at first log open.
12348c2ecf20Sopenharmony_ci *
12358c2ecf20Sopenharmony_ci *	logredo() (or logformat()) should have been run previously.
12368c2ecf20Sopenharmony_ci *	initialize the log from log superblock.
12378c2ecf20Sopenharmony_ci *	set the log state in the superblock to LOGMOUNT and
12388c2ecf20Sopenharmony_ci *	write SYNCPT log record.
12398c2ecf20Sopenharmony_ci *
12408c2ecf20Sopenharmony_ci * PARAMETER:	log	- log structure
12418c2ecf20Sopenharmony_ci *
12428c2ecf20Sopenharmony_ci * RETURN:	0	- if ok
12438c2ecf20Sopenharmony_ci *		-EINVAL	- bad log magic number or superblock dirty
12448c2ecf20Sopenharmony_ci *		error returned from logwait()
12458c2ecf20Sopenharmony_ci *
12468c2ecf20Sopenharmony_ci * serialization: single first open thread
12478c2ecf20Sopenharmony_ci */
12488c2ecf20Sopenharmony_ciint lmLogInit(struct jfs_log * log)
12498c2ecf20Sopenharmony_ci{
12508c2ecf20Sopenharmony_ci	int rc = 0;
12518c2ecf20Sopenharmony_ci	struct lrd lrd;
12528c2ecf20Sopenharmony_ci	struct logsuper *logsuper;
12538c2ecf20Sopenharmony_ci	struct lbuf *bpsuper;
12548c2ecf20Sopenharmony_ci	struct lbuf *bp;
12558c2ecf20Sopenharmony_ci	struct logpage *lp;
12568c2ecf20Sopenharmony_ci	int lsn = 0;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	jfs_info("lmLogInit: log:0x%p", log);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	/* initialize the group commit serialization lock */
12618c2ecf20Sopenharmony_ci	LOGGC_LOCK_INIT(log);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	/* allocate/initialize the log write serialization lock */
12648c2ecf20Sopenharmony_ci	LOG_LOCK_INIT(log);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	LOGSYNC_LOCK_INIT(log);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&log->synclist);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&log->cqueue);
12718c2ecf20Sopenharmony_ci	log->flush_tblk = NULL;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	log->count = 0;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	/*
12768c2ecf20Sopenharmony_ci	 * initialize log i/o
12778c2ecf20Sopenharmony_ci	 */
12788c2ecf20Sopenharmony_ci	if ((rc = lbmLogInit(log)))
12798c2ecf20Sopenharmony_ci		return rc;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	if (!test_bit(log_INLINELOG, &log->flag))
12828c2ecf20Sopenharmony_ci		log->l2bsize = L2LOGPSIZE;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	/* check for disabled journaling to disk */
12858c2ecf20Sopenharmony_ci	if (log->no_integrity) {
12868c2ecf20Sopenharmony_ci		/*
12878c2ecf20Sopenharmony_ci		 * Journal pages will still be filled.  When the time comes
12888c2ecf20Sopenharmony_ci		 * to actually do the I/O, the write is not done, and the
12898c2ecf20Sopenharmony_ci		 * endio routine is called directly.
12908c2ecf20Sopenharmony_ci		 */
12918c2ecf20Sopenharmony_ci		bp = lbmAllocate(log , 0);
12928c2ecf20Sopenharmony_ci		log->bp = bp;
12938c2ecf20Sopenharmony_ci		bp->l_pn = bp->l_eor = 0;
12948c2ecf20Sopenharmony_ci	} else {
12958c2ecf20Sopenharmony_ci		/*
12968c2ecf20Sopenharmony_ci		 * validate log superblock
12978c2ecf20Sopenharmony_ci		 */
12988c2ecf20Sopenharmony_ci		if ((rc = lbmRead(log, 1, &bpsuper)))
12998c2ecf20Sopenharmony_ci			goto errout10;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci		logsuper = (struct logsuper *) bpsuper->l_ldata;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
13048c2ecf20Sopenharmony_ci			jfs_warn("*** Log Format Error ! ***");
13058c2ecf20Sopenharmony_ci			rc = -EINVAL;
13068c2ecf20Sopenharmony_ci			goto errout20;
13078c2ecf20Sopenharmony_ci		}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci		/* logredo() should have been run successfully. */
13108c2ecf20Sopenharmony_ci		if (logsuper->state != cpu_to_le32(LOGREDONE)) {
13118c2ecf20Sopenharmony_ci			jfs_warn("*** Log Is Dirty ! ***");
13128c2ecf20Sopenharmony_ci			rc = -EINVAL;
13138c2ecf20Sopenharmony_ci			goto errout20;
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		/* initialize log from log superblock */
13178c2ecf20Sopenharmony_ci		if (test_bit(log_INLINELOG,&log->flag)) {
13188c2ecf20Sopenharmony_ci			if (log->size != le32_to_cpu(logsuper->size)) {
13198c2ecf20Sopenharmony_ci				rc = -EINVAL;
13208c2ecf20Sopenharmony_ci				goto errout20;
13218c2ecf20Sopenharmony_ci			}
13228c2ecf20Sopenharmony_ci			jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x",
13238c2ecf20Sopenharmony_ci				 log, (unsigned long long)log->base, log->size);
13248c2ecf20Sopenharmony_ci		} else {
13258c2ecf20Sopenharmony_ci			if (!uuid_equal(&logsuper->uuid, &log->uuid)) {
13268c2ecf20Sopenharmony_ci				jfs_warn("wrong uuid on JFS log device");
13278c2ecf20Sopenharmony_ci				rc = -EINVAL;
13288c2ecf20Sopenharmony_ci				goto errout20;
13298c2ecf20Sopenharmony_ci			}
13308c2ecf20Sopenharmony_ci			log->size = le32_to_cpu(logsuper->size);
13318c2ecf20Sopenharmony_ci			log->l2bsize = le32_to_cpu(logsuper->l2bsize);
13328c2ecf20Sopenharmony_ci			jfs_info("lmLogInit: external log:0x%p base:0x%Lx size:0x%x",
13338c2ecf20Sopenharmony_ci				 log, (unsigned long long)log->base, log->size);
13348c2ecf20Sopenharmony_ci		}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci		log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
13378c2ecf20Sopenharmony_ci		log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci		/*
13408c2ecf20Sopenharmony_ci		 * initialize for log append write mode
13418c2ecf20Sopenharmony_ci		 */
13428c2ecf20Sopenharmony_ci		/* establish current/end-of-log page/buffer */
13438c2ecf20Sopenharmony_ci		if ((rc = lbmRead(log, log->page, &bp)))
13448c2ecf20Sopenharmony_ci			goto errout20;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		jfs_info("lmLogInit: lsn:0x%x page:%d eor:%d:%d",
13498c2ecf20Sopenharmony_ci			 le32_to_cpu(logsuper->end), log->page, log->eor,
13508c2ecf20Sopenharmony_ci			 le16_to_cpu(lp->h.eor));
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci		log->bp = bp;
13538c2ecf20Sopenharmony_ci		bp->l_pn = log->page;
13548c2ecf20Sopenharmony_ci		bp->l_eor = log->eor;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci		/* if current page is full, move on to next page */
13578c2ecf20Sopenharmony_ci		if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
13588c2ecf20Sopenharmony_ci			lmNextPage(log);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci		/*
13618c2ecf20Sopenharmony_ci		 * initialize log syncpoint
13628c2ecf20Sopenharmony_ci		 */
13638c2ecf20Sopenharmony_ci		/*
13648c2ecf20Sopenharmony_ci		 * write the first SYNCPT record with syncpoint = 0
13658c2ecf20Sopenharmony_ci		 * (i.e., log redo up to HERE !);
13668c2ecf20Sopenharmony_ci		 * remove current page from lbm write queue at end of pageout
13678c2ecf20Sopenharmony_ci		 * (to write log superblock update), but do not release to
13688c2ecf20Sopenharmony_ci		 * freelist;
13698c2ecf20Sopenharmony_ci		 */
13708c2ecf20Sopenharmony_ci		lrd.logtid = 0;
13718c2ecf20Sopenharmony_ci		lrd.backchain = 0;
13728c2ecf20Sopenharmony_ci		lrd.type = cpu_to_le16(LOG_SYNCPT);
13738c2ecf20Sopenharmony_ci		lrd.length = 0;
13748c2ecf20Sopenharmony_ci		lrd.log.syncpt.sync = 0;
13758c2ecf20Sopenharmony_ci		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
13768c2ecf20Sopenharmony_ci		bp = log->bp;
13778c2ecf20Sopenharmony_ci		bp->l_ceor = bp->l_eor;
13788c2ecf20Sopenharmony_ci		lp = (struct logpage *) bp->l_ldata;
13798c2ecf20Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
13808c2ecf20Sopenharmony_ci		lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0);
13818c2ecf20Sopenharmony_ci		if ((rc = lbmIOWait(bp, 0)))
13828c2ecf20Sopenharmony_ci			goto errout30;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci		/*
13858c2ecf20Sopenharmony_ci		 * update/write superblock
13868c2ecf20Sopenharmony_ci		 */
13878c2ecf20Sopenharmony_ci		logsuper->state = cpu_to_le32(LOGMOUNT);
13888c2ecf20Sopenharmony_ci		log->serial = le32_to_cpu(logsuper->serial) + 1;
13898c2ecf20Sopenharmony_ci		logsuper->serial = cpu_to_le32(log->serial);
13908c2ecf20Sopenharmony_ci		lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
13918c2ecf20Sopenharmony_ci		if ((rc = lbmIOWait(bpsuper, lbmFREE)))
13928c2ecf20Sopenharmony_ci			goto errout30;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	/* initialize logsync parameters */
13968c2ecf20Sopenharmony_ci	log->logsize = (log->size - 2) << L2LOGPSIZE;
13978c2ecf20Sopenharmony_ci	log->lsn = lsn;
13988c2ecf20Sopenharmony_ci	log->syncpt = lsn;
13998c2ecf20Sopenharmony_ci	log->sync = log->syncpt;
14008c2ecf20Sopenharmony_ci	log->nextsync = LOGSYNC_DELTA(log->logsize);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	jfs_info("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x",
14038c2ecf20Sopenharmony_ci		 log->lsn, log->syncpt, log->sync);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	/*
14068c2ecf20Sopenharmony_ci	 * initialize for lazy/group commit
14078c2ecf20Sopenharmony_ci	 */
14088c2ecf20Sopenharmony_ci	log->clsn = lsn;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	return 0;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/*
14138c2ecf20Sopenharmony_ci	 *	unwind on error
14148c2ecf20Sopenharmony_ci	 */
14158c2ecf20Sopenharmony_ci      errout30:		/* release log page */
14168c2ecf20Sopenharmony_ci	log->wqueue = NULL;
14178c2ecf20Sopenharmony_ci	bp->l_wqnext = NULL;
14188c2ecf20Sopenharmony_ci	lbmFree(bp);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci      errout20:		/* release log superblock */
14218c2ecf20Sopenharmony_ci	lbmFree(bpsuper);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci      errout10:		/* unwind lbmLogInit() */
14248c2ecf20Sopenharmony_ci	lbmLogShutdown(log);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	jfs_warn("lmLogInit: exit(%d)", rc);
14278c2ecf20Sopenharmony_ci	return rc;
14288c2ecf20Sopenharmony_ci}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci/*
14328c2ecf20Sopenharmony_ci * NAME:	lmLogClose()
14338c2ecf20Sopenharmony_ci *
14348c2ecf20Sopenharmony_ci * FUNCTION:	remove file system <ipmnt> from active list of log <iplog>
14358c2ecf20Sopenharmony_ci *		and close it on last close.
14368c2ecf20Sopenharmony_ci *
14378c2ecf20Sopenharmony_ci * PARAMETER:	sb	- superblock
14388c2ecf20Sopenharmony_ci *
14398c2ecf20Sopenharmony_ci * RETURN:	errors from subroutines
14408c2ecf20Sopenharmony_ci *
14418c2ecf20Sopenharmony_ci * serialization:
14428c2ecf20Sopenharmony_ci */
14438c2ecf20Sopenharmony_ciint lmLogClose(struct super_block *sb)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
14468c2ecf20Sopenharmony_ci	struct jfs_log *log = sbi->log;
14478c2ecf20Sopenharmony_ci	struct block_device *bdev;
14488c2ecf20Sopenharmony_ci	int rc = 0;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	jfs_info("lmLogClose: log:0x%p", log);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	mutex_lock(&jfs_log_mutex);
14538c2ecf20Sopenharmony_ci	LOG_LOCK(log);
14548c2ecf20Sopenharmony_ci	list_del(&sbi->log_list);
14558c2ecf20Sopenharmony_ci	LOG_UNLOCK(log);
14568c2ecf20Sopenharmony_ci	sbi->log = NULL;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	/*
14598c2ecf20Sopenharmony_ci	 * We need to make sure all of the "written" metapages
14608c2ecf20Sopenharmony_ci	 * actually make it to disk
14618c2ecf20Sopenharmony_ci	 */
14628c2ecf20Sopenharmony_ci	sync_blockdev(sb->s_bdev);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (test_bit(log_INLINELOG, &log->flag)) {
14658c2ecf20Sopenharmony_ci		/*
14668c2ecf20Sopenharmony_ci		 *	in-line log in host file system
14678c2ecf20Sopenharmony_ci		 */
14688c2ecf20Sopenharmony_ci		rc = lmLogShutdown(log);
14698c2ecf20Sopenharmony_ci		kfree(log);
14708c2ecf20Sopenharmony_ci		goto out;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (!log->no_integrity)
14748c2ecf20Sopenharmony_ci		lmLogFileSystem(log, sbi, 0);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	if (!list_empty(&log->sb_list))
14778c2ecf20Sopenharmony_ci		goto out;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	/*
14808c2ecf20Sopenharmony_ci	 * TODO: ensure that the dummy_log is in a state to allow
14818c2ecf20Sopenharmony_ci	 * lbmLogShutdown to deallocate all the buffers and call
14828c2ecf20Sopenharmony_ci	 * kfree against dummy_log.  For now, leave dummy_log & its
14838c2ecf20Sopenharmony_ci	 * buffers in memory, and resuse if another no-integrity mount
14848c2ecf20Sopenharmony_ci	 * is requested.
14858c2ecf20Sopenharmony_ci	 */
14868c2ecf20Sopenharmony_ci	if (log->no_integrity)
14878c2ecf20Sopenharmony_ci		goto out;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	/*
14908c2ecf20Sopenharmony_ci	 *	external log as separate logical volume
14918c2ecf20Sopenharmony_ci	 */
14928c2ecf20Sopenharmony_ci	list_del(&log->journal_list);
14938c2ecf20Sopenharmony_ci	bdev = log->bdev;
14948c2ecf20Sopenharmony_ci	rc = lmLogShutdown(log);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	kfree(log);
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci      out:
15018c2ecf20Sopenharmony_ci	mutex_unlock(&jfs_log_mutex);
15028c2ecf20Sopenharmony_ci	jfs_info("lmLogClose: exit(%d)", rc);
15038c2ecf20Sopenharmony_ci	return rc;
15048c2ecf20Sopenharmony_ci}
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci/*
15088c2ecf20Sopenharmony_ci * NAME:	jfs_flush_journal()
15098c2ecf20Sopenharmony_ci *
15108c2ecf20Sopenharmony_ci * FUNCTION:	initiate write of any outstanding transactions to the journal
15118c2ecf20Sopenharmony_ci *		and optionally wait until they are all written to disk
15128c2ecf20Sopenharmony_ci *
15138c2ecf20Sopenharmony_ci *		wait == 0  flush until latest txn is committed, don't wait
15148c2ecf20Sopenharmony_ci *		wait == 1  flush until latest txn is committed, wait
15158c2ecf20Sopenharmony_ci *		wait > 1   flush until all txn's are complete, wait
15168c2ecf20Sopenharmony_ci */
15178c2ecf20Sopenharmony_civoid jfs_flush_journal(struct jfs_log *log, int wait)
15188c2ecf20Sopenharmony_ci{
15198c2ecf20Sopenharmony_ci	int i;
15208c2ecf20Sopenharmony_ci	struct tblock *target = NULL;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* jfs_write_inode may call us during read-only mount */
15238c2ecf20Sopenharmony_ci	if (!log)
15248c2ecf20Sopenharmony_ci		return;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	LOGGC_LOCK(log);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	if (!list_empty(&log->cqueue)) {
15318c2ecf20Sopenharmony_ci		/*
15328c2ecf20Sopenharmony_ci		 * This ensures that we will keep writing to the journal as long
15338c2ecf20Sopenharmony_ci		 * as there are unwritten commit records
15348c2ecf20Sopenharmony_ci		 */
15358c2ecf20Sopenharmony_ci		target = list_entry(log->cqueue.prev, struct tblock, cqueue);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci		if (test_bit(log_FLUSH, &log->flag)) {
15388c2ecf20Sopenharmony_ci			/*
15398c2ecf20Sopenharmony_ci			 * We're already flushing.
15408c2ecf20Sopenharmony_ci			 * if flush_tblk is NULL, we are flushing everything,
15418c2ecf20Sopenharmony_ci			 * so leave it that way.  Otherwise, update it to the
15428c2ecf20Sopenharmony_ci			 * latest transaction
15438c2ecf20Sopenharmony_ci			 */
15448c2ecf20Sopenharmony_ci			if (log->flush_tblk)
15458c2ecf20Sopenharmony_ci				log->flush_tblk = target;
15468c2ecf20Sopenharmony_ci		} else {
15478c2ecf20Sopenharmony_ci			/* Only flush until latest transaction is committed */
15488c2ecf20Sopenharmony_ci			log->flush_tblk = target;
15498c2ecf20Sopenharmony_ci			set_bit(log_FLUSH, &log->flag);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci			/*
15528c2ecf20Sopenharmony_ci			 * Initiate I/O on outstanding transactions
15538c2ecf20Sopenharmony_ci			 */
15548c2ecf20Sopenharmony_ci			if (!(log->cflag & logGC_PAGEOUT)) {
15558c2ecf20Sopenharmony_ci				log->cflag |= logGC_PAGEOUT;
15568c2ecf20Sopenharmony_ci				lmGCwrite(log, 0);
15578c2ecf20Sopenharmony_ci			}
15588c2ecf20Sopenharmony_ci		}
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci	if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
15618c2ecf20Sopenharmony_ci		/* Flush until all activity complete */
15628c2ecf20Sopenharmony_ci		set_bit(log_FLUSH, &log->flag);
15638c2ecf20Sopenharmony_ci		log->flush_tblk = NULL;
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
15678c2ecf20Sopenharmony_ci		DECLARE_WAITQUEUE(__wait, current);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci		add_wait_queue(&target->gcwait, &__wait);
15708c2ecf20Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
15718c2ecf20Sopenharmony_ci		LOGGC_UNLOCK(log);
15728c2ecf20Sopenharmony_ci		schedule();
15738c2ecf20Sopenharmony_ci		LOGGC_LOCK(log);
15748c2ecf20Sopenharmony_ci		remove_wait_queue(&target->gcwait, &__wait);
15758c2ecf20Sopenharmony_ci	}
15768c2ecf20Sopenharmony_ci	LOGGC_UNLOCK(log);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (wait < 2)
15798c2ecf20Sopenharmony_ci		return;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	write_special_inodes(log, filemap_fdatawrite);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	/*
15848c2ecf20Sopenharmony_ci	 * If there was recent activity, we may need to wait
15858c2ecf20Sopenharmony_ci	 * for the lazycommit thread to catch up
15868c2ecf20Sopenharmony_ci	 */
15878c2ecf20Sopenharmony_ci	if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
15888c2ecf20Sopenharmony_ci		for (i = 0; i < 200; i++) {	/* Too much? */
15898c2ecf20Sopenharmony_ci			msleep(250);
15908c2ecf20Sopenharmony_ci			write_special_inodes(log, filemap_fdatawrite);
15918c2ecf20Sopenharmony_ci			if (list_empty(&log->cqueue) &&
15928c2ecf20Sopenharmony_ci			    list_empty(&log->synclist))
15938c2ecf20Sopenharmony_ci				break;
15948c2ecf20Sopenharmony_ci		}
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci	assert(list_empty(&log->cqueue));
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci#ifdef CONFIG_JFS_DEBUG
15998c2ecf20Sopenharmony_ci	if (!list_empty(&log->synclist)) {
16008c2ecf20Sopenharmony_ci		struct logsyncblk *lp;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci		printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
16038c2ecf20Sopenharmony_ci		list_for_each_entry(lp, &log->synclist, synclist) {
16048c2ecf20Sopenharmony_ci			if (lp->xflag & COMMIT_PAGE) {
16058c2ecf20Sopenharmony_ci				struct metapage *mp = (struct metapage *)lp;
16068c2ecf20Sopenharmony_ci				print_hex_dump(KERN_ERR, "metapage: ",
16078c2ecf20Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16, 4,
16088c2ecf20Sopenharmony_ci					       mp, sizeof(struct metapage), 0);
16098c2ecf20Sopenharmony_ci				print_hex_dump(KERN_ERR, "page: ",
16108c2ecf20Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16,
16118c2ecf20Sopenharmony_ci					       sizeof(long), mp->page,
16128c2ecf20Sopenharmony_ci					       sizeof(struct page), 0);
16138c2ecf20Sopenharmony_ci			} else
16148c2ecf20Sopenharmony_ci				print_hex_dump(KERN_ERR, "tblock:",
16158c2ecf20Sopenharmony_ci					       DUMP_PREFIX_ADDRESS, 16, 4,
16168c2ecf20Sopenharmony_ci					       lp, sizeof(struct tblock), 0);
16178c2ecf20Sopenharmony_ci		}
16188c2ecf20Sopenharmony_ci	}
16198c2ecf20Sopenharmony_ci#else
16208c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&log->synclist));
16218c2ecf20Sopenharmony_ci#endif
16228c2ecf20Sopenharmony_ci	clear_bit(log_FLUSH, &log->flag);
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci/*
16268c2ecf20Sopenharmony_ci * NAME:	lmLogShutdown()
16278c2ecf20Sopenharmony_ci *
16288c2ecf20Sopenharmony_ci * FUNCTION:	log shutdown at last LogClose().
16298c2ecf20Sopenharmony_ci *
16308c2ecf20Sopenharmony_ci *		write log syncpt record.
16318c2ecf20Sopenharmony_ci *		update super block to set redone flag to 0.
16328c2ecf20Sopenharmony_ci *
16338c2ecf20Sopenharmony_ci * PARAMETER:	log	- log inode
16348c2ecf20Sopenharmony_ci *
16358c2ecf20Sopenharmony_ci * RETURN:	0	- success
16368c2ecf20Sopenharmony_ci *
16378c2ecf20Sopenharmony_ci * serialization: single last close thread
16388c2ecf20Sopenharmony_ci */
16398c2ecf20Sopenharmony_ciint lmLogShutdown(struct jfs_log * log)
16408c2ecf20Sopenharmony_ci{
16418c2ecf20Sopenharmony_ci	int rc;
16428c2ecf20Sopenharmony_ci	struct lrd lrd;
16438c2ecf20Sopenharmony_ci	int lsn;
16448c2ecf20Sopenharmony_ci	struct logsuper *logsuper;
16458c2ecf20Sopenharmony_ci	struct lbuf *bpsuper;
16468c2ecf20Sopenharmony_ci	struct lbuf *bp;
16478c2ecf20Sopenharmony_ci	struct logpage *lp;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	jfs_info("lmLogShutdown: log:0x%p", log);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	jfs_flush_journal(log, 2);
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	/*
16548c2ecf20Sopenharmony_ci	 * write the last SYNCPT record with syncpoint = 0
16558c2ecf20Sopenharmony_ci	 * (i.e., log redo up to HERE !)
16568c2ecf20Sopenharmony_ci	 */
16578c2ecf20Sopenharmony_ci	lrd.logtid = 0;
16588c2ecf20Sopenharmony_ci	lrd.backchain = 0;
16598c2ecf20Sopenharmony_ci	lrd.type = cpu_to_le16(LOG_SYNCPT);
16608c2ecf20Sopenharmony_ci	lrd.length = 0;
16618c2ecf20Sopenharmony_ci	lrd.log.syncpt.sync = 0;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
16648c2ecf20Sopenharmony_ci	bp = log->bp;
16658c2ecf20Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
16668c2ecf20Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
16678c2ecf20Sopenharmony_ci	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
16688c2ecf20Sopenharmony_ci	lbmIOWait(log->bp, lbmFREE);
16698c2ecf20Sopenharmony_ci	log->bp = NULL;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	/*
16728c2ecf20Sopenharmony_ci	 * synchronous update log superblock
16738c2ecf20Sopenharmony_ci	 * mark log state as shutdown cleanly
16748c2ecf20Sopenharmony_ci	 * (i.e., Log does not need to be replayed).
16758c2ecf20Sopenharmony_ci	 */
16768c2ecf20Sopenharmony_ci	if ((rc = lbmRead(log, 1, &bpsuper)))
16778c2ecf20Sopenharmony_ci		goto out;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	logsuper = (struct logsuper *) bpsuper->l_ldata;
16808c2ecf20Sopenharmony_ci	logsuper->state = cpu_to_le32(LOGREDONE);
16818c2ecf20Sopenharmony_ci	logsuper->end = cpu_to_le32(lsn);
16828c2ecf20Sopenharmony_ci	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
16838c2ecf20Sopenharmony_ci	rc = lbmIOWait(bpsuper, lbmFREE);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
16868c2ecf20Sopenharmony_ci		 lsn, log->page, log->eor);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci      out:
16898c2ecf20Sopenharmony_ci	/*
16908c2ecf20Sopenharmony_ci	 * shutdown per log i/o
16918c2ecf20Sopenharmony_ci	 */
16928c2ecf20Sopenharmony_ci	lbmLogShutdown(log);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	if (rc) {
16958c2ecf20Sopenharmony_ci		jfs_warn("lmLogShutdown: exit(%d)", rc);
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci	return rc;
16988c2ecf20Sopenharmony_ci}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci/*
17028c2ecf20Sopenharmony_ci * NAME:	lmLogFileSystem()
17038c2ecf20Sopenharmony_ci *
17048c2ecf20Sopenharmony_ci * FUNCTION:	insert (<activate> = true)/remove (<activate> = false)
17058c2ecf20Sopenharmony_ci *	file system into/from log active file system list.
17068c2ecf20Sopenharmony_ci *
17078c2ecf20Sopenharmony_ci * PARAMETE:	log	- pointer to logs inode.
17088c2ecf20Sopenharmony_ci *		fsdev	- kdev_t of filesystem.
17098c2ecf20Sopenharmony_ci *		serial	- pointer to returned log serial number
17108c2ecf20Sopenharmony_ci *		activate - insert/remove device from active list.
17118c2ecf20Sopenharmony_ci *
17128c2ecf20Sopenharmony_ci * RETURN:	0	- success
17138c2ecf20Sopenharmony_ci *		errors returned by vms_iowait().
17148c2ecf20Sopenharmony_ci */
17158c2ecf20Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
17168c2ecf20Sopenharmony_ci			   int activate)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	int rc = 0;
17198c2ecf20Sopenharmony_ci	int i;
17208c2ecf20Sopenharmony_ci	struct logsuper *logsuper;
17218c2ecf20Sopenharmony_ci	struct lbuf *bpsuper;
17228c2ecf20Sopenharmony_ci	uuid_t *uuid = &sbi->uuid;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	/*
17258c2ecf20Sopenharmony_ci	 * insert/remove file system device to log active file system list.
17268c2ecf20Sopenharmony_ci	 */
17278c2ecf20Sopenharmony_ci	if ((rc = lbmRead(log, 1, &bpsuper)))
17288c2ecf20Sopenharmony_ci		return rc;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	logsuper = (struct logsuper *) bpsuper->l_ldata;
17318c2ecf20Sopenharmony_ci	if (activate) {
17328c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_ACTIVE; i++)
17338c2ecf20Sopenharmony_ci			if (uuid_is_null(&logsuper->active[i].uuid)) {
17348c2ecf20Sopenharmony_ci				uuid_copy(&logsuper->active[i].uuid, uuid);
17358c2ecf20Sopenharmony_ci				sbi->aggregate = i;
17368c2ecf20Sopenharmony_ci				break;
17378c2ecf20Sopenharmony_ci			}
17388c2ecf20Sopenharmony_ci		if (i == MAX_ACTIVE) {
17398c2ecf20Sopenharmony_ci			jfs_warn("Too many file systems sharing journal!");
17408c2ecf20Sopenharmony_ci			lbmFree(bpsuper);
17418c2ecf20Sopenharmony_ci			return -EMFILE;	/* Is there a better rc? */
17428c2ecf20Sopenharmony_ci		}
17438c2ecf20Sopenharmony_ci	} else {
17448c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_ACTIVE; i++)
17458c2ecf20Sopenharmony_ci			if (uuid_equal(&logsuper->active[i].uuid, uuid)) {
17468c2ecf20Sopenharmony_ci				uuid_copy(&logsuper->active[i].uuid,
17478c2ecf20Sopenharmony_ci					  &uuid_null);
17488c2ecf20Sopenharmony_ci				break;
17498c2ecf20Sopenharmony_ci			}
17508c2ecf20Sopenharmony_ci		if (i == MAX_ACTIVE) {
17518c2ecf20Sopenharmony_ci			jfs_warn("Somebody stomped on the journal!");
17528c2ecf20Sopenharmony_ci			lbmFree(bpsuper);
17538c2ecf20Sopenharmony_ci			return -EIO;
17548c2ecf20Sopenharmony_ci		}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	/*
17598c2ecf20Sopenharmony_ci	 * synchronous write log superblock:
17608c2ecf20Sopenharmony_ci	 *
17618c2ecf20Sopenharmony_ci	 * write sidestream bypassing write queue:
17628c2ecf20Sopenharmony_ci	 * at file system mount, log super block is updated for
17638c2ecf20Sopenharmony_ci	 * activation of the file system before any log record
17648c2ecf20Sopenharmony_ci	 * (MOUNT record) of the file system, and at file system
17658c2ecf20Sopenharmony_ci	 * unmount, all meta data for the file system has been
17668c2ecf20Sopenharmony_ci	 * flushed before log super block is updated for deactivation
17678c2ecf20Sopenharmony_ci	 * of the file system.
17688c2ecf20Sopenharmony_ci	 */
17698c2ecf20Sopenharmony_ci	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
17708c2ecf20Sopenharmony_ci	rc = lbmIOWait(bpsuper, lbmFREE);
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	return rc;
17738c2ecf20Sopenharmony_ci}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci/*
17768c2ecf20Sopenharmony_ci *		log buffer manager (lbm)
17778c2ecf20Sopenharmony_ci *		------------------------
17788c2ecf20Sopenharmony_ci *
17798c2ecf20Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements.
17808c2ecf20Sopenharmony_ci *
17818c2ecf20Sopenharmony_ci * per log write queue:
17828c2ecf20Sopenharmony_ci * log pageout occurs in serial order by fifo write queue and
17838c2ecf20Sopenharmony_ci * restricting to a single i/o in pregress at any one time.
17848c2ecf20Sopenharmony_ci * a circular singly-linked list
17858c2ecf20Sopenharmony_ci * (log->wrqueue points to the tail, and buffers are linked via
17868c2ecf20Sopenharmony_ci * bp->wrqueue field), and
17878c2ecf20Sopenharmony_ci * maintains log page in pageout ot waiting for pageout in serial pageout.
17888c2ecf20Sopenharmony_ci */
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci/*
17918c2ecf20Sopenharmony_ci *	lbmLogInit()
17928c2ecf20Sopenharmony_ci *
17938c2ecf20Sopenharmony_ci * initialize per log I/O setup at lmLogInit()
17948c2ecf20Sopenharmony_ci */
17958c2ecf20Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log)
17968c2ecf20Sopenharmony_ci{				/* log inode */
17978c2ecf20Sopenharmony_ci	int i;
17988c2ecf20Sopenharmony_ci	struct lbuf *lbuf;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	jfs_info("lbmLogInit: log:0x%p", log);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	/* initialize current buffer cursor */
18038c2ecf20Sopenharmony_ci	log->bp = NULL;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	/* initialize log device write queue */
18068c2ecf20Sopenharmony_ci	log->wqueue = NULL;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	/*
18098c2ecf20Sopenharmony_ci	 * Each log has its own buffer pages allocated to it.  These are
18108c2ecf20Sopenharmony_ci	 * not managed by the page cache.  This ensures that a transaction
18118c2ecf20Sopenharmony_ci	 * writing to the log does not block trying to allocate a page from
18128c2ecf20Sopenharmony_ci	 * the page cache (for the log).  This would be bad, since page
18138c2ecf20Sopenharmony_ci	 * allocation waits on the kswapd thread that may be committing inodes
18148c2ecf20Sopenharmony_ci	 * which would cause log activity.  Was that clear?  I'm trying to
18158c2ecf20Sopenharmony_ci	 * avoid deadlock here.
18168c2ecf20Sopenharmony_ci	 */
18178c2ecf20Sopenharmony_ci	init_waitqueue_head(&log->free_wait);
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	log->lbuf_free = NULL;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	for (i = 0; i < LOGPAGES;) {
18228c2ecf20Sopenharmony_ci		char *buffer;
18238c2ecf20Sopenharmony_ci		uint offset;
18248c2ecf20Sopenharmony_ci		struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO);
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci		if (!page)
18278c2ecf20Sopenharmony_ci			goto error;
18288c2ecf20Sopenharmony_ci		buffer = page_address(page);
18298c2ecf20Sopenharmony_ci		for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
18308c2ecf20Sopenharmony_ci			lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
18318c2ecf20Sopenharmony_ci			if (lbuf == NULL) {
18328c2ecf20Sopenharmony_ci				if (offset == 0)
18338c2ecf20Sopenharmony_ci					__free_page(page);
18348c2ecf20Sopenharmony_ci				goto error;
18358c2ecf20Sopenharmony_ci			}
18368c2ecf20Sopenharmony_ci			if (offset) /* we already have one reference */
18378c2ecf20Sopenharmony_ci				get_page(page);
18388c2ecf20Sopenharmony_ci			lbuf->l_offset = offset;
18398c2ecf20Sopenharmony_ci			lbuf->l_ldata = buffer + offset;
18408c2ecf20Sopenharmony_ci			lbuf->l_page = page;
18418c2ecf20Sopenharmony_ci			lbuf->l_log = log;
18428c2ecf20Sopenharmony_ci			init_waitqueue_head(&lbuf->l_ioevent);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci			lbuf->l_freelist = log->lbuf_free;
18458c2ecf20Sopenharmony_ci			log->lbuf_free = lbuf;
18468c2ecf20Sopenharmony_ci			i++;
18478c2ecf20Sopenharmony_ci		}
18488c2ecf20Sopenharmony_ci	}
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	return (0);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci      error:
18538c2ecf20Sopenharmony_ci	lbmLogShutdown(log);
18548c2ecf20Sopenharmony_ci	return -ENOMEM;
18558c2ecf20Sopenharmony_ci}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci/*
18598c2ecf20Sopenharmony_ci *	lbmLogShutdown()
18608c2ecf20Sopenharmony_ci *
18618c2ecf20Sopenharmony_ci * finalize per log I/O setup at lmLogShutdown()
18628c2ecf20Sopenharmony_ci */
18638c2ecf20Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log)
18648c2ecf20Sopenharmony_ci{
18658c2ecf20Sopenharmony_ci	struct lbuf *lbuf;
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	jfs_info("lbmLogShutdown: log:0x%p", log);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	lbuf = log->lbuf_free;
18708c2ecf20Sopenharmony_ci	while (lbuf) {
18718c2ecf20Sopenharmony_ci		struct lbuf *next = lbuf->l_freelist;
18728c2ecf20Sopenharmony_ci		__free_page(lbuf->l_page);
18738c2ecf20Sopenharmony_ci		kfree(lbuf);
18748c2ecf20Sopenharmony_ci		lbuf = next;
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci/*
18808c2ecf20Sopenharmony_ci *	lbmAllocate()
18818c2ecf20Sopenharmony_ci *
18828c2ecf20Sopenharmony_ci * allocate an empty log buffer
18838c2ecf20Sopenharmony_ci */
18848c2ecf20Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int pn)
18858c2ecf20Sopenharmony_ci{
18868c2ecf20Sopenharmony_ci	struct lbuf *bp;
18878c2ecf20Sopenharmony_ci	unsigned long flags;
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/*
18908c2ecf20Sopenharmony_ci	 * recycle from log buffer freelist if any
18918c2ecf20Sopenharmony_ci	 */
18928c2ecf20Sopenharmony_ci	LCACHE_LOCK(flags);
18938c2ecf20Sopenharmony_ci	LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags);
18948c2ecf20Sopenharmony_ci	log->lbuf_free = bp->l_freelist;
18958c2ecf20Sopenharmony_ci	LCACHE_UNLOCK(flags);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	bp->l_flag = 0;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	bp->l_wqnext = NULL;
19008c2ecf20Sopenharmony_ci	bp->l_freelist = NULL;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	bp->l_pn = pn;
19038c2ecf20Sopenharmony_ci	bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize));
19048c2ecf20Sopenharmony_ci	bp->l_ceor = 0;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	return bp;
19078c2ecf20Sopenharmony_ci}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci/*
19118c2ecf20Sopenharmony_ci *	lbmFree()
19128c2ecf20Sopenharmony_ci *
19138c2ecf20Sopenharmony_ci * release a log buffer to freelist
19148c2ecf20Sopenharmony_ci */
19158c2ecf20Sopenharmony_cistatic void lbmFree(struct lbuf * bp)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	unsigned long flags;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	LCACHE_LOCK(flags);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	lbmfree(bp);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	LCACHE_UNLOCK(flags);
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic void lbmfree(struct lbuf * bp)
19278c2ecf20Sopenharmony_ci{
19288c2ecf20Sopenharmony_ci	struct jfs_log *log = bp->l_log;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	assert(bp->l_wqnext == NULL);
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/*
19338c2ecf20Sopenharmony_ci	 * return the buffer to head of freelist
19348c2ecf20Sopenharmony_ci	 */
19358c2ecf20Sopenharmony_ci	bp->l_freelist = log->lbuf_free;
19368c2ecf20Sopenharmony_ci	log->lbuf_free = bp;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	wake_up(&log->free_wait);
19398c2ecf20Sopenharmony_ci	return;
19408c2ecf20Sopenharmony_ci}
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci/*
19448c2ecf20Sopenharmony_ci * NAME:	lbmRedrive
19458c2ecf20Sopenharmony_ci *
19468c2ecf20Sopenharmony_ci * FUNCTION:	add a log buffer to the log redrive list
19478c2ecf20Sopenharmony_ci *
19488c2ecf20Sopenharmony_ci * PARAMETER:
19498c2ecf20Sopenharmony_ci *	bp	- log buffer
19508c2ecf20Sopenharmony_ci *
19518c2ecf20Sopenharmony_ci * NOTES:
19528c2ecf20Sopenharmony_ci *	Takes log_redrive_lock.
19538c2ecf20Sopenharmony_ci */
19548c2ecf20Sopenharmony_cistatic inline void lbmRedrive(struct lbuf *bp)
19558c2ecf20Sopenharmony_ci{
19568c2ecf20Sopenharmony_ci	unsigned long flags;
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	spin_lock_irqsave(&log_redrive_lock, flags);
19598c2ecf20Sopenharmony_ci	bp->l_redrive_next = log_redrive_list;
19608c2ecf20Sopenharmony_ci	log_redrive_list = bp;
19618c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&log_redrive_lock, flags);
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	wake_up_process(jfsIOthread);
19648c2ecf20Sopenharmony_ci}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci/*
19688c2ecf20Sopenharmony_ci *	lbmRead()
19698c2ecf20Sopenharmony_ci */
19708c2ecf20Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	struct bio *bio;
19738c2ecf20Sopenharmony_ci	struct lbuf *bp;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	/*
19768c2ecf20Sopenharmony_ci	 * allocate a log buffer
19778c2ecf20Sopenharmony_ci	 */
19788c2ecf20Sopenharmony_ci	*bpp = bp = lbmAllocate(log, pn);
19798c2ecf20Sopenharmony_ci	jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	bp->l_flag |= lbmREAD;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	bio = bio_alloc(GFP_NOFS, 1);
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
19868c2ecf20Sopenharmony_ci	bio_set_dev(bio, log->bdev);
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset);
19898c2ecf20Sopenharmony_ci	BUG_ON(bio->bi_iter.bi_size != LOGPSIZE);
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	bio->bi_end_io = lbmIODone;
19928c2ecf20Sopenharmony_ci	bio->bi_private = bp;
19938c2ecf20Sopenharmony_ci	bio->bi_opf = REQ_OP_READ;
19948c2ecf20Sopenharmony_ci	/*check if journaling to disk has been disabled*/
19958c2ecf20Sopenharmony_ci	if (log->no_integrity) {
19968c2ecf20Sopenharmony_ci		bio->bi_iter.bi_size = 0;
19978c2ecf20Sopenharmony_ci		lbmIODone(bio);
19988c2ecf20Sopenharmony_ci	} else {
19998c2ecf20Sopenharmony_ci		submit_bio(bio);
20008c2ecf20Sopenharmony_ci	}
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	return 0;
20058c2ecf20Sopenharmony_ci}
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci/*
20098c2ecf20Sopenharmony_ci *	lbmWrite()
20108c2ecf20Sopenharmony_ci *
20118c2ecf20Sopenharmony_ci * buffer at head of pageout queue stays after completion of
20128c2ecf20Sopenharmony_ci * partial-page pageout and redriven by explicit initiation of
20138c2ecf20Sopenharmony_ci * pageout by caller until full-page pageout is completed and
20148c2ecf20Sopenharmony_ci * released.
20158c2ecf20Sopenharmony_ci *
20168c2ecf20Sopenharmony_ci * device driver i/o done redrives pageout of new buffer at
20178c2ecf20Sopenharmony_ci * head of pageout queue when current buffer at head of pageout
20188c2ecf20Sopenharmony_ci * queue is released at the completion of its full-page pageout.
20198c2ecf20Sopenharmony_ci *
20208c2ecf20Sopenharmony_ci * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit().
20218c2ecf20Sopenharmony_ci * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone()
20228c2ecf20Sopenharmony_ci */
20238c2ecf20Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
20248c2ecf20Sopenharmony_ci		     int cant_block)
20258c2ecf20Sopenharmony_ci{
20268c2ecf20Sopenharmony_ci	struct lbuf *tail;
20278c2ecf20Sopenharmony_ci	unsigned long flags;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	jfs_info("lbmWrite: bp:0x%p flag:0x%x pn:0x%x", bp, flag, bp->l_pn);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	/* map the logical block address to physical block address */
20328c2ecf20Sopenharmony_ci	bp->l_blkno =
20338c2ecf20Sopenharmony_ci	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	/*
20388c2ecf20Sopenharmony_ci	 * initialize buffer for device driver
20398c2ecf20Sopenharmony_ci	 */
20408c2ecf20Sopenharmony_ci	bp->l_flag = flag;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/*
20438c2ecf20Sopenharmony_ci	 *	insert bp at tail of write queue associated with log
20448c2ecf20Sopenharmony_ci	 *
20458c2ecf20Sopenharmony_ci	 * (request is either for bp already/currently at head of queue
20468c2ecf20Sopenharmony_ci	 * or new bp to be inserted at tail)
20478c2ecf20Sopenharmony_ci	 */
20488c2ecf20Sopenharmony_ci	tail = log->wqueue;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	/* is buffer not already on write queue ? */
20518c2ecf20Sopenharmony_ci	if (bp->l_wqnext == NULL) {
20528c2ecf20Sopenharmony_ci		/* insert at tail of wqueue */
20538c2ecf20Sopenharmony_ci		if (tail == NULL) {
20548c2ecf20Sopenharmony_ci			log->wqueue = bp;
20558c2ecf20Sopenharmony_ci			bp->l_wqnext = bp;
20568c2ecf20Sopenharmony_ci		} else {
20578c2ecf20Sopenharmony_ci			log->wqueue = bp;
20588c2ecf20Sopenharmony_ci			bp->l_wqnext = tail->l_wqnext;
20598c2ecf20Sopenharmony_ci			tail->l_wqnext = bp;
20608c2ecf20Sopenharmony_ci		}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci		tail = bp;
20638c2ecf20Sopenharmony_ci	}
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	/* is buffer at head of wqueue and for write ? */
20668c2ecf20Sopenharmony_ci	if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) {
20678c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
20688c2ecf20Sopenharmony_ci		return;
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	LCACHE_UNLOCK(flags);	/* unlock+enable */
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	if (cant_block)
20748c2ecf20Sopenharmony_ci		lbmRedrive(bp);
20758c2ecf20Sopenharmony_ci	else if (flag & lbmSYNC)
20768c2ecf20Sopenharmony_ci		lbmStartIO(bp);
20778c2ecf20Sopenharmony_ci	else {
20788c2ecf20Sopenharmony_ci		LOGGC_UNLOCK(log);
20798c2ecf20Sopenharmony_ci		lbmStartIO(bp);
20808c2ecf20Sopenharmony_ci		LOGGC_LOCK(log);
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci/*
20868c2ecf20Sopenharmony_ci *	lbmDirectWrite()
20878c2ecf20Sopenharmony_ci *
20888c2ecf20Sopenharmony_ci * initiate pageout bypassing write queue for sidestream
20898c2ecf20Sopenharmony_ci * (e.g., log superblock) write;
20908c2ecf20Sopenharmony_ci */
20918c2ecf20Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
20928c2ecf20Sopenharmony_ci{
20938c2ecf20Sopenharmony_ci	jfs_info("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x",
20948c2ecf20Sopenharmony_ci		 bp, flag, bp->l_pn);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	/*
20978c2ecf20Sopenharmony_ci	 * initialize buffer for device driver
20988c2ecf20Sopenharmony_ci	 */
20998c2ecf20Sopenharmony_ci	bp->l_flag = flag | lbmDIRECT;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	/* map the logical block address to physical block address */
21028c2ecf20Sopenharmony_ci	bp->l_blkno =
21038c2ecf20Sopenharmony_ci	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/*
21068c2ecf20Sopenharmony_ci	 *	initiate pageout of the page
21078c2ecf20Sopenharmony_ci	 */
21088c2ecf20Sopenharmony_ci	lbmStartIO(bp);
21098c2ecf20Sopenharmony_ci}
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci/*
21138c2ecf20Sopenharmony_ci * NAME:	lbmStartIO()
21148c2ecf20Sopenharmony_ci *
21158c2ecf20Sopenharmony_ci * FUNCTION:	Interface to DD strategy routine
21168c2ecf20Sopenharmony_ci *
21178c2ecf20Sopenharmony_ci * RETURN:	none
21188c2ecf20Sopenharmony_ci *
21198c2ecf20Sopenharmony_ci * serialization: LCACHE_LOCK() is NOT held during log i/o;
21208c2ecf20Sopenharmony_ci */
21218c2ecf20Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp)
21228c2ecf20Sopenharmony_ci{
21238c2ecf20Sopenharmony_ci	struct bio *bio;
21248c2ecf20Sopenharmony_ci	struct jfs_log *log = bp->l_log;
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	jfs_info("lbmStartIO");
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	bio = bio_alloc(GFP_NOFS, 1);
21298c2ecf20Sopenharmony_ci	bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
21308c2ecf20Sopenharmony_ci	bio_set_dev(bio, log->bdev);
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset);
21338c2ecf20Sopenharmony_ci	BUG_ON(bio->bi_iter.bi_size != LOGPSIZE);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	bio->bi_end_io = lbmIODone;
21368c2ecf20Sopenharmony_ci	bio->bi_private = bp;
21378c2ecf20Sopenharmony_ci	bio->bi_opf = REQ_OP_WRITE | REQ_SYNC;
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	/* check if journaling to disk has been disabled */
21408c2ecf20Sopenharmony_ci	if (log->no_integrity) {
21418c2ecf20Sopenharmony_ci		bio->bi_iter.bi_size = 0;
21428c2ecf20Sopenharmony_ci		lbmIODone(bio);
21438c2ecf20Sopenharmony_ci	} else {
21448c2ecf20Sopenharmony_ci		submit_bio(bio);
21458c2ecf20Sopenharmony_ci		INCREMENT(lmStat.submitted);
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci}
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci/*
21518c2ecf20Sopenharmony_ci *	lbmIOWait()
21528c2ecf20Sopenharmony_ci */
21538c2ecf20Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag)
21548c2ecf20Sopenharmony_ci{
21558c2ecf20Sopenharmony_ci	unsigned long flags;
21568c2ecf20Sopenharmony_ci	int rc = 0;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	jfs_info("lbmIOWait1: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	rc = (bp->l_flag & lbmERROR) ? -EIO : 0;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	if (flag & lbmFREE)
21678c2ecf20Sopenharmony_ci		lbmfree(bp);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	LCACHE_UNLOCK(flags);	/* unlock+enable */
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	jfs_info("lbmIOWait2: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
21728c2ecf20Sopenharmony_ci	return rc;
21738c2ecf20Sopenharmony_ci}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci/*
21768c2ecf20Sopenharmony_ci *	lbmIODone()
21778c2ecf20Sopenharmony_ci *
21788c2ecf20Sopenharmony_ci * executed at INTIODONE level
21798c2ecf20Sopenharmony_ci */
21808c2ecf20Sopenharmony_cistatic void lbmIODone(struct bio *bio)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	struct lbuf *bp = bio->bi_private;
21838c2ecf20Sopenharmony_ci	struct lbuf *nextbp, *tail;
21848c2ecf20Sopenharmony_ci	struct jfs_log *log;
21858c2ecf20Sopenharmony_ci	unsigned long flags;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	/*
21888c2ecf20Sopenharmony_ci	 * get back jfs buffer bound to the i/o buffer
21898c2ecf20Sopenharmony_ci	 */
21908c2ecf20Sopenharmony_ci	jfs_info("lbmIODone: bp:0x%p flag:0x%x", bp, bp->l_flag);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	LCACHE_LOCK(flags);		/* disable+lock */
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	bp->l_flag |= lbmDONE;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	if (bio->bi_status) {
21978c2ecf20Sopenharmony_ci		bp->l_flag |= lbmERROR;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci		jfs_err("lbmIODone: I/O error in JFS log");
22008c2ecf20Sopenharmony_ci	}
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	bio_put(bio);
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	/*
22058c2ecf20Sopenharmony_ci	 *	pagein completion
22068c2ecf20Sopenharmony_ci	 */
22078c2ecf20Sopenharmony_ci	if (bp->l_flag & lbmREAD) {
22088c2ecf20Sopenharmony_ci		bp->l_flag &= ~lbmREAD;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci		/* wakeup I/O initiator */
22138c2ecf20Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		return;
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	/*
22198c2ecf20Sopenharmony_ci	 *	pageout completion
22208c2ecf20Sopenharmony_ci	 *
22218c2ecf20Sopenharmony_ci	 * the bp at the head of write queue has completed pageout.
22228c2ecf20Sopenharmony_ci	 *
22238c2ecf20Sopenharmony_ci	 * if single-commit/full-page pageout, remove the current buffer
22248c2ecf20Sopenharmony_ci	 * from head of pageout queue, and redrive pageout with
22258c2ecf20Sopenharmony_ci	 * the new buffer at head of pageout queue;
22268c2ecf20Sopenharmony_ci	 * otherwise, the partial-page pageout buffer stays at
22278c2ecf20Sopenharmony_ci	 * the head of pageout queue to be redriven for pageout
22288c2ecf20Sopenharmony_ci	 * by lmGroupCommit() until full-page pageout is completed.
22298c2ecf20Sopenharmony_ci	 */
22308c2ecf20Sopenharmony_ci	bp->l_flag &= ~lbmWRITE;
22318c2ecf20Sopenharmony_ci	INCREMENT(lmStat.pagedone);
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	/* update committed lsn */
22348c2ecf20Sopenharmony_ci	log = bp->l_log;
22358c2ecf20Sopenharmony_ci	log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	if (bp->l_flag & lbmDIRECT) {
22388c2ecf20Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
22398c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);
22408c2ecf20Sopenharmony_ci		return;
22418c2ecf20Sopenharmony_ci	}
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	tail = log->wqueue;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	/* single element queue */
22468c2ecf20Sopenharmony_ci	if (bp == tail) {
22478c2ecf20Sopenharmony_ci		/* remove head buffer of full-page pageout
22488c2ecf20Sopenharmony_ci		 * from log device write queue
22498c2ecf20Sopenharmony_ci		 */
22508c2ecf20Sopenharmony_ci		if (bp->l_flag & lbmRELEASE) {
22518c2ecf20Sopenharmony_ci			log->wqueue = NULL;
22528c2ecf20Sopenharmony_ci			bp->l_wqnext = NULL;
22538c2ecf20Sopenharmony_ci		}
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci	/* multi element queue */
22568c2ecf20Sopenharmony_ci	else {
22578c2ecf20Sopenharmony_ci		/* remove head buffer of full-page pageout
22588c2ecf20Sopenharmony_ci		 * from log device write queue
22598c2ecf20Sopenharmony_ci		 */
22608c2ecf20Sopenharmony_ci		if (bp->l_flag & lbmRELEASE) {
22618c2ecf20Sopenharmony_ci			nextbp = tail->l_wqnext = bp->l_wqnext;
22628c2ecf20Sopenharmony_ci			bp->l_wqnext = NULL;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci			/*
22658c2ecf20Sopenharmony_ci			 * redrive pageout of next page at head of write queue:
22668c2ecf20Sopenharmony_ci			 * redrive next page without any bound tblk
22678c2ecf20Sopenharmony_ci			 * (i.e., page w/o any COMMIT records), or
22688c2ecf20Sopenharmony_ci			 * first page of new group commit which has been
22698c2ecf20Sopenharmony_ci			 * queued after current page (subsequent pageout
22708c2ecf20Sopenharmony_ci			 * is performed synchronously, except page without
22718c2ecf20Sopenharmony_ci			 * any COMMITs) by lmGroupCommit() as indicated
22728c2ecf20Sopenharmony_ci			 * by lbmWRITE flag;
22738c2ecf20Sopenharmony_ci			 */
22748c2ecf20Sopenharmony_ci			if (nextbp->l_flag & lbmWRITE) {
22758c2ecf20Sopenharmony_ci				/*
22768c2ecf20Sopenharmony_ci				 * We can't do the I/O at interrupt time.
22778c2ecf20Sopenharmony_ci				 * The jfsIO thread can do it
22788c2ecf20Sopenharmony_ci				 */
22798c2ecf20Sopenharmony_ci				lbmRedrive(nextbp);
22808c2ecf20Sopenharmony_ci			}
22818c2ecf20Sopenharmony_ci		}
22828c2ecf20Sopenharmony_ci	}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	/*
22858c2ecf20Sopenharmony_ci	 *	synchronous pageout:
22868c2ecf20Sopenharmony_ci	 *
22878c2ecf20Sopenharmony_ci	 * buffer has not necessarily been removed from write queue
22888c2ecf20Sopenharmony_ci	 * (e.g., synchronous write of partial-page with COMMIT):
22898c2ecf20Sopenharmony_ci	 * leave buffer for i/o initiator to dispose
22908c2ecf20Sopenharmony_ci	 */
22918c2ecf20Sopenharmony_ci	if (bp->l_flag & lbmSYNC) {
22928c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci		/* wakeup I/O initiator */
22958c2ecf20Sopenharmony_ci		LCACHE_WAKEUP(&bp->l_ioevent);
22968c2ecf20Sopenharmony_ci	}
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	/*
22998c2ecf20Sopenharmony_ci	 *	Group Commit pageout:
23008c2ecf20Sopenharmony_ci	 */
23018c2ecf20Sopenharmony_ci	else if (bp->l_flag & lbmGC) {
23028c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);
23038c2ecf20Sopenharmony_ci		lmPostGC(bp);
23048c2ecf20Sopenharmony_ci	}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci	/*
23078c2ecf20Sopenharmony_ci	 *	asynchronous pageout:
23088c2ecf20Sopenharmony_ci	 *
23098c2ecf20Sopenharmony_ci	 * buffer must have been removed from write queue:
23108c2ecf20Sopenharmony_ci	 * insert buffer at head of freelist where it can be recycled
23118c2ecf20Sopenharmony_ci	 */
23128c2ecf20Sopenharmony_ci	else {
23138c2ecf20Sopenharmony_ci		assert(bp->l_flag & lbmRELEASE);
23148c2ecf20Sopenharmony_ci		assert(bp->l_flag & lbmFREE);
23158c2ecf20Sopenharmony_ci		lbmfree(bp);
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci		LCACHE_UNLOCK(flags);	/* unlock+enable */
23188c2ecf20Sopenharmony_ci	}
23198c2ecf20Sopenharmony_ci}
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ciint jfsIOWait(void *arg)
23228c2ecf20Sopenharmony_ci{
23238c2ecf20Sopenharmony_ci	struct lbuf *bp;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	do {
23268c2ecf20Sopenharmony_ci		spin_lock_irq(&log_redrive_lock);
23278c2ecf20Sopenharmony_ci		while ((bp = log_redrive_list)) {
23288c2ecf20Sopenharmony_ci			log_redrive_list = bp->l_redrive_next;
23298c2ecf20Sopenharmony_ci			bp->l_redrive_next = NULL;
23308c2ecf20Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
23318c2ecf20Sopenharmony_ci			lbmStartIO(bp);
23328c2ecf20Sopenharmony_ci			spin_lock_irq(&log_redrive_lock);
23338c2ecf20Sopenharmony_ci		}
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci		if (freezing(current)) {
23368c2ecf20Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
23378c2ecf20Sopenharmony_ci			try_to_freeze();
23388c2ecf20Sopenharmony_ci		} else {
23398c2ecf20Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
23408c2ecf20Sopenharmony_ci			spin_unlock_irq(&log_redrive_lock);
23418c2ecf20Sopenharmony_ci			schedule();
23428c2ecf20Sopenharmony_ci		}
23438c2ecf20Sopenharmony_ci	} while (!kthread_should_stop());
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	jfs_info("jfsIOWait being killed!");
23468c2ecf20Sopenharmony_ci	return 0;
23478c2ecf20Sopenharmony_ci}
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci/*
23508c2ecf20Sopenharmony_ci * NAME:	lmLogFormat()/jfs_logform()
23518c2ecf20Sopenharmony_ci *
23528c2ecf20Sopenharmony_ci * FUNCTION:	format file system log
23538c2ecf20Sopenharmony_ci *
23548c2ecf20Sopenharmony_ci * PARAMETERS:
23558c2ecf20Sopenharmony_ci *	log	- volume log
23568c2ecf20Sopenharmony_ci *	logAddress - start address of log space in FS block
23578c2ecf20Sopenharmony_ci *	logSize	- length of log space in FS block;
23588c2ecf20Sopenharmony_ci *
23598c2ecf20Sopenharmony_ci * RETURN:	0	- success
23608c2ecf20Sopenharmony_ci *		-EIO	- i/o error
23618c2ecf20Sopenharmony_ci *
23628c2ecf20Sopenharmony_ci * XXX: We're synchronously writing one page at a time.  This needs to
23638c2ecf20Sopenharmony_ci *	be improved by writing multiple pages at once.
23648c2ecf20Sopenharmony_ci */
23658c2ecf20Sopenharmony_ciint lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	int rc = -EIO;
23688c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi;
23698c2ecf20Sopenharmony_ci	struct logsuper *logsuper;
23708c2ecf20Sopenharmony_ci	struct logpage *lp;
23718c2ecf20Sopenharmony_ci	int lspn;		/* log sequence page number */
23728c2ecf20Sopenharmony_ci	struct lrd *lrd_ptr;
23738c2ecf20Sopenharmony_ci	int npages = 0;
23748c2ecf20Sopenharmony_ci	struct lbuf *bp;
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	jfs_info("lmLogFormat: logAddress:%Ld logSize:%d",
23778c2ecf20Sopenharmony_ci		 (long long)logAddress, logSize);
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	sbi = list_entry(log->sb_list.next, struct jfs_sb_info, log_list);
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	/* allocate a log buffer */
23828c2ecf20Sopenharmony_ci	bp = lbmAllocate(log, 1);
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	npages = logSize >> sbi->l2nbperpage;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	/*
23878c2ecf20Sopenharmony_ci	 *	log space:
23888c2ecf20Sopenharmony_ci	 *
23898c2ecf20Sopenharmony_ci	 * page 0 - reserved;
23908c2ecf20Sopenharmony_ci	 * page 1 - log superblock;
23918c2ecf20Sopenharmony_ci	 * page 2 - log data page: A SYNC log record is written
23928c2ecf20Sopenharmony_ci	 *	    into this page at logform time;
23938c2ecf20Sopenharmony_ci	 * pages 3-N - log data page: set to empty log data pages;
23948c2ecf20Sopenharmony_ci	 */
23958c2ecf20Sopenharmony_ci	/*
23968c2ecf20Sopenharmony_ci	 *	init log superblock: log page 1
23978c2ecf20Sopenharmony_ci	 */
23988c2ecf20Sopenharmony_ci	logsuper = (struct logsuper *) bp->l_ldata;
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	logsuper->magic = cpu_to_le32(LOGMAGIC);
24018c2ecf20Sopenharmony_ci	logsuper->version = cpu_to_le32(LOGVERSION);
24028c2ecf20Sopenharmony_ci	logsuper->state = cpu_to_le32(LOGREDONE);
24038c2ecf20Sopenharmony_ci	logsuper->flag = cpu_to_le32(sbi->mntflag);	/* ? */
24048c2ecf20Sopenharmony_ci	logsuper->size = cpu_to_le32(npages);
24058c2ecf20Sopenharmony_ci	logsuper->bsize = cpu_to_le32(sbi->bsize);
24068c2ecf20Sopenharmony_ci	logsuper->l2bsize = cpu_to_le32(sbi->l2bsize);
24078c2ecf20Sopenharmony_ci	logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE);
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
24108c2ecf20Sopenharmony_ci	bp->l_blkno = logAddress + sbi->nbperpage;
24118c2ecf20Sopenharmony_ci	lbmStartIO(bp);
24128c2ecf20Sopenharmony_ci	if ((rc = lbmIOWait(bp, 0)))
24138c2ecf20Sopenharmony_ci		goto exit;
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	/*
24168c2ecf20Sopenharmony_ci	 *	init pages 2 to npages-1 as log data pages:
24178c2ecf20Sopenharmony_ci	 *
24188c2ecf20Sopenharmony_ci	 * log page sequence number (lpsn) initialization:
24198c2ecf20Sopenharmony_ci	 *
24208c2ecf20Sopenharmony_ci	 * pn:   0     1     2     3                 n-1
24218c2ecf20Sopenharmony_ci	 *       +-----+-----+=====+=====+===.....===+=====+
24228c2ecf20Sopenharmony_ci	 * lspn:             N-1   0     1           N-2
24238c2ecf20Sopenharmony_ci	 *                   <--- N page circular file ---->
24248c2ecf20Sopenharmony_ci	 *
24258c2ecf20Sopenharmony_ci	 * the N (= npages-2) data pages of the log is maintained as
24268c2ecf20Sopenharmony_ci	 * a circular file for the log records;
24278c2ecf20Sopenharmony_ci	 * lpsn grows by 1 monotonically as each log page is written
24288c2ecf20Sopenharmony_ci	 * to the circular file of the log;
24298c2ecf20Sopenharmony_ci	 * and setLogpage() will not reset the page number even if
24308c2ecf20Sopenharmony_ci	 * the eor is equal to LOGPHDRSIZE. In order for binary search
24318c2ecf20Sopenharmony_ci	 * still work in find log end process, we have to simulate the
24328c2ecf20Sopenharmony_ci	 * log wrap situation at the log format time.
24338c2ecf20Sopenharmony_ci	 * The 1st log page written will have the highest lpsn. Then
24348c2ecf20Sopenharmony_ci	 * the succeeding log pages will have ascending order of
24358c2ecf20Sopenharmony_ci	 * the lspn starting from 0, ... (N-2)
24368c2ecf20Sopenharmony_ci	 */
24378c2ecf20Sopenharmony_ci	lp = (struct logpage *) bp->l_ldata;
24388c2ecf20Sopenharmony_ci	/*
24398c2ecf20Sopenharmony_ci	 * initialize 1st log page to be written: lpsn = N - 1,
24408c2ecf20Sopenharmony_ci	 * write a SYNCPT log record is written to this page
24418c2ecf20Sopenharmony_ci	 */
24428c2ecf20Sopenharmony_ci	lp->h.page = lp->t.page = cpu_to_le32(npages - 3);
24438c2ecf20Sopenharmony_ci	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE);
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	lrd_ptr = (struct lrd *) &lp->data;
24468c2ecf20Sopenharmony_ci	lrd_ptr->logtid = 0;
24478c2ecf20Sopenharmony_ci	lrd_ptr->backchain = 0;
24488c2ecf20Sopenharmony_ci	lrd_ptr->type = cpu_to_le16(LOG_SYNCPT);
24498c2ecf20Sopenharmony_ci	lrd_ptr->length = 0;
24508c2ecf20Sopenharmony_ci	lrd_ptr->log.syncpt.sync = 0;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	bp->l_blkno += sbi->nbperpage;
24538c2ecf20Sopenharmony_ci	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
24548c2ecf20Sopenharmony_ci	lbmStartIO(bp);
24558c2ecf20Sopenharmony_ci	if ((rc = lbmIOWait(bp, 0)))
24568c2ecf20Sopenharmony_ci		goto exit;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	/*
24598c2ecf20Sopenharmony_ci	 *	initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
24608c2ecf20Sopenharmony_ci	 */
24618c2ecf20Sopenharmony_ci	for (lspn = 0; lspn < npages - 3; lspn++) {
24628c2ecf20Sopenharmony_ci		lp->h.page = lp->t.page = cpu_to_le32(lspn);
24638c2ecf20Sopenharmony_ci		lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci		bp->l_blkno += sbi->nbperpage;
24668c2ecf20Sopenharmony_ci		bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
24678c2ecf20Sopenharmony_ci		lbmStartIO(bp);
24688c2ecf20Sopenharmony_ci		if ((rc = lbmIOWait(bp, 0)))
24698c2ecf20Sopenharmony_ci			goto exit;
24708c2ecf20Sopenharmony_ci	}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	rc = 0;
24738c2ecf20Sopenharmony_ciexit:
24748c2ecf20Sopenharmony_ci	/*
24758c2ecf20Sopenharmony_ci	 *	finalize log
24768c2ecf20Sopenharmony_ci	 */
24778c2ecf20Sopenharmony_ci	/* release the buffer */
24788c2ecf20Sopenharmony_ci	lbmFree(bp);
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	return rc;
24818c2ecf20Sopenharmony_ci}
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS
24848c2ecf20Sopenharmony_ciint jfs_lmstats_proc_show(struct seq_file *m, void *v)
24858c2ecf20Sopenharmony_ci{
24868c2ecf20Sopenharmony_ci	seq_printf(m,
24878c2ecf20Sopenharmony_ci		       "JFS Logmgr stats\n"
24888c2ecf20Sopenharmony_ci		       "================\n"
24898c2ecf20Sopenharmony_ci		       "commits = %d\n"
24908c2ecf20Sopenharmony_ci		       "writes submitted = %d\n"
24918c2ecf20Sopenharmony_ci		       "writes completed = %d\n"
24928c2ecf20Sopenharmony_ci		       "full pages submitted = %d\n"
24938c2ecf20Sopenharmony_ci		       "partial pages submitted = %d\n",
24948c2ecf20Sopenharmony_ci		       lmStat.commit,
24958c2ecf20Sopenharmony_ci		       lmStat.submitted,
24968c2ecf20Sopenharmony_ci		       lmStat.pagedone,
24978c2ecf20Sopenharmony_ci		       lmStat.full_page,
24988c2ecf20Sopenharmony_ci		       lmStat.partial_page);
24998c2ecf20Sopenharmony_ci	return 0;
25008c2ecf20Sopenharmony_ci}
25018c2ecf20Sopenharmony_ci#endif /* CONFIG_JFS_STATISTICS */
2502