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