11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Copyright (C) International Business Machines Corp., 2000-2004 41da177e4SLinus Torvalds * Portions Copyright (C) Christoph Hellwig, 2001-2002 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* 81da177e4SLinus Torvalds * jfs_logmgr.c: log manager 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * for related information, see transaction manager (jfs_txnmgr.c), and 111da177e4SLinus Torvalds * recovery manager (jfs_logredo.c). 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * note: for detail, RTFS. 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * log buffer manager: 161da177e4SLinus Torvalds * special purpose buffer manager supporting log i/o requirements. 171da177e4SLinus Torvalds * per log serial pageout of logpage 181da177e4SLinus Torvalds * queuing i/o requests and redrive i/o at iodone 191da177e4SLinus Torvalds * maintain current logpage buffer 201da177e4SLinus Torvalds * no caching since append only 211da177e4SLinus Torvalds * appropriate jfs buffer cache buffers as needed 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * group commit: 241da177e4SLinus Torvalds * transactions which wrote COMMIT records in the same in-memory 251da177e4SLinus Torvalds * log page during the pageout of previous/current log page(s) are 261da177e4SLinus Torvalds * committed together by the pageout of the page. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * TBD lazy commit: 291da177e4SLinus Torvalds * transactions are committed asynchronously when the log page 301da177e4SLinus Torvalds * containing it COMMIT is paged out when it becomes full; 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds * serialization: 331da177e4SLinus Torvalds * . a per log lock serialize log write. 341da177e4SLinus Torvalds * . a per log lock serialize group commit. 351da177e4SLinus Torvalds * . a per log lock serialize log open/close; 361da177e4SLinus Torvalds * 371da177e4SLinus Torvalds * TBD log integrity: 381da177e4SLinus Torvalds * careful-write (ping-pong) of last logpage to recover from crash 391da177e4SLinus Torvalds * in overwrite. 401da177e4SLinus Torvalds * detection of split (out-of-order) write of physical sectors 411da177e4SLinus Torvalds * of last logpage via timestamp at end of each sector 421da177e4SLinus Torvalds * with its mirror data array at trailer). 431da177e4SLinus Torvalds * 441da177e4SLinus Torvalds * alternatives: 451da177e4SLinus Torvalds * lsn - 64-bit monotonically increasing integer vs 461da177e4SLinus Torvalds * 32-bit lspn and page eor. 471da177e4SLinus Torvalds */ 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #include <linux/fs.h> 501da177e4SLinus Torvalds #include <linux/blkdev.h> 511da177e4SLinus Torvalds #include <linux/interrupt.h> 521da177e4SLinus Torvalds #include <linux/completion.h> 5391dbb4deSChristoph Hellwig #include <linux/kthread.h> 541da177e4SLinus Torvalds #include <linux/buffer_head.h> /* for sync_blockdev() */ 551da177e4SLinus Torvalds #include <linux/bio.h> 567dfb7103SNigel Cunningham #include <linux/freezer.h> 57afeacc8cSPaul Gortmaker #include <linux/export.h> 581da177e4SLinus Torvalds #include <linux/delay.h> 59353ab6e9SIngo Molnar #include <linux/mutex.h> 60b2e03ca7SAlexey Dobriyan #include <linux/seq_file.h> 615a0e3ad6STejun Heo #include <linux/slab.h> 621da177e4SLinus Torvalds #include "jfs_incore.h" 631da177e4SLinus Torvalds #include "jfs_filsys.h" 641da177e4SLinus Torvalds #include "jfs_metapage.h" 651868f4aaSDave Kleikamp #include "jfs_superblock.h" 661da177e4SLinus Torvalds #include "jfs_txnmgr.h" 671da177e4SLinus Torvalds #include "jfs_debug.h" 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* 711da177e4SLinus Torvalds * lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread) 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds static struct lbuf *log_redrive_list; 741da177e4SLinus Torvalds static DEFINE_SPINLOCK(log_redrive_lock); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds /* 781da177e4SLinus Torvalds * log read/write serialization (per log) 791da177e4SLinus Torvalds */ 801de87444SIngo Molnar #define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) 811de87444SIngo Molnar #define LOG_LOCK(log) mutex_lock(&((log)->loglock)) 821de87444SIngo Molnar #define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* 861da177e4SLinus Torvalds * log group commit serialization (per log) 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds #define LOGGC_LOCK_INIT(log) spin_lock_init(&(log)->gclock) 901da177e4SLinus Torvalds #define LOGGC_LOCK(log) spin_lock_irq(&(log)->gclock) 911da177e4SLinus Torvalds #define LOGGC_UNLOCK(log) spin_unlock_irq(&(log)->gclock) 921da177e4SLinus Torvalds #define LOGGC_WAKEUP(tblk) wake_up_all(&(tblk)->gcwait) 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* 951da177e4SLinus Torvalds * log sync serialization (per log) 961da177e4SLinus Torvalds */ 971da177e4SLinus Torvalds #define LOGSYNC_DELTA(logsize) min((logsize)/8, 128*LOGPSIZE) 981da177e4SLinus Torvalds #define LOGSYNC_BARRIER(logsize) ((logsize)/4) 991da177e4SLinus Torvalds /* 1001da177e4SLinus Torvalds #define LOGSYNC_DELTA(logsize) min((logsize)/4, 256*LOGPSIZE) 1011da177e4SLinus Torvalds #define LOGSYNC_BARRIER(logsize) ((logsize)/2) 1021da177e4SLinus Torvalds */ 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* 1061da177e4SLinus Torvalds * log buffer cache synchronization 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds static DEFINE_SPINLOCK(jfsLCacheLock); 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds #define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags) 1111da177e4SLinus Torvalds #define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags) 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /* 1141da177e4SLinus Torvalds * See __SLEEP_COND in jfs_locks.h 1151da177e4SLinus Torvalds */ 1161da177e4SLinus Torvalds #define LCACHE_SLEEP_COND(wq, cond, flags) \ 1171da177e4SLinus Torvalds do { \ 1181da177e4SLinus Torvalds if (cond) \ 1191da177e4SLinus Torvalds break; \ 1201da177e4SLinus Torvalds __SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \ 1211da177e4SLinus Torvalds } while (0) 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds #define LCACHE_WAKEUP(event) wake_up(event) 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* 1271da177e4SLinus Torvalds * lbuf buffer cache (lCache) control 1281da177e4SLinus Torvalds */ 1291da177e4SLinus Torvalds /* log buffer manager pageout control (cumulative, inclusive) */ 1301da177e4SLinus Torvalds #define lbmREAD 0x0001 1311da177e4SLinus Torvalds #define lbmWRITE 0x0002 /* enqueue at tail of write queue; 1321da177e4SLinus Torvalds * init pageout if at head of queue; 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds #define lbmRELEASE 0x0004 /* remove from write queue 1351da177e4SLinus Torvalds * at completion of pageout; 1361da177e4SLinus Torvalds * do not free/recycle it yet: 1371da177e4SLinus Torvalds * caller will free it; 1381da177e4SLinus Torvalds */ 1391da177e4SLinus Torvalds #define lbmSYNC 0x0008 /* do not return to freelist 1401da177e4SLinus Torvalds * when removed from write queue; 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds #define lbmFREE 0x0010 /* return to freelist 1431da177e4SLinus Torvalds * at completion of pageout; 1441da177e4SLinus Torvalds * the buffer may be recycled; 1451da177e4SLinus Torvalds */ 1461da177e4SLinus Torvalds #define lbmDONE 0x0020 1471da177e4SLinus Torvalds #define lbmERROR 0x0040 1481da177e4SLinus Torvalds #define lbmGC 0x0080 /* lbmIODone to perform post-GC processing 1491da177e4SLinus Torvalds * of log page 1501da177e4SLinus Torvalds */ 1511da177e4SLinus Torvalds #define lbmDIRECT 0x0100 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds /* 1541da177e4SLinus Torvalds * Global list of active external journals 1551da177e4SLinus Torvalds */ 1561da177e4SLinus Torvalds static LIST_HEAD(jfs_external_logs); 157bc4e6b28SFabian Frederick static struct jfs_log *dummy_log; 158353ab6e9SIngo Molnar static DEFINE_MUTEX(jfs_log_mutex); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* 1611da177e4SLinus Torvalds * forward references 1621da177e4SLinus Torvalds */ 1631da177e4SLinus Torvalds static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk, 1641da177e4SLinus Torvalds struct lrd * lrd, struct tlock * tlck); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds static int lmNextPage(struct jfs_log * log); 1671da177e4SLinus Torvalds static int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi, 1681da177e4SLinus Torvalds int activate); 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static int open_inline_log(struct super_block *sb); 1711da177e4SLinus Torvalds static int open_dummy_log(struct super_block *sb); 1721da177e4SLinus Torvalds static int lbmLogInit(struct jfs_log * log); 1731da177e4SLinus Torvalds static void lbmLogShutdown(struct jfs_log * log); 1741da177e4SLinus Torvalds static struct lbuf *lbmAllocate(struct jfs_log * log, int); 1751da177e4SLinus Torvalds static void lbmFree(struct lbuf * bp); 1761da177e4SLinus Torvalds static void lbmfree(struct lbuf * bp); 1771da177e4SLinus Torvalds static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp); 1781da177e4SLinus Torvalds static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block); 1791da177e4SLinus Torvalds static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag); 1801da177e4SLinus Torvalds static int lbmIOWait(struct lbuf * bp, int flag); 1811da177e4SLinus Torvalds static bio_end_io_t lbmIODone; 1821da177e4SLinus Torvalds static void lbmStartIO(struct lbuf * bp); 1831da177e4SLinus Torvalds static void lmGCwrite(struct jfs_log * log, int cant_block); 184cbc3d65eSDave Kleikamp static int lmLogSync(struct jfs_log * log, int hard_sync); 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds /* 1891da177e4SLinus Torvalds * statistics 1901da177e4SLinus Torvalds */ 1911da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS 1921da177e4SLinus Torvalds static struct lmStat { 1931da177e4SLinus Torvalds uint commit; /* # of commit */ 1941da177e4SLinus Torvalds uint pagedone; /* # of page written */ 1951da177e4SLinus Torvalds uint submitted; /* # of pages submitted */ 1961da177e4SLinus Torvalds uint full_page; /* # of full pages submitted */ 1971da177e4SLinus Torvalds uint partial_page; /* # of partial pages submitted */ 1981da177e4SLinus Torvalds } lmStat; 1991da177e4SLinus Torvalds #endif 2001da177e4SLinus Torvalds 20167e6682fSDave Kleikamp static void write_special_inodes(struct jfs_log *log, 20267e6682fSDave Kleikamp int (*writer)(struct address_space *)) 20367e6682fSDave Kleikamp { 20467e6682fSDave Kleikamp struct jfs_sb_info *sbi; 20567e6682fSDave Kleikamp 20667e6682fSDave Kleikamp list_for_each_entry(sbi, &log->sb_list, log_list) { 20767e6682fSDave Kleikamp writer(sbi->ipbmap->i_mapping); 20867e6682fSDave Kleikamp writer(sbi->ipimap->i_mapping); 20967e6682fSDave Kleikamp writer(sbi->direct_inode->i_mapping); 21067e6682fSDave Kleikamp } 21167e6682fSDave Kleikamp } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds /* 2141da177e4SLinus Torvalds * NAME: lmLog() 2151da177e4SLinus Torvalds * 2161da177e4SLinus Torvalds * FUNCTION: write a log record; 2171da177e4SLinus Torvalds * 2181da177e4SLinus Torvalds * PARAMETER: 2191da177e4SLinus Torvalds * 2201da177e4SLinus Torvalds * RETURN: lsn - offset to the next log record to write (end-of-log); 2211da177e4SLinus Torvalds * -1 - error; 2221da177e4SLinus Torvalds * 2231da177e4SLinus Torvalds * note: todo: log error handler 2241da177e4SLinus Torvalds */ 2251da177e4SLinus Torvalds int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, 2261da177e4SLinus Torvalds struct tlock * tlck) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds int lsn; 2291da177e4SLinus Torvalds int diffp, difft; 2301da177e4SLinus Torvalds struct metapage *mp = NULL; 2317fab479bSDave Kleikamp unsigned long flags; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p", 2341da177e4SLinus Torvalds log, tblk, lrd, tlck); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds LOG_LOCK(log); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds /* log by (out-of-transaction) JFS ? */ 2391da177e4SLinus Torvalds if (tblk == NULL) 2401da177e4SLinus Torvalds goto writeRecord; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds /* log from page ? */ 2431da177e4SLinus Torvalds if (tlck == NULL || 2441da177e4SLinus Torvalds tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL) 2451da177e4SLinus Torvalds goto writeRecord; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* 2481da177e4SLinus Torvalds * initialize/update page/transaction recovery lsn 2491da177e4SLinus Torvalds */ 2501da177e4SLinus Torvalds lsn = log->lsn; 2511da177e4SLinus Torvalds 2527fab479bSDave Kleikamp LOGSYNC_LOCK(log, flags); 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* 2551da177e4SLinus Torvalds * initialize page lsn if first log write of the page 2561da177e4SLinus Torvalds */ 2571da177e4SLinus Torvalds if (mp->lsn == 0) { 2581da177e4SLinus Torvalds mp->log = log; 2591da177e4SLinus Torvalds mp->lsn = lsn; 2601da177e4SLinus Torvalds log->count++; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds /* insert page at tail of logsynclist */ 2631da177e4SLinus Torvalds list_add_tail(&mp->synclist, &log->synclist); 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* 2671da177e4SLinus Torvalds * initialize/update lsn of tblock of the page 2681da177e4SLinus Torvalds * 2691da177e4SLinus Torvalds * transaction inherits oldest lsn of pages associated 2701da177e4SLinus Torvalds * with allocation/deallocation of resources (their 2711da177e4SLinus Torvalds * log records are used to reconstruct allocation map 2721da177e4SLinus Torvalds * at recovery time: inode for inode allocation map, 2731da177e4SLinus Torvalds * B+-tree index of extent descriptors for block 2741da177e4SLinus Torvalds * allocation map); 2751da177e4SLinus Torvalds * allocation map pages inherit transaction lsn at 2761da177e4SLinus Torvalds * commit time to allow forwarding log syncpt past log 2771da177e4SLinus Torvalds * records associated with allocation/deallocation of 2781da177e4SLinus Torvalds * resources only after persistent map of these map pages 2791da177e4SLinus Torvalds * have been updated and propagated to home. 2801da177e4SLinus Torvalds */ 2811da177e4SLinus Torvalds /* 2821da177e4SLinus Torvalds * initialize transaction lsn: 2831da177e4SLinus Torvalds */ 2841da177e4SLinus Torvalds if (tblk->lsn == 0) { 2851da177e4SLinus Torvalds /* inherit lsn of its first page logged */ 2861da177e4SLinus Torvalds tblk->lsn = mp->lsn; 2871da177e4SLinus Torvalds log->count++; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /* insert tblock after the page on logsynclist */ 2901da177e4SLinus Torvalds list_add(&tblk->synclist, &mp->synclist); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds /* 2931da177e4SLinus Torvalds * update transaction lsn: 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds else { 2961da177e4SLinus Torvalds /* inherit oldest/smallest lsn of page */ 2971da177e4SLinus Torvalds logdiff(diffp, mp->lsn, log); 2981da177e4SLinus Torvalds logdiff(difft, tblk->lsn, log); 2991da177e4SLinus Torvalds if (diffp < difft) { 3001da177e4SLinus Torvalds /* update tblock lsn with page lsn */ 3011da177e4SLinus Torvalds tblk->lsn = mp->lsn; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* move tblock after page on logsynclist */ 3041da177e4SLinus Torvalds list_move(&tblk->synclist, &mp->synclist); 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3087fab479bSDave Kleikamp LOGSYNC_UNLOCK(log, flags); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* 3111da177e4SLinus Torvalds * write the log record 3121da177e4SLinus Torvalds */ 3131da177e4SLinus Torvalds writeRecord: 3141da177e4SLinus Torvalds lsn = lmWriteRecord(log, tblk, lrd, tlck); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds /* 3171da177e4SLinus Torvalds * forward log syncpt if log reached next syncpt trigger 3181da177e4SLinus Torvalds */ 3191da177e4SLinus Torvalds logdiff(diffp, lsn, log); 3201da177e4SLinus Torvalds if (diffp >= log->nextsync) 3211da177e4SLinus Torvalds lsn = lmLogSync(log, 0); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* update end-of-log lsn */ 3241da177e4SLinus Torvalds log->lsn = lsn; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds LOG_UNLOCK(log); 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds /* return end-of-log address */ 3291da177e4SLinus Torvalds return lsn; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* 3331da177e4SLinus Torvalds * NAME: lmWriteRecord() 3341da177e4SLinus Torvalds * 3351da177e4SLinus Torvalds * FUNCTION: move the log record to current log page 3361da177e4SLinus Torvalds * 3371da177e4SLinus Torvalds * PARAMETER: cd - commit descriptor 3381da177e4SLinus Torvalds * 3391da177e4SLinus Torvalds * RETURN: end-of-log address 3401da177e4SLinus Torvalds * 3411da177e4SLinus Torvalds * serialization: LOG_LOCK() held on entry/exit 3421da177e4SLinus Torvalds */ 3431da177e4SLinus Torvalds static int 3441da177e4SLinus Torvalds lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, 3451da177e4SLinus Torvalds struct tlock * tlck) 3461da177e4SLinus Torvalds { 3471da177e4SLinus Torvalds int lsn = 0; /* end-of-log address */ 3481da177e4SLinus Torvalds struct lbuf *bp; /* dst log page buffer */ 3491da177e4SLinus Torvalds struct logpage *lp; /* dst log page */ 3501da177e4SLinus Torvalds caddr_t dst; /* destination address in log page */ 3511da177e4SLinus Torvalds int dstoffset; /* end-of-log offset in log page */ 3521da177e4SLinus Torvalds int freespace; /* free space in log page */ 3531da177e4SLinus Torvalds caddr_t p; /* src meta-data page */ 3541da177e4SLinus Torvalds caddr_t src; 3551da177e4SLinus Torvalds int srclen; 3561da177e4SLinus Torvalds int nbytes; /* number of bytes to move */ 3571da177e4SLinus Torvalds int i; 3581da177e4SLinus Torvalds int len; 3591da177e4SLinus Torvalds struct linelock *linelock; 3601da177e4SLinus Torvalds struct lv *lv; 3611da177e4SLinus Torvalds struct lvd *lvd; 3621da177e4SLinus Torvalds int l2linesize; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds len = 0; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds /* retrieve destination log page to write */ 3671da177e4SLinus Torvalds bp = (struct lbuf *) log->bp; 3681da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 3691da177e4SLinus Torvalds dstoffset = log->eor; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* any log data to write ? */ 3721da177e4SLinus Torvalds if (tlck == NULL) 3731da177e4SLinus Torvalds goto moveLrd; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds /* 3761da177e4SLinus Torvalds * move log record data 3771da177e4SLinus Torvalds */ 3781da177e4SLinus Torvalds /* retrieve source meta-data page to log */ 3791da177e4SLinus Torvalds if (tlck->flag & tlckPAGELOCK) { 3801da177e4SLinus Torvalds p = (caddr_t) (tlck->mp->data); 3811da177e4SLinus Torvalds linelock = (struct linelock *) & tlck->lock; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds /* retrieve source in-memory inode to log */ 3841da177e4SLinus Torvalds else if (tlck->flag & tlckINODELOCK) { 3851da177e4SLinus Torvalds if (tlck->type & tlckDTREE) 3861da177e4SLinus Torvalds p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot; 3871da177e4SLinus Torvalds else 3881da177e4SLinus Torvalds p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot; 3891da177e4SLinus Torvalds linelock = (struct linelock *) & tlck->lock; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds else { 3921da177e4SLinus Torvalds jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck); 3931da177e4SLinus Torvalds return 0; /* Probably should trap */ 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds l2linesize = linelock->l2linesize; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds moveData: 3981da177e4SLinus Torvalds ASSERT(linelock->index <= linelock->maxcnt); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds lv = linelock->lv; 4011da177e4SLinus Torvalds for (i = 0; i < linelock->index; i++, lv++) { 4021da177e4SLinus Torvalds if (lv->length == 0) 4031da177e4SLinus Torvalds continue; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds /* is page full ? */ 4061da177e4SLinus Torvalds if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) { 4071da177e4SLinus Torvalds /* page become full: move on to next page */ 4081da177e4SLinus Torvalds lmNextPage(log); 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds bp = log->bp; 4111da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 4121da177e4SLinus Torvalds dstoffset = LOGPHDRSIZE; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* 4161da177e4SLinus Torvalds * move log vector data 4171da177e4SLinus Torvalds */ 4181da177e4SLinus Torvalds src = (u8 *) p + (lv->offset << l2linesize); 4191da177e4SLinus Torvalds srclen = lv->length << l2linesize; 4201da177e4SLinus Torvalds len += srclen; 4211da177e4SLinus Torvalds while (srclen > 0) { 4221da177e4SLinus Torvalds freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; 4231da177e4SLinus Torvalds nbytes = min(freespace, srclen); 4241da177e4SLinus Torvalds dst = (caddr_t) lp + dstoffset; 4251da177e4SLinus Torvalds memcpy(dst, src, nbytes); 4261da177e4SLinus Torvalds dstoffset += nbytes; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* is page not full ? */ 4291da177e4SLinus Torvalds if (dstoffset < LOGPSIZE - LOGPTLRSIZE) 4301da177e4SLinus Torvalds break; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds /* page become full: move on to next page */ 4331da177e4SLinus Torvalds lmNextPage(log); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds bp = (struct lbuf *) log->bp; 4361da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 4371da177e4SLinus Torvalds dstoffset = LOGPHDRSIZE; 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds srclen -= nbytes; 4401da177e4SLinus Torvalds src += nbytes; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds /* 4441da177e4SLinus Torvalds * move log vector descriptor 4451da177e4SLinus Torvalds */ 4461da177e4SLinus Torvalds len += 4; 4471da177e4SLinus Torvalds lvd = (struct lvd *) ((caddr_t) lp + dstoffset); 4481da177e4SLinus Torvalds lvd->offset = cpu_to_le16(lv->offset); 4491da177e4SLinus Torvalds lvd->length = cpu_to_le16(lv->length); 4501da177e4SLinus Torvalds dstoffset += 4; 4511da177e4SLinus Torvalds jfs_info("lmWriteRecord: lv offset:%d length:%d", 4521da177e4SLinus Torvalds lv->offset, lv->length); 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds if ((i = linelock->next)) { 4561da177e4SLinus Torvalds linelock = (struct linelock *) lid_to_tlock(i); 4571da177e4SLinus Torvalds goto moveData; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds /* 4611da177e4SLinus Torvalds * move log record descriptor 4621da177e4SLinus Torvalds */ 4631da177e4SLinus Torvalds moveLrd: 4641da177e4SLinus Torvalds lrd->length = cpu_to_le16(len); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds src = (caddr_t) lrd; 4671da177e4SLinus Torvalds srclen = LOGRDSIZE; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds while (srclen > 0) { 4701da177e4SLinus Torvalds freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; 4711da177e4SLinus Torvalds nbytes = min(freespace, srclen); 4721da177e4SLinus Torvalds dst = (caddr_t) lp + dstoffset; 4731da177e4SLinus Torvalds memcpy(dst, src, nbytes); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds dstoffset += nbytes; 4761da177e4SLinus Torvalds srclen -= nbytes; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds /* are there more to move than freespace of page ? */ 4791da177e4SLinus Torvalds if (srclen) 4801da177e4SLinus Torvalds goto pageFull; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds /* 4831da177e4SLinus Torvalds * end of log record descriptor 4841da177e4SLinus Torvalds */ 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds /* update last log record eor */ 4871da177e4SLinus Torvalds log->eor = dstoffset; 4881da177e4SLinus Torvalds bp->l_eor = dstoffset; 4891da177e4SLinus Torvalds lsn = (log->page << L2LOGPSIZE) + dstoffset; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds if (lrd->type & cpu_to_le16(LOG_COMMIT)) { 4921da177e4SLinus Torvalds tblk->clsn = lsn; 4931da177e4SLinus Torvalds jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn, 4941da177e4SLinus Torvalds bp->l_eor); 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds INCREMENT(lmStat.commit); /* # of commit */ 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds /* 4991da177e4SLinus Torvalds * enqueue tblock for group commit: 5001da177e4SLinus Torvalds * 5011da177e4SLinus Torvalds * enqueue tblock of non-trivial/synchronous COMMIT 5021da177e4SLinus Torvalds * at tail of group commit queue 5031da177e4SLinus Torvalds * (trivial/asynchronous COMMITs are ignored by 5041da177e4SLinus Torvalds * group commit.) 5051da177e4SLinus Torvalds */ 5061da177e4SLinus Torvalds LOGGC_LOCK(log); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* init tblock gc state */ 5091da177e4SLinus Torvalds tblk->flag = tblkGC_QUEUE; 5101da177e4SLinus Torvalds tblk->bp = log->bp; 5111da177e4SLinus Torvalds tblk->pn = log->page; 5121da177e4SLinus Torvalds tblk->eor = log->eor; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* enqueue transaction to commit queue */ 5151da177e4SLinus Torvalds list_add_tail(&tblk->cqueue, &log->cqueue); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds LOGGC_UNLOCK(log); 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x", 5211da177e4SLinus Torvalds le16_to_cpu(lrd->type), log->bp, log->page, dstoffset); 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds /* page not full ? */ 5241da177e4SLinus Torvalds if (dstoffset < LOGPSIZE - LOGPTLRSIZE) 5251da177e4SLinus Torvalds return lsn; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds pageFull: 5281da177e4SLinus Torvalds /* page become full: move on to next page */ 5291da177e4SLinus Torvalds lmNextPage(log); 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds bp = (struct lbuf *) log->bp; 5321da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 5331da177e4SLinus Torvalds dstoffset = LOGPHDRSIZE; 5341da177e4SLinus Torvalds src += nbytes; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds return lsn; 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds /* 5421da177e4SLinus Torvalds * NAME: lmNextPage() 5431da177e4SLinus Torvalds * 5441da177e4SLinus Torvalds * FUNCTION: write current page and allocate next page. 5451da177e4SLinus Torvalds * 5461da177e4SLinus Torvalds * PARAMETER: log 5471da177e4SLinus Torvalds * 5481da177e4SLinus Torvalds * RETURN: 0 5491da177e4SLinus Torvalds * 5501da177e4SLinus Torvalds * serialization: LOG_LOCK() held on entry/exit 5511da177e4SLinus Torvalds */ 5521da177e4SLinus Torvalds static int lmNextPage(struct jfs_log * log) 5531da177e4SLinus Torvalds { 5541da177e4SLinus Torvalds struct logpage *lp; 5551da177e4SLinus Torvalds int lspn; /* log sequence page number */ 5561da177e4SLinus Torvalds int pn; /* current page number */ 5571da177e4SLinus Torvalds struct lbuf *bp; 5581da177e4SLinus Torvalds struct lbuf *nextbp; 5591da177e4SLinus Torvalds struct tblock *tblk; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* get current log page number and log sequence page number */ 5621da177e4SLinus Torvalds pn = log->page; 5631da177e4SLinus Torvalds bp = log->bp; 5641da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 5651da177e4SLinus Torvalds lspn = le32_to_cpu(lp->h.page); 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds LOGGC_LOCK(log); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* 5701da177e4SLinus Torvalds * write or queue the full page at the tail of write queue 5711da177e4SLinus Torvalds */ 5721da177e4SLinus Torvalds /* get the tail tblk on commit queue */ 5731da177e4SLinus Torvalds if (list_empty(&log->cqueue)) 5741da177e4SLinus Torvalds tblk = NULL; 5751da177e4SLinus Torvalds else 5761da177e4SLinus Torvalds tblk = list_entry(log->cqueue.prev, struct tblock, cqueue); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds /* every tblk who has COMMIT record on the current page, 5791da177e4SLinus Torvalds * and has not been committed, must be on commit queue 5801da177e4SLinus Torvalds * since tblk is queued at commit queueu at the time 5811da177e4SLinus Torvalds * of writing its COMMIT record on the page before 5821da177e4SLinus Torvalds * page becomes full (even though the tblk thread 5831da177e4SLinus Torvalds * who wrote COMMIT record may have been suspended 5841da177e4SLinus Torvalds * currently); 5851da177e4SLinus Torvalds */ 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /* is page bound with outstanding tail tblk ? */ 5881da177e4SLinus Torvalds if (tblk && tblk->pn == pn) { 5891da177e4SLinus Torvalds /* mark tblk for end-of-page */ 5901da177e4SLinus Torvalds tblk->flag |= tblkGC_EOP; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds if (log->cflag & logGC_PAGEOUT) { 5931da177e4SLinus Torvalds /* if page is not already on write queue, 5941da177e4SLinus Torvalds * just enqueue (no lbmWRITE to prevent redrive) 5951da177e4SLinus Torvalds * buffer to wqueue to ensure correct serial order 5961da177e4SLinus Torvalds * of the pages since log pages will be added 5971da177e4SLinus Torvalds * continuously 5981da177e4SLinus Torvalds */ 5991da177e4SLinus Torvalds if (bp->l_wqnext == NULL) 6001da177e4SLinus Torvalds lbmWrite(log, bp, 0, 0); 6011da177e4SLinus Torvalds } else { 6021da177e4SLinus Torvalds /* 6031da177e4SLinus Torvalds * No current GC leader, initiate group commit 6041da177e4SLinus Torvalds */ 6051da177e4SLinus Torvalds log->cflag |= logGC_PAGEOUT; 6061da177e4SLinus Torvalds lmGCwrite(log, 0); 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds /* page is not bound with outstanding tblk: 6101da177e4SLinus Torvalds * init write or mark it to be redriven (lbmWRITE) 6111da177e4SLinus Torvalds */ 6121da177e4SLinus Torvalds else { 6131da177e4SLinus Torvalds /* finalize the page */ 6141da177e4SLinus Torvalds bp->l_ceor = bp->l_eor; 6151da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 6161da177e4SLinus Torvalds lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0); 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds LOGGC_UNLOCK(log); 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds /* 6211da177e4SLinus Torvalds * allocate/initialize next page 6221da177e4SLinus Torvalds */ 6231da177e4SLinus Torvalds /* if log wraps, the first data page of log is 2 6241da177e4SLinus Torvalds * (0 never used, 1 is superblock). 6251da177e4SLinus Torvalds */ 6261da177e4SLinus Torvalds log->page = (pn == log->size - 1) ? 2 : pn + 1; 6271da177e4SLinus Torvalds log->eor = LOGPHDRSIZE; /* ? valid page empty/full at logRedo() */ 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /* allocate/initialize next log page buffer */ 6301da177e4SLinus Torvalds nextbp = lbmAllocate(log, log->page); 6311da177e4SLinus Torvalds nextbp->l_eor = log->eor; 6321da177e4SLinus Torvalds log->bp = nextbp; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds /* initialize next log page */ 6351da177e4SLinus Torvalds lp = (struct logpage *) nextbp->l_ldata; 6361da177e4SLinus Torvalds lp->h.page = lp->t.page = cpu_to_le32(lspn + 1); 6371da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds return 0; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds /* 6441da177e4SLinus Torvalds * NAME: lmGroupCommit() 6451da177e4SLinus Torvalds * 6461da177e4SLinus Torvalds * FUNCTION: group commit 6471da177e4SLinus Torvalds * initiate pageout of the pages with COMMIT in the order of 6481da177e4SLinus Torvalds * page number - redrive pageout of the page at the head of 6491da177e4SLinus Torvalds * pageout queue until full page has been written. 6501da177e4SLinus Torvalds * 6511da177e4SLinus Torvalds * RETURN: 6521da177e4SLinus Torvalds * 6531da177e4SLinus Torvalds * NOTE: 6541da177e4SLinus Torvalds * LOGGC_LOCK serializes log group commit queue, and 6551da177e4SLinus Torvalds * transaction blocks on the commit queue. 6561da177e4SLinus Torvalds * N.B. LOG_LOCK is NOT held during lmGroupCommit(). 6571da177e4SLinus Torvalds */ 6581da177e4SLinus Torvalds int lmGroupCommit(struct jfs_log * log, struct tblock * tblk) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds int rc = 0; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds LOGGC_LOCK(log); 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds /* group committed already ? */ 6651da177e4SLinus Torvalds if (tblk->flag & tblkGC_COMMITTED) { 6661da177e4SLinus Torvalds if (tblk->flag & tblkGC_ERROR) 6671da177e4SLinus Torvalds rc = -EIO; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds LOGGC_UNLOCK(log); 6701da177e4SLinus Torvalds return rc; 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc); 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds if (tblk->xflag & COMMIT_LAZY) 6751da177e4SLinus Torvalds tblk->flag |= tblkGC_LAZY; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) && 6781da177e4SLinus Torvalds (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag) 6791da177e4SLinus Torvalds || jfs_tlocks_low)) { 6801da177e4SLinus Torvalds /* 6811da177e4SLinus Torvalds * No pageout in progress 6821da177e4SLinus Torvalds * 6831da177e4SLinus Torvalds * start group commit as its group leader. 6841da177e4SLinus Torvalds */ 6851da177e4SLinus Torvalds log->cflag |= logGC_PAGEOUT; 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds lmGCwrite(log, 0); 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds if (tblk->xflag & COMMIT_LAZY) { 6911da177e4SLinus Torvalds /* 6921da177e4SLinus Torvalds * Lazy transactions can leave now 6931da177e4SLinus Torvalds */ 6941da177e4SLinus Torvalds LOGGC_UNLOCK(log); 6951da177e4SLinus Torvalds return 0; 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* lmGCwrite gives up LOGGC_LOCK, check again */ 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds if (tblk->flag & tblkGC_COMMITTED) { 7011da177e4SLinus Torvalds if (tblk->flag & tblkGC_ERROR) 7021da177e4SLinus Torvalds rc = -EIO; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds LOGGC_UNLOCK(log); 7051da177e4SLinus Torvalds return rc; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds /* upcount transaction waiting for completion 7091da177e4SLinus Torvalds */ 7101da177e4SLinus Torvalds log->gcrtc++; 7111da177e4SLinus Torvalds tblk->flag |= tblkGC_READY; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds __SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED), 7141da177e4SLinus Torvalds LOGGC_LOCK(log), LOGGC_UNLOCK(log)); 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds /* removed from commit queue */ 7171da177e4SLinus Torvalds if (tblk->flag & tblkGC_ERROR) 7181da177e4SLinus Torvalds rc = -EIO; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds LOGGC_UNLOCK(log); 7211da177e4SLinus Torvalds return rc; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds /* 7251da177e4SLinus Torvalds * NAME: lmGCwrite() 7261da177e4SLinus Torvalds * 7271da177e4SLinus Torvalds * FUNCTION: group commit write 7281da177e4SLinus Torvalds * initiate write of log page, building a group of all transactions 7291da177e4SLinus Torvalds * with commit records on that page. 7301da177e4SLinus Torvalds * 7311da177e4SLinus Torvalds * RETURN: None 7321da177e4SLinus Torvalds * 7331da177e4SLinus Torvalds * NOTE: 7341da177e4SLinus Torvalds * LOGGC_LOCK must be held by caller. 7351da177e4SLinus Torvalds * N.B. LOG_LOCK is NOT held during lmGroupCommit(). 7361da177e4SLinus Torvalds */ 7371da177e4SLinus Torvalds static void lmGCwrite(struct jfs_log * log, int cant_write) 7381da177e4SLinus Torvalds { 7391da177e4SLinus Torvalds struct lbuf *bp; 7401da177e4SLinus Torvalds struct logpage *lp; 7411da177e4SLinus Torvalds int gcpn; /* group commit page number */ 7421da177e4SLinus Torvalds struct tblock *tblk; 7431da177e4SLinus Torvalds struct tblock *xtblk = NULL; 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds /* 7461da177e4SLinus Torvalds * build the commit group of a log page 7471da177e4SLinus Torvalds * 7481da177e4SLinus Torvalds * scan commit queue and make a commit group of all 7491da177e4SLinus Torvalds * transactions with COMMIT records on the same log page. 7501da177e4SLinus Torvalds */ 7511da177e4SLinus Torvalds /* get the head tblk on the commit queue */ 7521da177e4SLinus Torvalds gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn; 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds list_for_each_entry(tblk, &log->cqueue, cqueue) { 7551da177e4SLinus Torvalds if (tblk->pn != gcpn) 7561da177e4SLinus Torvalds break; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds xtblk = tblk; 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds /* state transition: (QUEUE, READY) -> COMMIT */ 7611da177e4SLinus Torvalds tblk->flag |= tblkGC_COMMIT; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds tblk = xtblk; /* last tblk of the page */ 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds /* 7661da177e4SLinus Torvalds * pageout to commit transactions on the log page. 7671da177e4SLinus Torvalds */ 7681da177e4SLinus Torvalds bp = (struct lbuf *) tblk->bp; 7691da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 7701da177e4SLinus Torvalds /* is page already full ? */ 7711da177e4SLinus Torvalds if (tblk->flag & tblkGC_EOP) { 7721da177e4SLinus Torvalds /* mark page to free at end of group commit of the page */ 7731da177e4SLinus Torvalds tblk->flag &= ~tblkGC_EOP; 7741da177e4SLinus Torvalds tblk->flag |= tblkGC_FREE; 7751da177e4SLinus Torvalds bp->l_ceor = bp->l_eor; 7761da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 7771da177e4SLinus Torvalds lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC, 7781da177e4SLinus Torvalds cant_write); 7791da177e4SLinus Torvalds INCREMENT(lmStat.full_page); 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds /* page is not yet full */ 7821da177e4SLinus Torvalds else { 7831da177e4SLinus Torvalds bp->l_ceor = tblk->eor; /* ? bp->l_ceor = bp->l_eor; */ 7841da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 7851da177e4SLinus Torvalds lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write); 7861da177e4SLinus Torvalds INCREMENT(lmStat.partial_page); 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* 7911da177e4SLinus Torvalds * NAME: lmPostGC() 7921da177e4SLinus Torvalds * 7931da177e4SLinus Torvalds * FUNCTION: group commit post-processing 7941da177e4SLinus Torvalds * Processes transactions after their commit records have been written 7951da177e4SLinus Torvalds * to disk, redriving log I/O if necessary. 7961da177e4SLinus Torvalds * 7971da177e4SLinus Torvalds * RETURN: None 7981da177e4SLinus Torvalds * 7991da177e4SLinus Torvalds * NOTE: 8001da177e4SLinus Torvalds * This routine is called a interrupt time by lbmIODone 8011da177e4SLinus Torvalds */ 8021da177e4SLinus Torvalds static void lmPostGC(struct lbuf * bp) 8031da177e4SLinus Torvalds { 8041da177e4SLinus Torvalds unsigned long flags; 8051da177e4SLinus Torvalds struct jfs_log *log = bp->l_log; 8061da177e4SLinus Torvalds struct logpage *lp; 8071da177e4SLinus Torvalds struct tblock *tblk, *temp; 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds //LOGGC_LOCK(log); 8101da177e4SLinus Torvalds spin_lock_irqsave(&log->gclock, flags); 8111da177e4SLinus Torvalds /* 8121da177e4SLinus Torvalds * current pageout of group commit completed. 8131da177e4SLinus Torvalds * 8141da177e4SLinus Torvalds * remove/wakeup transactions from commit queue who were 8151da177e4SLinus Torvalds * group committed with the current log page 8161da177e4SLinus Torvalds */ 8171da177e4SLinus Torvalds list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) { 8181da177e4SLinus Torvalds if (!(tblk->flag & tblkGC_COMMIT)) 8191da177e4SLinus Torvalds break; 8201da177e4SLinus Torvalds /* if transaction was marked GC_COMMIT then 8211da177e4SLinus Torvalds * it has been shipped in the current pageout 8221da177e4SLinus Torvalds * and made it to disk - it is committed. 8231da177e4SLinus Torvalds */ 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds if (bp->l_flag & lbmERROR) 8261da177e4SLinus Torvalds tblk->flag |= tblkGC_ERROR; 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds /* remove it from the commit queue */ 8291da177e4SLinus Torvalds list_del(&tblk->cqueue); 8301da177e4SLinus Torvalds tblk->flag &= ~tblkGC_QUEUE; 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds if (tblk == log->flush_tblk) { 8331da177e4SLinus Torvalds /* we can stop flushing the log now */ 8341da177e4SLinus Torvalds clear_bit(log_FLUSH, &log->flag); 8351da177e4SLinus Torvalds log->flush_tblk = NULL; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk, 8391da177e4SLinus Torvalds tblk->flag); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds if (!(tblk->xflag & COMMIT_FORCE)) 8421da177e4SLinus Torvalds /* 8431da177e4SLinus Torvalds * Hand tblk over to lazy commit thread 8441da177e4SLinus Torvalds */ 8451da177e4SLinus Torvalds txLazyUnlock(tblk); 8461da177e4SLinus Torvalds else { 8471da177e4SLinus Torvalds /* state transition: COMMIT -> COMMITTED */ 8481da177e4SLinus Torvalds tblk->flag |= tblkGC_COMMITTED; 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds if (tblk->flag & tblkGC_READY) 8511da177e4SLinus Torvalds log->gcrtc--; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds LOGGC_WAKEUP(tblk); 8541da177e4SLinus Torvalds } 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds /* was page full before pageout ? 8571da177e4SLinus Torvalds * (and this is the last tblk bound with the page) 8581da177e4SLinus Torvalds */ 8591da177e4SLinus Torvalds if (tblk->flag & tblkGC_FREE) 8601da177e4SLinus Torvalds lbmFree(bp); 8611da177e4SLinus Torvalds /* did page become full after pageout ? 8621da177e4SLinus Torvalds * (and this is the last tblk bound with the page) 8631da177e4SLinus Torvalds */ 8641da177e4SLinus Torvalds else if (tblk->flag & tblkGC_EOP) { 8651da177e4SLinus Torvalds /* finalize the page */ 8661da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 8671da177e4SLinus Torvalds bp->l_ceor = bp->l_eor; 8681da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 8691da177e4SLinus Torvalds jfs_info("lmPostGC: calling lbmWrite"); 8701da177e4SLinus Torvalds lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 8711da177e4SLinus Torvalds 1); 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds /* are there any transactions who have entered lnGroupCommit() 8771da177e4SLinus Torvalds * (whose COMMITs are after that of the last log page written. 8781da177e4SLinus Torvalds * They are waiting for new group commit (above at (SLEEP 1)) 8791da177e4SLinus Torvalds * or lazy transactions are on a full (queued) log page, 8801da177e4SLinus Torvalds * select the latest ready transaction as new group leader and 8811da177e4SLinus Torvalds * wake her up to lead her group. 8821da177e4SLinus Torvalds */ 8831da177e4SLinus Torvalds if ((!list_empty(&log->cqueue)) && 8841da177e4SLinus Torvalds ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) || 8851da177e4SLinus Torvalds test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low)) 8861da177e4SLinus Torvalds /* 8871da177e4SLinus Torvalds * Call lmGCwrite with new group leader 8881da177e4SLinus Torvalds */ 8891da177e4SLinus Torvalds lmGCwrite(log, 1); 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds /* no transaction are ready yet (transactions are only just 8921da177e4SLinus Torvalds * queued (GC_QUEUE) and not entered for group commit yet). 8931da177e4SLinus Torvalds * the first transaction entering group commit 8941da177e4SLinus Torvalds * will elect herself as new group leader. 8951da177e4SLinus Torvalds */ 8961da177e4SLinus Torvalds else 8971da177e4SLinus Torvalds log->cflag &= ~logGC_PAGEOUT; 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds //LOGGC_UNLOCK(log); 9001da177e4SLinus Torvalds spin_unlock_irqrestore(&log->gclock, flags); 9011da177e4SLinus Torvalds return; 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds /* 9051da177e4SLinus Torvalds * NAME: lmLogSync() 9061da177e4SLinus Torvalds * 9071da177e4SLinus Torvalds * FUNCTION: write log SYNCPT record for specified log 9081da177e4SLinus Torvalds * if new sync address is available 9091da177e4SLinus Torvalds * (normally the case if sync() is executed by back-ground 9101da177e4SLinus Torvalds * process). 9111da177e4SLinus Torvalds * calculate new value of i_nextsync which determines when 9121da177e4SLinus Torvalds * this code is called again. 9131da177e4SLinus Torvalds * 9141c627829SDave Kleikamp * PARAMETERS: log - log structure 915cbc3d65eSDave Kleikamp * hard_sync - 1 to force all metadata to be written 9161da177e4SLinus Torvalds * 9171da177e4SLinus Torvalds * RETURN: 0 9181da177e4SLinus Torvalds * 9191da177e4SLinus Torvalds * serialization: LOG_LOCK() held on entry/exit 9201da177e4SLinus Torvalds */ 921cbc3d65eSDave Kleikamp static int lmLogSync(struct jfs_log * log, int hard_sync) 9221da177e4SLinus Torvalds { 9231da177e4SLinus Torvalds int logsize; 9241da177e4SLinus Torvalds int written; /* written since last syncpt */ 9251da177e4SLinus Torvalds int free; /* free space left available */ 9261da177e4SLinus Torvalds int delta; /* additional delta to write normally */ 9271da177e4SLinus Torvalds int more; /* additional write granted */ 9281da177e4SLinus Torvalds struct lrd lrd; 9291da177e4SLinus Torvalds int lsn; 9301da177e4SLinus Torvalds struct logsyncblk *lp; 9317fab479bSDave Kleikamp unsigned long flags; 9327fab479bSDave Kleikamp 9337fab479bSDave Kleikamp /* push dirty metapages out to disk */ 934cbc3d65eSDave Kleikamp if (hard_sync) 93567e6682fSDave Kleikamp write_special_inodes(log, filemap_fdatawrite); 936cbc3d65eSDave Kleikamp else 93767e6682fSDave Kleikamp write_special_inodes(log, filemap_flush); 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds /* 9401da177e4SLinus Torvalds * forward syncpt 9411da177e4SLinus Torvalds */ 9421da177e4SLinus Torvalds /* if last sync is same as last syncpt, 9431da177e4SLinus Torvalds * invoke sync point forward processing to update sync. 9441da177e4SLinus Torvalds */ 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds if (log->sync == log->syncpt) { 9477fab479bSDave Kleikamp LOGSYNC_LOCK(log, flags); 9481da177e4SLinus Torvalds if (list_empty(&log->synclist)) 9491da177e4SLinus Torvalds log->sync = log->lsn; 9501da177e4SLinus Torvalds else { 9511da177e4SLinus Torvalds lp = list_entry(log->synclist.next, 9521da177e4SLinus Torvalds struct logsyncblk, synclist); 9531da177e4SLinus Torvalds log->sync = lp->lsn; 9541da177e4SLinus Torvalds } 9557fab479bSDave Kleikamp LOGSYNC_UNLOCK(log, flags); 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /* if sync is different from last syncpt, 9601da177e4SLinus Torvalds * write a SYNCPT record with syncpt = sync. 9611da177e4SLinus Torvalds * reset syncpt = sync 9621da177e4SLinus Torvalds */ 9631da177e4SLinus Torvalds if (log->sync != log->syncpt) { 9641da177e4SLinus Torvalds lrd.logtid = 0; 9651da177e4SLinus Torvalds lrd.backchain = 0; 9661da177e4SLinus Torvalds lrd.type = cpu_to_le16(LOG_SYNCPT); 9671da177e4SLinus Torvalds lrd.length = 0; 9681da177e4SLinus Torvalds lrd.log.syncpt.sync = cpu_to_le32(log->sync); 9691da177e4SLinus Torvalds lsn = lmWriteRecord(log, NULL, &lrd, NULL); 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds log->syncpt = log->sync; 9721da177e4SLinus Torvalds } else 9731da177e4SLinus Torvalds lsn = log->lsn; 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds /* 9761da177e4SLinus Torvalds * setup next syncpt trigger (SWAG) 9771da177e4SLinus Torvalds */ 9781da177e4SLinus Torvalds logsize = log->logsize; 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds logdiff(written, lsn, log); 9811da177e4SLinus Torvalds free = logsize - written; 9821da177e4SLinus Torvalds delta = LOGSYNC_DELTA(logsize); 9831da177e4SLinus Torvalds more = min(free / 2, delta); 9841da177e4SLinus Torvalds if (more < 2 * LOGPSIZE) { 9851da177e4SLinus Torvalds jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n"); 9861da177e4SLinus Torvalds /* 9871da177e4SLinus Torvalds * log wrapping 9881da177e4SLinus Torvalds * 9891da177e4SLinus Torvalds * option 1 - panic ? No.! 9901da177e4SLinus Torvalds * option 2 - shutdown file systems 9911da177e4SLinus Torvalds * associated with log ? 9921da177e4SLinus Torvalds * option 3 - extend log ? 9931da177e4SLinus Torvalds * option 4 - second chance 9941da177e4SLinus Torvalds * 9951da177e4SLinus Torvalds * mark log wrapped, and continue. 9961da177e4SLinus Torvalds * when all active transactions are completed, 997817f2c84SNikanth Karthikesan * mark log valid for recovery. 9981da177e4SLinus Torvalds * if crashed during invalid state, log state 999817f2c84SNikanth Karthikesan * implies invalid log, forcing fsck(). 10001da177e4SLinus Torvalds */ 10011da177e4SLinus Torvalds /* mark log state log wrap in log superblock */ 10021da177e4SLinus Torvalds /* log->state = LOGWRAP; */ 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds /* reset sync point computation */ 10051da177e4SLinus Torvalds log->syncpt = log->sync = lsn; 10061da177e4SLinus Torvalds log->nextsync = delta; 10071da177e4SLinus Torvalds } else 10081da177e4SLinus Torvalds /* next syncpt trigger = written + more */ 10091da177e4SLinus Torvalds log->nextsync = written + more; 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds /* if number of bytes written from last sync point is more 10121da177e4SLinus Torvalds * than 1/4 of the log size, stop new transactions from 10131da177e4SLinus Torvalds * starting until all current transactions are completed 10141da177e4SLinus Torvalds * by setting syncbarrier flag. 10151da177e4SLinus Torvalds */ 1016c2783f3aSDave Kleikamp if (!test_bit(log_SYNCBARRIER, &log->flag) && 1017c2783f3aSDave Kleikamp (written > LOGSYNC_BARRIER(logsize)) && log->active) { 10181da177e4SLinus Torvalds set_bit(log_SYNCBARRIER, &log->flag); 10191da177e4SLinus Torvalds jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn, 10201da177e4SLinus Torvalds log->syncpt); 10211da177e4SLinus Torvalds /* 10221da177e4SLinus Torvalds * We may have to initiate group commit 10231da177e4SLinus Torvalds */ 10241da177e4SLinus Torvalds jfs_flush_journal(log, 0); 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds return lsn; 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 10301c627829SDave Kleikamp /* 10311c627829SDave Kleikamp * NAME: jfs_syncpt 10321c627829SDave Kleikamp * 10331c627829SDave Kleikamp * FUNCTION: write log SYNCPT record for specified log 10341c627829SDave Kleikamp * 10351c627829SDave Kleikamp * PARAMETERS: log - log structure 1036cbc3d65eSDave Kleikamp * hard_sync - set to 1 to force metadata to be written 10371c627829SDave Kleikamp */ 1038cbc3d65eSDave Kleikamp void jfs_syncpt(struct jfs_log *log, int hard_sync) 10391c627829SDave Kleikamp { LOG_LOCK(log); 104073aaa22dSDave Kleikamp if (!test_bit(log_QUIESCE, &log->flag)) 1041cbc3d65eSDave Kleikamp lmLogSync(log, hard_sync); 10421c627829SDave Kleikamp LOG_UNLOCK(log); 10431c627829SDave Kleikamp } 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds /* 10461da177e4SLinus Torvalds * NAME: lmLogOpen() 10471da177e4SLinus Torvalds * 10481da177e4SLinus Torvalds * FUNCTION: open the log on first open; 10491da177e4SLinus Torvalds * insert filesystem in the active list of the log. 10501da177e4SLinus Torvalds * 10511da177e4SLinus Torvalds * PARAMETER: ipmnt - file system mount inode 10521da177e4SLinus Torvalds * iplog - log inode (out) 10531da177e4SLinus Torvalds * 10541da177e4SLinus Torvalds * RETURN: 10551da177e4SLinus Torvalds * 10561da177e4SLinus Torvalds * serialization: 10571da177e4SLinus Torvalds */ 10581da177e4SLinus Torvalds int lmLogOpen(struct super_block *sb) 10591da177e4SLinus Torvalds { 10601da177e4SLinus Torvalds int rc; 10611da177e4SLinus Torvalds struct block_device *bdev; 10621da177e4SLinus Torvalds struct jfs_log *log; 10631da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb); 10641da177e4SLinus Torvalds 10651da177e4SLinus Torvalds if (sbi->flag & JFS_NOINTEGRITY) 10661da177e4SLinus Torvalds return open_dummy_log(sb); 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds if (sbi->mntflag & JFS_INLINELOG) 10691da177e4SLinus Torvalds return open_inline_log(sb); 10701da177e4SLinus Torvalds 1071353ab6e9SIngo Molnar mutex_lock(&jfs_log_mutex); 10721da177e4SLinus Torvalds list_for_each_entry(log, &jfs_external_logs, journal_list) { 10731da177e4SLinus Torvalds if (log->bdev->bd_dev == sbi->logdev) { 10742e3bc612SAndy Shevchenko if (!uuid_equal(&log->uuid, &sbi->loguuid)) { 1075b18db6deSJoe Perches jfs_warn("wrong uuid on JFS journal"); 1076353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 10771da177e4SLinus Torvalds return -EINVAL; 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds /* 10801da177e4SLinus Torvalds * add file system to log active file system list 10811da177e4SLinus Torvalds */ 10821da177e4SLinus Torvalds if ((rc = lmLogFileSystem(log, sbi, 1))) { 1083353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 10841da177e4SLinus Torvalds return rc; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds goto journal_found; 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds } 10891da177e4SLinus Torvalds 10905b3030e3SEric Sesterhenn if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) { 1091353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 10921da177e4SLinus Torvalds return -ENOMEM; 10931da177e4SLinus Torvalds } 10941da177e4SLinus Torvalds INIT_LIST_HEAD(&log->sb_list); 10951da177e4SLinus Torvalds init_waitqueue_head(&log->syncwait); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds /* 10981da177e4SLinus Torvalds * external log as separate logical volume 10991da177e4SLinus Torvalds * 11001da177e4SLinus Torvalds * file systems to log may have n-to-1 relationship; 11011da177e4SLinus Torvalds */ 11021da177e4SLinus Torvalds 1103d4d77629STejun Heo bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, 1104e525fd89STejun Heo log); 11051da177e4SLinus Torvalds if (IS_ERR(bdev)) { 11069054760fSAl Viro rc = PTR_ERR(bdev); 11071da177e4SLinus Torvalds goto free; 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds log->bdev = bdev; 11112e3bc612SAndy Shevchenko uuid_copy(&log->uuid, &sbi->loguuid); 11121da177e4SLinus Torvalds 11131da177e4SLinus Torvalds /* 11141da177e4SLinus Torvalds * initialize log: 11151da177e4SLinus Torvalds */ 11161da177e4SLinus Torvalds if ((rc = lmLogInit(log))) 1117e525fd89STejun Heo goto close; 11181da177e4SLinus Torvalds 11191da177e4SLinus Torvalds list_add(&log->journal_list, &jfs_external_logs); 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds /* 11221da177e4SLinus Torvalds * add file system to log active file system list 11231da177e4SLinus Torvalds */ 11241da177e4SLinus Torvalds if ((rc = lmLogFileSystem(log, sbi, 1))) 11251da177e4SLinus Torvalds goto shutdown; 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds journal_found: 11281da177e4SLinus Torvalds LOG_LOCK(log); 11291da177e4SLinus Torvalds list_add(&sbi->log_list, &log->sb_list); 11301da177e4SLinus Torvalds sbi->log = log; 11311da177e4SLinus Torvalds LOG_UNLOCK(log); 11321da177e4SLinus Torvalds 1133353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 11341da177e4SLinus Torvalds return 0; 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds /* 11371da177e4SLinus Torvalds * unwind on error 11381da177e4SLinus Torvalds */ 11391da177e4SLinus Torvalds shutdown: /* unwind lbmLogInit() */ 11401da177e4SLinus Torvalds list_del(&log->journal_list); 11411da177e4SLinus Torvalds lbmLogShutdown(log); 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds close: /* close external log device */ 1144e525fd89STejun Heo blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); 11451da177e4SLinus Torvalds 11461da177e4SLinus Torvalds free: /* free log descriptor */ 1147353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 11481da177e4SLinus Torvalds kfree(log); 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds jfs_warn("lmLogOpen: exit(%d)", rc); 11511da177e4SLinus Torvalds return rc; 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds static int open_inline_log(struct super_block *sb) 11551da177e4SLinus Torvalds { 11561da177e4SLinus Torvalds struct jfs_log *log; 11571da177e4SLinus Torvalds int rc; 11581da177e4SLinus Torvalds 11595b3030e3SEric Sesterhenn if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) 11601da177e4SLinus Torvalds return -ENOMEM; 11611da177e4SLinus Torvalds INIT_LIST_HEAD(&log->sb_list); 11621da177e4SLinus Torvalds init_waitqueue_head(&log->syncwait); 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds set_bit(log_INLINELOG, &log->flag); 11651da177e4SLinus Torvalds log->bdev = sb->s_bdev; 11661da177e4SLinus Torvalds log->base = addressPXD(&JFS_SBI(sb)->logpxd); 11671da177e4SLinus Torvalds log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >> 11681da177e4SLinus Torvalds (L2LOGPSIZE - sb->s_blocksize_bits); 11691da177e4SLinus Torvalds log->l2bsize = sb->s_blocksize_bits; 11701da177e4SLinus Torvalds ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits); 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds /* 11731da177e4SLinus Torvalds * initialize log. 11741da177e4SLinus Torvalds */ 11751da177e4SLinus Torvalds if ((rc = lmLogInit(log))) { 11761da177e4SLinus Torvalds kfree(log); 11771da177e4SLinus Torvalds jfs_warn("lmLogOpen: exit(%d)", rc); 11781da177e4SLinus Torvalds return rc; 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds list_add(&JFS_SBI(sb)->log_list, &log->sb_list); 11821da177e4SLinus Torvalds JFS_SBI(sb)->log = log; 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds return rc; 11851da177e4SLinus Torvalds } 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds static int open_dummy_log(struct super_block *sb) 11881da177e4SLinus Torvalds { 11891da177e4SLinus Torvalds int rc; 11901da177e4SLinus Torvalds 1191353ab6e9SIngo Molnar mutex_lock(&jfs_log_mutex); 11921da177e4SLinus Torvalds if (!dummy_log) { 11935b3030e3SEric Sesterhenn dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL); 11941da177e4SLinus Torvalds if (!dummy_log) { 1195353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 11961da177e4SLinus Torvalds return -ENOMEM; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds INIT_LIST_HEAD(&dummy_log->sb_list); 11991da177e4SLinus Torvalds init_waitqueue_head(&dummy_log->syncwait); 12001da177e4SLinus Torvalds dummy_log->no_integrity = 1; 12011da177e4SLinus Torvalds /* Make up some stuff */ 12021da177e4SLinus Torvalds dummy_log->base = 0; 12031da177e4SLinus Torvalds dummy_log->size = 1024; 12041da177e4SLinus Torvalds rc = lmLogInit(dummy_log); 12051da177e4SLinus Torvalds if (rc) { 12061da177e4SLinus Torvalds kfree(dummy_log); 12071da177e4SLinus Torvalds dummy_log = NULL; 1208353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 12091da177e4SLinus Torvalds return rc; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds LOG_LOCK(dummy_log); 12141da177e4SLinus Torvalds list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list); 12151da177e4SLinus Torvalds JFS_SBI(sb)->log = dummy_log; 12161da177e4SLinus Torvalds LOG_UNLOCK(dummy_log); 1217353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds return 0; 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds /* 12231da177e4SLinus Torvalds * NAME: lmLogInit() 12241da177e4SLinus Torvalds * 12251da177e4SLinus Torvalds * FUNCTION: log initialization at first log open. 12261da177e4SLinus Torvalds * 12271da177e4SLinus Torvalds * logredo() (or logformat()) should have been run previously. 12281da177e4SLinus Torvalds * initialize the log from log superblock. 12291da177e4SLinus Torvalds * set the log state in the superblock to LOGMOUNT and 12301da177e4SLinus Torvalds * write SYNCPT log record. 12311da177e4SLinus Torvalds * 12321da177e4SLinus Torvalds * PARAMETER: log - log structure 12331da177e4SLinus Torvalds * 12341da177e4SLinus Torvalds * RETURN: 0 - if ok 12351da177e4SLinus Torvalds * -EINVAL - bad log magic number or superblock dirty 12361da177e4SLinus Torvalds * error returned from logwait() 12371da177e4SLinus Torvalds * 12381da177e4SLinus Torvalds * serialization: single first open thread 12391da177e4SLinus Torvalds */ 12401da177e4SLinus Torvalds int lmLogInit(struct jfs_log * log) 12411da177e4SLinus Torvalds { 12421da177e4SLinus Torvalds int rc = 0; 12431da177e4SLinus Torvalds struct lrd lrd; 12441da177e4SLinus Torvalds struct logsuper *logsuper; 12451da177e4SLinus Torvalds struct lbuf *bpsuper; 12461da177e4SLinus Torvalds struct lbuf *bp; 12471da177e4SLinus Torvalds struct logpage *lp; 12481da177e4SLinus Torvalds int lsn = 0; 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds jfs_info("lmLogInit: log:0x%p", log); 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds /* initialize the group commit serialization lock */ 12531da177e4SLinus Torvalds LOGGC_LOCK_INIT(log); 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds /* allocate/initialize the log write serialization lock */ 12561da177e4SLinus Torvalds LOG_LOCK_INIT(log); 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds LOGSYNC_LOCK_INIT(log); 12591da177e4SLinus Torvalds 12601da177e4SLinus Torvalds INIT_LIST_HEAD(&log->synclist); 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds INIT_LIST_HEAD(&log->cqueue); 12631da177e4SLinus Torvalds log->flush_tblk = NULL; 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds log->count = 0; 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds /* 12681da177e4SLinus Torvalds * initialize log i/o 12691da177e4SLinus Torvalds */ 12701da177e4SLinus Torvalds if ((rc = lbmLogInit(log))) 12711da177e4SLinus Torvalds return rc; 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds if (!test_bit(log_INLINELOG, &log->flag)) 12741da177e4SLinus Torvalds log->l2bsize = L2LOGPSIZE; 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds /* check for disabled journaling to disk */ 12771da177e4SLinus Torvalds if (log->no_integrity) { 12781da177e4SLinus Torvalds /* 12791da177e4SLinus Torvalds * Journal pages will still be filled. When the time comes 12801da177e4SLinus Torvalds * to actually do the I/O, the write is not done, and the 12811da177e4SLinus Torvalds * endio routine is called directly. 12821da177e4SLinus Torvalds */ 12831da177e4SLinus Torvalds bp = lbmAllocate(log , 0); 12841da177e4SLinus Torvalds log->bp = bp; 12851da177e4SLinus Torvalds bp->l_pn = bp->l_eor = 0; 12861da177e4SLinus Torvalds } else { 12871da177e4SLinus Torvalds /* 12881da177e4SLinus Torvalds * validate log superblock 12891da177e4SLinus Torvalds */ 12901da177e4SLinus Torvalds if ((rc = lbmRead(log, 1, &bpsuper))) 12911da177e4SLinus Torvalds goto errout10; 12921da177e4SLinus Torvalds 12931da177e4SLinus Torvalds logsuper = (struct logsuper *) bpsuper->l_ldata; 12941da177e4SLinus Torvalds 12951da177e4SLinus Torvalds if (logsuper->magic != cpu_to_le32(LOGMAGIC)) { 12961da177e4SLinus Torvalds jfs_warn("*** Log Format Error ! ***"); 12971da177e4SLinus Torvalds rc = -EINVAL; 12981da177e4SLinus Torvalds goto errout20; 12991da177e4SLinus Torvalds } 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds /* logredo() should have been run successfully. */ 13021da177e4SLinus Torvalds if (logsuper->state != cpu_to_le32(LOGREDONE)) { 13031da177e4SLinus Torvalds jfs_warn("*** Log Is Dirty ! ***"); 13041da177e4SLinus Torvalds rc = -EINVAL; 13051da177e4SLinus Torvalds goto errout20; 13061da177e4SLinus Torvalds } 13071da177e4SLinus Torvalds 13081da177e4SLinus Torvalds /* initialize log from log superblock */ 13091da177e4SLinus Torvalds if (test_bit(log_INLINELOG,&log->flag)) { 13101da177e4SLinus Torvalds if (log->size != le32_to_cpu(logsuper->size)) { 13111da177e4SLinus Torvalds rc = -EINVAL; 13121da177e4SLinus Torvalds goto errout20; 13131da177e4SLinus Torvalds } 13146ed71e98SJoe Perches jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x", 13156ed71e98SJoe Perches log, (unsigned long long)log->base, log->size); 13161da177e4SLinus Torvalds } else { 13172e3bc612SAndy Shevchenko if (!uuid_equal(&logsuper->uuid, &log->uuid)) { 13181da177e4SLinus Torvalds jfs_warn("wrong uuid on JFS log device"); 131949210933SJiapeng Chong rc = -EINVAL; 13201da177e4SLinus Torvalds goto errout20; 13211da177e4SLinus Torvalds } 13221da177e4SLinus Torvalds log->size = le32_to_cpu(logsuper->size); 13231da177e4SLinus Torvalds log->l2bsize = le32_to_cpu(logsuper->l2bsize); 13246ed71e98SJoe Perches jfs_info("lmLogInit: external log:0x%p base:0x%Lx size:0x%x", 13256ed71e98SJoe Perches log, (unsigned long long)log->base, log->size); 13261da177e4SLinus Torvalds } 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds log->page = le32_to_cpu(logsuper->end) / LOGPSIZE; 13291da177e4SLinus Torvalds log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page); 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds /* 13321da177e4SLinus Torvalds * initialize for log append write mode 13331da177e4SLinus Torvalds */ 13341da177e4SLinus Torvalds /* establish current/end-of-log page/buffer */ 13351da177e4SLinus Torvalds if ((rc = lbmRead(log, log->page, &bp))) 13361da177e4SLinus Torvalds goto errout20; 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds jfs_info("lmLogInit: lsn:0x%x page:%d eor:%d:%d", 13411da177e4SLinus Torvalds le32_to_cpu(logsuper->end), log->page, log->eor, 13421da177e4SLinus Torvalds le16_to_cpu(lp->h.eor)); 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds log->bp = bp; 13451da177e4SLinus Torvalds bp->l_pn = log->page; 13461da177e4SLinus Torvalds bp->l_eor = log->eor; 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds /* if current page is full, move on to next page */ 13491da177e4SLinus Torvalds if (log->eor >= LOGPSIZE - LOGPTLRSIZE) 13501da177e4SLinus Torvalds lmNextPage(log); 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds /* 13531da177e4SLinus Torvalds * initialize log syncpoint 13541da177e4SLinus Torvalds */ 13551da177e4SLinus Torvalds /* 13561da177e4SLinus Torvalds * write the first SYNCPT record with syncpoint = 0 13571da177e4SLinus Torvalds * (i.e., log redo up to HERE !); 13581da177e4SLinus Torvalds * remove current page from lbm write queue at end of pageout 13591da177e4SLinus Torvalds * (to write log superblock update), but do not release to 13601da177e4SLinus Torvalds * freelist; 13611da177e4SLinus Torvalds */ 13621da177e4SLinus Torvalds lrd.logtid = 0; 13631da177e4SLinus Torvalds lrd.backchain = 0; 13641da177e4SLinus Torvalds lrd.type = cpu_to_le16(LOG_SYNCPT); 13651da177e4SLinus Torvalds lrd.length = 0; 13661da177e4SLinus Torvalds lrd.log.syncpt.sync = 0; 13671da177e4SLinus Torvalds lsn = lmWriteRecord(log, NULL, &lrd, NULL); 13681da177e4SLinus Torvalds bp = log->bp; 13691da177e4SLinus Torvalds bp->l_ceor = bp->l_eor; 13701da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 13711da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 13721da177e4SLinus Torvalds lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0); 13731da177e4SLinus Torvalds if ((rc = lbmIOWait(bp, 0))) 13741da177e4SLinus Torvalds goto errout30; 13751da177e4SLinus Torvalds 13761da177e4SLinus Torvalds /* 13771da177e4SLinus Torvalds * update/write superblock 13781da177e4SLinus Torvalds */ 13791da177e4SLinus Torvalds logsuper->state = cpu_to_le32(LOGMOUNT); 13801da177e4SLinus Torvalds log->serial = le32_to_cpu(logsuper->serial) + 1; 13811da177e4SLinus Torvalds logsuper->serial = cpu_to_le32(log->serial); 13821da177e4SLinus Torvalds lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 13831da177e4SLinus Torvalds if ((rc = lbmIOWait(bpsuper, lbmFREE))) 13841da177e4SLinus Torvalds goto errout30; 13851da177e4SLinus Torvalds } 13861da177e4SLinus Torvalds 13871da177e4SLinus Torvalds /* initialize logsync parameters */ 13881da177e4SLinus Torvalds log->logsize = (log->size - 2) << L2LOGPSIZE; 13891da177e4SLinus Torvalds log->lsn = lsn; 13901da177e4SLinus Torvalds log->syncpt = lsn; 13911da177e4SLinus Torvalds log->sync = log->syncpt; 13921da177e4SLinus Torvalds log->nextsync = LOGSYNC_DELTA(log->logsize); 13931da177e4SLinus Torvalds 13941da177e4SLinus Torvalds jfs_info("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x", 13951da177e4SLinus Torvalds log->lsn, log->syncpt, log->sync); 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds /* 13981da177e4SLinus Torvalds * initialize for lazy/group commit 13991da177e4SLinus Torvalds */ 14001da177e4SLinus Torvalds log->clsn = lsn; 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds return 0; 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds /* 14051da177e4SLinus Torvalds * unwind on error 14061da177e4SLinus Torvalds */ 14071da177e4SLinus Torvalds errout30: /* release log page */ 14081da177e4SLinus Torvalds log->wqueue = NULL; 14091da177e4SLinus Torvalds bp->l_wqnext = NULL; 14101da177e4SLinus Torvalds lbmFree(bp); 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds errout20: /* release log superblock */ 14131da177e4SLinus Torvalds lbmFree(bpsuper); 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds errout10: /* unwind lbmLogInit() */ 14161da177e4SLinus Torvalds lbmLogShutdown(log); 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds jfs_warn("lmLogInit: exit(%d)", rc); 14191da177e4SLinus Torvalds return rc; 14201da177e4SLinus Torvalds } 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds /* 14241da177e4SLinus Torvalds * NAME: lmLogClose() 14251da177e4SLinus Torvalds * 14261da177e4SLinus Torvalds * FUNCTION: remove file system <ipmnt> from active list of log <iplog> 14271da177e4SLinus Torvalds * and close it on last close. 14281da177e4SLinus Torvalds * 14291da177e4SLinus Torvalds * PARAMETER: sb - superblock 14301da177e4SLinus Torvalds * 14311da177e4SLinus Torvalds * RETURN: errors from subroutines 14321da177e4SLinus Torvalds * 14331da177e4SLinus Torvalds * serialization: 14341da177e4SLinus Torvalds */ 14351da177e4SLinus Torvalds int lmLogClose(struct super_block *sb) 14361da177e4SLinus Torvalds { 14371da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb); 14381da177e4SLinus Torvalds struct jfs_log *log = sbi->log; 14391da177e4SLinus Torvalds struct block_device *bdev; 14401da177e4SLinus Torvalds int rc = 0; 14411da177e4SLinus Torvalds 14421da177e4SLinus Torvalds jfs_info("lmLogClose: log:0x%p", log); 14431da177e4SLinus Torvalds 1444353ab6e9SIngo Molnar mutex_lock(&jfs_log_mutex); 14451da177e4SLinus Torvalds LOG_LOCK(log); 14461da177e4SLinus Torvalds list_del(&sbi->log_list); 14471da177e4SLinus Torvalds LOG_UNLOCK(log); 14481da177e4SLinus Torvalds sbi->log = NULL; 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds /* 14511da177e4SLinus Torvalds * We need to make sure all of the "written" metapages 14521da177e4SLinus Torvalds * actually make it to disk 14531da177e4SLinus Torvalds */ 14541da177e4SLinus Torvalds sync_blockdev(sb->s_bdev); 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds if (test_bit(log_INLINELOG, &log->flag)) { 14571da177e4SLinus Torvalds /* 14581da177e4SLinus Torvalds * in-line log in host file system 14591da177e4SLinus Torvalds */ 14601da177e4SLinus Torvalds rc = lmLogShutdown(log); 14611da177e4SLinus Torvalds kfree(log); 14621da177e4SLinus Torvalds goto out; 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds if (!log->no_integrity) 14661da177e4SLinus Torvalds lmLogFileSystem(log, sbi, 0); 14671da177e4SLinus Torvalds 14681da177e4SLinus Torvalds if (!list_empty(&log->sb_list)) 14691da177e4SLinus Torvalds goto out; 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds /* 14721da177e4SLinus Torvalds * TODO: ensure that the dummy_log is in a state to allow 14731da177e4SLinus Torvalds * lbmLogShutdown to deallocate all the buffers and call 14741da177e4SLinus Torvalds * kfree against dummy_log. For now, leave dummy_log & its 14751da177e4SLinus Torvalds * buffers in memory, and resuse if another no-integrity mount 14761da177e4SLinus Torvalds * is requested. 14771da177e4SLinus Torvalds */ 14781da177e4SLinus Torvalds if (log->no_integrity) 14791da177e4SLinus Torvalds goto out; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds /* 14821da177e4SLinus Torvalds * external log as separate logical volume 14831da177e4SLinus Torvalds */ 14841da177e4SLinus Torvalds list_del(&log->journal_list); 14851da177e4SLinus Torvalds bdev = log->bdev; 14861da177e4SLinus Torvalds rc = lmLogShutdown(log); 14871da177e4SLinus Torvalds 1488e525fd89STejun Heo blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds kfree(log); 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds out: 1493353ab6e9SIngo Molnar mutex_unlock(&jfs_log_mutex); 14941da177e4SLinus Torvalds jfs_info("lmLogClose: exit(%d)", rc); 14951da177e4SLinus Torvalds return rc; 14961da177e4SLinus Torvalds } 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds 14991da177e4SLinus Torvalds /* 15001da177e4SLinus Torvalds * NAME: jfs_flush_journal() 15011da177e4SLinus Torvalds * 15021da177e4SLinus Torvalds * FUNCTION: initiate write of any outstanding transactions to the journal 15031da177e4SLinus Torvalds * and optionally wait until they are all written to disk 15041da177e4SLinus Torvalds * 15051da177e4SLinus Torvalds * wait == 0 flush until latest txn is committed, don't wait 15061da177e4SLinus Torvalds * wait == 1 flush until latest txn is committed, wait 15071da177e4SLinus Torvalds * wait > 1 flush until all txn's are complete, wait 15081da177e4SLinus Torvalds */ 15091da177e4SLinus Torvalds void jfs_flush_journal(struct jfs_log *log, int wait) 15101da177e4SLinus Torvalds { 15111da177e4SLinus Torvalds int i; 15121da177e4SLinus Torvalds struct tblock *target = NULL; 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds /* jfs_write_inode may call us during read-only mount */ 15151da177e4SLinus Torvalds if (!log) 15161da177e4SLinus Torvalds return; 15171da177e4SLinus Torvalds 15181da177e4SLinus Torvalds jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait); 15191da177e4SLinus Torvalds 15201da177e4SLinus Torvalds LOGGC_LOCK(log); 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds if (!list_empty(&log->cqueue)) { 15231da177e4SLinus Torvalds /* 15241da177e4SLinus Torvalds * This ensures that we will keep writing to the journal as long 15251da177e4SLinus Torvalds * as there are unwritten commit records 15261da177e4SLinus Torvalds */ 15271da177e4SLinus Torvalds target = list_entry(log->cqueue.prev, struct tblock, cqueue); 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds if (test_bit(log_FLUSH, &log->flag)) { 15301da177e4SLinus Torvalds /* 15311da177e4SLinus Torvalds * We're already flushing. 15321da177e4SLinus Torvalds * if flush_tblk is NULL, we are flushing everything, 15331da177e4SLinus Torvalds * so leave it that way. Otherwise, update it to the 15341da177e4SLinus Torvalds * latest transaction 15351da177e4SLinus Torvalds */ 15361da177e4SLinus Torvalds if (log->flush_tblk) 15371da177e4SLinus Torvalds log->flush_tblk = target; 15381da177e4SLinus Torvalds } else { 15391da177e4SLinus Torvalds /* Only flush until latest transaction is committed */ 15401da177e4SLinus Torvalds log->flush_tblk = target; 15411da177e4SLinus Torvalds set_bit(log_FLUSH, &log->flag); 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds /* 15441da177e4SLinus Torvalds * Initiate I/O on outstanding transactions 15451da177e4SLinus Torvalds */ 15461da177e4SLinus Torvalds if (!(log->cflag & logGC_PAGEOUT)) { 15471da177e4SLinus Torvalds log->cflag |= logGC_PAGEOUT; 15481da177e4SLinus Torvalds lmGCwrite(log, 0); 15491da177e4SLinus Torvalds } 15501da177e4SLinus Torvalds } 15511da177e4SLinus Torvalds } 15521da177e4SLinus Torvalds if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) { 15531da177e4SLinus Torvalds /* Flush until all activity complete */ 15541da177e4SLinus Torvalds set_bit(log_FLUSH, &log->flag); 15551da177e4SLinus Torvalds log->flush_tblk = NULL; 15561da177e4SLinus Torvalds } 15571da177e4SLinus Torvalds 15581da177e4SLinus Torvalds if (wait && target && !(target->flag & tblkGC_COMMITTED)) { 15591da177e4SLinus Torvalds DECLARE_WAITQUEUE(__wait, current); 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds add_wait_queue(&target->gcwait, &__wait); 15621da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 15631da177e4SLinus Torvalds LOGGC_UNLOCK(log); 15641da177e4SLinus Torvalds schedule(); 15651da177e4SLinus Torvalds LOGGC_LOCK(log); 15661da177e4SLinus Torvalds remove_wait_queue(&target->gcwait, &__wait); 15671da177e4SLinus Torvalds } 15681da177e4SLinus Torvalds LOGGC_UNLOCK(log); 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds if (wait < 2) 15711da177e4SLinus Torvalds return; 15721da177e4SLinus Torvalds 157367e6682fSDave Kleikamp write_special_inodes(log, filemap_fdatawrite); 15747fab479bSDave Kleikamp 15751da177e4SLinus Torvalds /* 15761da177e4SLinus Torvalds * If there was recent activity, we may need to wait 15771da177e4SLinus Torvalds * for the lazycommit thread to catch up 15781da177e4SLinus Torvalds */ 15791da177e4SLinus Torvalds if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { 15807fab479bSDave Kleikamp for (i = 0; i < 200; i++) { /* Too much? */ 15811da177e4SLinus Torvalds msleep(250); 158267e6682fSDave Kleikamp write_special_inodes(log, filemap_fdatawrite); 15831da177e4SLinus Torvalds if (list_empty(&log->cqueue) && 15841da177e4SLinus Torvalds list_empty(&log->synclist)) 15851da177e4SLinus Torvalds break; 15861da177e4SLinus Torvalds } 15871da177e4SLinus Torvalds } 15881da177e4SLinus Torvalds assert(list_empty(&log->cqueue)); 158972e3148aSDave Kleikamp 159072e3148aSDave Kleikamp #ifdef CONFIG_JFS_DEBUG 15917fab479bSDave Kleikamp if (!list_empty(&log->synclist)) { 15927fab479bSDave Kleikamp struct logsyncblk *lp; 15937fab479bSDave Kleikamp 1594209e101bSDave Kleikamp printk(KERN_ERR "jfs_flush_journal: synclist not empty\n"); 15957fab479bSDave Kleikamp list_for_each_entry(lp, &log->synclist, synclist) { 15967fab479bSDave Kleikamp if (lp->xflag & COMMIT_PAGE) { 15977fab479bSDave Kleikamp struct metapage *mp = (struct metapage *)lp; 1598288e4d83SDave Kleikamp print_hex_dump(KERN_ERR, "metapage: ", 1599288e4d83SDave Kleikamp DUMP_PREFIX_ADDRESS, 16, 4, 1600288e4d83SDave Kleikamp mp, sizeof(struct metapage), 0); 1601288e4d83SDave Kleikamp print_hex_dump(KERN_ERR, "page: ", 1602288e4d83SDave Kleikamp DUMP_PREFIX_ADDRESS, 16, 1603288e4d83SDave Kleikamp sizeof(long), mp->page, 1604288e4d83SDave Kleikamp sizeof(struct page), 0); 1605288e4d83SDave Kleikamp } else 1606288e4d83SDave Kleikamp print_hex_dump(KERN_ERR, "tblock:", 1607288e4d83SDave Kleikamp DUMP_PREFIX_ADDRESS, 16, 4, 1608288e4d83SDave Kleikamp lp, sizeof(struct tblock), 0); 1609209e101bSDave Kleikamp } 16107fab479bSDave Kleikamp } 1611288e4d83SDave Kleikamp #else 1612288e4d83SDave Kleikamp WARN_ON(!list_empty(&log->synclist)); 161372e3148aSDave Kleikamp #endif 16141da177e4SLinus Torvalds clear_bit(log_FLUSH, &log->flag); 16151da177e4SLinus Torvalds } 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds /* 16181da177e4SLinus Torvalds * NAME: lmLogShutdown() 16191da177e4SLinus Torvalds * 16201da177e4SLinus Torvalds * FUNCTION: log shutdown at last LogClose(). 16211da177e4SLinus Torvalds * 16221da177e4SLinus Torvalds * write log syncpt record. 16231da177e4SLinus Torvalds * update super block to set redone flag to 0. 16241da177e4SLinus Torvalds * 16251da177e4SLinus Torvalds * PARAMETER: log - log inode 16261da177e4SLinus Torvalds * 16271da177e4SLinus Torvalds * RETURN: 0 - success 16281da177e4SLinus Torvalds * 16291da177e4SLinus Torvalds * serialization: single last close thread 16301da177e4SLinus Torvalds */ 16311da177e4SLinus Torvalds int lmLogShutdown(struct jfs_log * log) 16321da177e4SLinus Torvalds { 16331da177e4SLinus Torvalds int rc; 16341da177e4SLinus Torvalds struct lrd lrd; 16351da177e4SLinus Torvalds int lsn; 16361da177e4SLinus Torvalds struct logsuper *logsuper; 16371da177e4SLinus Torvalds struct lbuf *bpsuper; 16381da177e4SLinus Torvalds struct lbuf *bp; 16391da177e4SLinus Torvalds struct logpage *lp; 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds jfs_info("lmLogShutdown: log:0x%p", log); 16421da177e4SLinus Torvalds 16431da177e4SLinus Torvalds jfs_flush_journal(log, 2); 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds /* 16461da177e4SLinus Torvalds * write the last SYNCPT record with syncpoint = 0 16471da177e4SLinus Torvalds * (i.e., log redo up to HERE !) 16481da177e4SLinus Torvalds */ 16491da177e4SLinus Torvalds lrd.logtid = 0; 16501da177e4SLinus Torvalds lrd.backchain = 0; 16511da177e4SLinus Torvalds lrd.type = cpu_to_le16(LOG_SYNCPT); 16521da177e4SLinus Torvalds lrd.length = 0; 16531da177e4SLinus Torvalds lrd.log.syncpt.sync = 0; 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds lsn = lmWriteRecord(log, NULL, &lrd, NULL); 16561da177e4SLinus Torvalds bp = log->bp; 16571da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 16581da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 16591da177e4SLinus Torvalds lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0); 16601da177e4SLinus Torvalds lbmIOWait(log->bp, lbmFREE); 1661dc5798d9SDave Kleikamp log->bp = NULL; 16621da177e4SLinus Torvalds 16631da177e4SLinus Torvalds /* 16641da177e4SLinus Torvalds * synchronous update log superblock 16651da177e4SLinus Torvalds * mark log state as shutdown cleanly 16661da177e4SLinus Torvalds * (i.e., Log does not need to be replayed). 16671da177e4SLinus Torvalds */ 16681da177e4SLinus Torvalds if ((rc = lbmRead(log, 1, &bpsuper))) 16691da177e4SLinus Torvalds goto out; 16701da177e4SLinus Torvalds 16711da177e4SLinus Torvalds logsuper = (struct logsuper *) bpsuper->l_ldata; 16721da177e4SLinus Torvalds logsuper->state = cpu_to_le32(LOGREDONE); 16731da177e4SLinus Torvalds logsuper->end = cpu_to_le32(lsn); 16741da177e4SLinus Torvalds lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 16751da177e4SLinus Torvalds rc = lbmIOWait(bpsuper, lbmFREE); 16761da177e4SLinus Torvalds 16771da177e4SLinus Torvalds jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d", 16781da177e4SLinus Torvalds lsn, log->page, log->eor); 16791da177e4SLinus Torvalds 16801da177e4SLinus Torvalds out: 16811da177e4SLinus Torvalds /* 16821da177e4SLinus Torvalds * shutdown per log i/o 16831da177e4SLinus Torvalds */ 16841da177e4SLinus Torvalds lbmLogShutdown(log); 16851da177e4SLinus Torvalds 16861da177e4SLinus Torvalds if (rc) { 16871da177e4SLinus Torvalds jfs_warn("lmLogShutdown: exit(%d)", rc); 16881da177e4SLinus Torvalds } 16891da177e4SLinus Torvalds return rc; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds /* 16941da177e4SLinus Torvalds * NAME: lmLogFileSystem() 16951da177e4SLinus Torvalds * 16961da177e4SLinus Torvalds * FUNCTION: insert (<activate> = true)/remove (<activate> = false) 16971da177e4SLinus Torvalds * file system into/from log active file system list. 16981da177e4SLinus Torvalds * 16991da177e4SLinus Torvalds * PARAMETE: log - pointer to logs inode. 17001da177e4SLinus Torvalds * fsdev - kdev_t of filesystem. 17011da177e4SLinus Torvalds * serial - pointer to returned log serial number 17021da177e4SLinus Torvalds * activate - insert/remove device from active list. 17031da177e4SLinus Torvalds * 17041da177e4SLinus Torvalds * RETURN: 0 - success 17051da177e4SLinus Torvalds * errors returned by vms_iowait(). 17061da177e4SLinus Torvalds */ 17071da177e4SLinus Torvalds static int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi, 17081da177e4SLinus Torvalds int activate) 17091da177e4SLinus Torvalds { 17101da177e4SLinus Torvalds int rc = 0; 17111da177e4SLinus Torvalds int i; 17121da177e4SLinus Torvalds struct logsuper *logsuper; 17131da177e4SLinus Torvalds struct lbuf *bpsuper; 17142e3bc612SAndy Shevchenko uuid_t *uuid = &sbi->uuid; 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds /* 17171da177e4SLinus Torvalds * insert/remove file system device to log active file system list. 17181da177e4SLinus Torvalds */ 17191da177e4SLinus Torvalds if ((rc = lbmRead(log, 1, &bpsuper))) 17201da177e4SLinus Torvalds return rc; 17211da177e4SLinus Torvalds 17221da177e4SLinus Torvalds logsuper = (struct logsuper *) bpsuper->l_ldata; 17231da177e4SLinus Torvalds if (activate) { 17241da177e4SLinus Torvalds for (i = 0; i < MAX_ACTIVE; i++) 17252e3bc612SAndy Shevchenko if (uuid_is_null(&logsuper->active[i].uuid)) { 17262e3bc612SAndy Shevchenko uuid_copy(&logsuper->active[i].uuid, uuid); 17271da177e4SLinus Torvalds sbi->aggregate = i; 17281da177e4SLinus Torvalds break; 17291da177e4SLinus Torvalds } 17301da177e4SLinus Torvalds if (i == MAX_ACTIVE) { 17311da177e4SLinus Torvalds jfs_warn("Too many file systems sharing journal!"); 17321da177e4SLinus Torvalds lbmFree(bpsuper); 17331da177e4SLinus Torvalds return -EMFILE; /* Is there a better rc? */ 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds } else { 17361da177e4SLinus Torvalds for (i = 0; i < MAX_ACTIVE; i++) 17372e3bc612SAndy Shevchenko if (uuid_equal(&logsuper->active[i].uuid, uuid)) { 17382e3bc612SAndy Shevchenko uuid_copy(&logsuper->active[i].uuid, 17392e3bc612SAndy Shevchenko &uuid_null); 17401da177e4SLinus Torvalds break; 17411da177e4SLinus Torvalds } 17421da177e4SLinus Torvalds if (i == MAX_ACTIVE) { 17431da177e4SLinus Torvalds jfs_warn("Somebody stomped on the journal!"); 17441da177e4SLinus Torvalds lbmFree(bpsuper); 17451da177e4SLinus Torvalds return -EIO; 17461da177e4SLinus Torvalds } 17471da177e4SLinus Torvalds 17481da177e4SLinus Torvalds } 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds /* 17511da177e4SLinus Torvalds * synchronous write log superblock: 17521da177e4SLinus Torvalds * 17531da177e4SLinus Torvalds * write sidestream bypassing write queue: 17541da177e4SLinus Torvalds * at file system mount, log super block is updated for 17551da177e4SLinus Torvalds * activation of the file system before any log record 17561da177e4SLinus Torvalds * (MOUNT record) of the file system, and at file system 17571da177e4SLinus Torvalds * unmount, all meta data for the file system has been 17581da177e4SLinus Torvalds * flushed before log super block is updated for deactivation 17591da177e4SLinus Torvalds * of the file system. 17601da177e4SLinus Torvalds */ 17611da177e4SLinus Torvalds lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 17621da177e4SLinus Torvalds rc = lbmIOWait(bpsuper, lbmFREE); 17631da177e4SLinus Torvalds 17641da177e4SLinus Torvalds return rc; 17651da177e4SLinus Torvalds } 17661da177e4SLinus Torvalds 17671da177e4SLinus Torvalds /* 17681da177e4SLinus Torvalds * log buffer manager (lbm) 17691da177e4SLinus Torvalds * ------------------------ 17701da177e4SLinus Torvalds * 17711da177e4SLinus Torvalds * special purpose buffer manager supporting log i/o requirements. 17721da177e4SLinus Torvalds * 17731da177e4SLinus Torvalds * per log write queue: 17741da177e4SLinus Torvalds * log pageout occurs in serial order by fifo write queue and 17751da177e4SLinus Torvalds * restricting to a single i/o in pregress at any one time. 17761da177e4SLinus Torvalds * a circular singly-linked list 17771da177e4SLinus Torvalds * (log->wrqueue points to the tail, and buffers are linked via 17781da177e4SLinus Torvalds * bp->wrqueue field), and 17791da177e4SLinus Torvalds * maintains log page in pageout ot waiting for pageout in serial pageout. 17801da177e4SLinus Torvalds */ 17811da177e4SLinus Torvalds 17821da177e4SLinus Torvalds /* 17831da177e4SLinus Torvalds * lbmLogInit() 17841da177e4SLinus Torvalds * 17851da177e4SLinus Torvalds * initialize per log I/O setup at lmLogInit() 17861da177e4SLinus Torvalds */ 17871da177e4SLinus Torvalds static int lbmLogInit(struct jfs_log * log) 17881da177e4SLinus Torvalds { /* log inode */ 17891da177e4SLinus Torvalds int i; 17901da177e4SLinus Torvalds struct lbuf *lbuf; 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds jfs_info("lbmLogInit: log:0x%p", log); 17931da177e4SLinus Torvalds 17941da177e4SLinus Torvalds /* initialize current buffer cursor */ 17951da177e4SLinus Torvalds log->bp = NULL; 17961da177e4SLinus Torvalds 17971da177e4SLinus Torvalds /* initialize log device write queue */ 17981da177e4SLinus Torvalds log->wqueue = NULL; 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds /* 18011da177e4SLinus Torvalds * Each log has its own buffer pages allocated to it. These are 18021da177e4SLinus Torvalds * not managed by the page cache. This ensures that a transaction 18031da177e4SLinus Torvalds * writing to the log does not block trying to allocate a page from 18041da177e4SLinus Torvalds * the page cache (for the log). This would be bad, since page 18051da177e4SLinus Torvalds * allocation waits on the kswapd thread that may be committing inodes 18061da177e4SLinus Torvalds * which would cause log activity. Was that clear? I'm trying to 18071da177e4SLinus Torvalds * avoid deadlock here. 18081da177e4SLinus Torvalds */ 18091da177e4SLinus Torvalds init_waitqueue_head(&log->free_wait); 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds log->lbuf_free = NULL; 18121da177e4SLinus Torvalds 1813dc5798d9SDave Kleikamp for (i = 0; i < LOGPAGES;) { 1814dc5798d9SDave Kleikamp char *buffer; 1815dc5798d9SDave Kleikamp uint offset; 181676e8d7cbSAl Viro struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO); 1817dc5798d9SDave Kleikamp 181876e8d7cbSAl Viro if (!page) 18191da177e4SLinus Torvalds goto error; 182076e8d7cbSAl Viro buffer = page_address(page); 1821dc5798d9SDave Kleikamp for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) { 1822dc5798d9SDave Kleikamp lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL); 1823dc5798d9SDave Kleikamp if (lbuf == NULL) { 1824dc5798d9SDave Kleikamp if (offset == 0) 182576e8d7cbSAl Viro __free_page(page); 18261da177e4SLinus Torvalds goto error; 18271da177e4SLinus Torvalds } 1828dc5798d9SDave Kleikamp if (offset) /* we already have one reference */ 1829dc5798d9SDave Kleikamp get_page(page); 1830dc5798d9SDave Kleikamp lbuf->l_offset = offset; 1831dc5798d9SDave Kleikamp lbuf->l_ldata = buffer + offset; 1832dc5798d9SDave Kleikamp lbuf->l_page = page; 18331da177e4SLinus Torvalds lbuf->l_log = log; 18341da177e4SLinus Torvalds init_waitqueue_head(&lbuf->l_ioevent); 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds lbuf->l_freelist = log->lbuf_free; 18371da177e4SLinus Torvalds log->lbuf_free = lbuf; 1838dc5798d9SDave Kleikamp i++; 1839dc5798d9SDave Kleikamp } 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds 18421da177e4SLinus Torvalds return (0); 18431da177e4SLinus Torvalds 18441da177e4SLinus Torvalds error: 18451da177e4SLinus Torvalds lbmLogShutdown(log); 18461da177e4SLinus Torvalds return -ENOMEM; 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds /* 18511da177e4SLinus Torvalds * lbmLogShutdown() 18521da177e4SLinus Torvalds * 18531da177e4SLinus Torvalds * finalize per log I/O setup at lmLogShutdown() 18541da177e4SLinus Torvalds */ 18551da177e4SLinus Torvalds static void lbmLogShutdown(struct jfs_log * log) 18561da177e4SLinus Torvalds { 18571da177e4SLinus Torvalds struct lbuf *lbuf; 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds jfs_info("lbmLogShutdown: log:0x%p", log); 18601da177e4SLinus Torvalds 18611da177e4SLinus Torvalds lbuf = log->lbuf_free; 18621da177e4SLinus Torvalds while (lbuf) { 18631da177e4SLinus Torvalds struct lbuf *next = lbuf->l_freelist; 1864dc5798d9SDave Kleikamp __free_page(lbuf->l_page); 18651da177e4SLinus Torvalds kfree(lbuf); 18661da177e4SLinus Torvalds lbuf = next; 18671da177e4SLinus Torvalds } 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds 18701da177e4SLinus Torvalds 18711da177e4SLinus Torvalds /* 18721da177e4SLinus Torvalds * lbmAllocate() 18731da177e4SLinus Torvalds * 18741da177e4SLinus Torvalds * allocate an empty log buffer 18751da177e4SLinus Torvalds */ 18761da177e4SLinus Torvalds static struct lbuf *lbmAllocate(struct jfs_log * log, int pn) 18771da177e4SLinus Torvalds { 18781da177e4SLinus Torvalds struct lbuf *bp; 18791da177e4SLinus Torvalds unsigned long flags; 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds /* 18821da177e4SLinus Torvalds * recycle from log buffer freelist if any 18831da177e4SLinus Torvalds */ 18841da177e4SLinus Torvalds LCACHE_LOCK(flags); 18851da177e4SLinus Torvalds LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags); 18861da177e4SLinus Torvalds log->lbuf_free = bp->l_freelist; 18871da177e4SLinus Torvalds LCACHE_UNLOCK(flags); 18881da177e4SLinus Torvalds 18891da177e4SLinus Torvalds bp->l_flag = 0; 18901da177e4SLinus Torvalds 18911da177e4SLinus Torvalds bp->l_wqnext = NULL; 18921da177e4SLinus Torvalds bp->l_freelist = NULL; 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds bp->l_pn = pn; 18951da177e4SLinus Torvalds bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize)); 18961da177e4SLinus Torvalds bp->l_ceor = 0; 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds return bp; 18991da177e4SLinus Torvalds } 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds 19021da177e4SLinus Torvalds /* 19031da177e4SLinus Torvalds * lbmFree() 19041da177e4SLinus Torvalds * 19051da177e4SLinus Torvalds * release a log buffer to freelist 19061da177e4SLinus Torvalds */ 19071da177e4SLinus Torvalds static void lbmFree(struct lbuf * bp) 19081da177e4SLinus Torvalds { 19091da177e4SLinus Torvalds unsigned long flags; 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds LCACHE_LOCK(flags); 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds lbmfree(bp); 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds LCACHE_UNLOCK(flags); 19161da177e4SLinus Torvalds } 19171da177e4SLinus Torvalds 19181da177e4SLinus Torvalds static void lbmfree(struct lbuf * bp) 19191da177e4SLinus Torvalds { 19201da177e4SLinus Torvalds struct jfs_log *log = bp->l_log; 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds assert(bp->l_wqnext == NULL); 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds /* 19251da177e4SLinus Torvalds * return the buffer to head of freelist 19261da177e4SLinus Torvalds */ 19271da177e4SLinus Torvalds bp->l_freelist = log->lbuf_free; 19281da177e4SLinus Torvalds log->lbuf_free = bp; 19291da177e4SLinus Torvalds 19301da177e4SLinus Torvalds wake_up(&log->free_wait); 19311da177e4SLinus Torvalds return; 19321da177e4SLinus Torvalds } 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds 19351da177e4SLinus Torvalds /* 19361da177e4SLinus Torvalds * NAME: lbmRedrive 19371da177e4SLinus Torvalds * 193859c51591SMichael Opdenacker * FUNCTION: add a log buffer to the log redrive list 19391da177e4SLinus Torvalds * 19401da177e4SLinus Torvalds * PARAMETER: 19411da177e4SLinus Torvalds * bp - log buffer 19421da177e4SLinus Torvalds * 19431da177e4SLinus Torvalds * NOTES: 19441da177e4SLinus Torvalds * Takes log_redrive_lock. 19451da177e4SLinus Torvalds */ 19461da177e4SLinus Torvalds static inline void lbmRedrive(struct lbuf *bp) 19471da177e4SLinus Torvalds { 19481da177e4SLinus Torvalds unsigned long flags; 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds spin_lock_irqsave(&log_redrive_lock, flags); 19511da177e4SLinus Torvalds bp->l_redrive_next = log_redrive_list; 19521da177e4SLinus Torvalds log_redrive_list = bp; 19531da177e4SLinus Torvalds spin_unlock_irqrestore(&log_redrive_lock, flags); 19541da177e4SLinus Torvalds 195591dbb4deSChristoph Hellwig wake_up_process(jfsIOthread); 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds 19591da177e4SLinus Torvalds /* 19601da177e4SLinus Torvalds * lbmRead() 19611da177e4SLinus Torvalds */ 19621da177e4SLinus Torvalds static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) 19631da177e4SLinus Torvalds { 19641da177e4SLinus Torvalds struct bio *bio; 19651da177e4SLinus Torvalds struct lbuf *bp; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds /* 19681da177e4SLinus Torvalds * allocate a log buffer 19691da177e4SLinus Torvalds */ 19701da177e4SLinus Torvalds *bpp = bp = lbmAllocate(log, pn); 19711da177e4SLinus Torvalds jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn); 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds bp->l_flag |= lbmREAD; 19741da177e4SLinus Torvalds 197507888c66SChristoph Hellwig bio = bio_alloc(log->bdev, 1, REQ_OP_READ, GFP_NOFS); 19764f024f37SKent Overstreet bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); 1977*2896db17SJohannes Thumshirn __bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset); 19786cf66b4cSKent Overstreet BUG_ON(bio->bi_iter.bi_size != LOGPSIZE); 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds bio->bi_end_io = lbmIODone; 19811da177e4SLinus Torvalds bio->bi_private = bp; 198295bbb82fSGu Zheng /*check if journaling to disk has been disabled*/ 198395bbb82fSGu Zheng if (log->no_integrity) { 19844f024f37SKent Overstreet bio->bi_iter.bi_size = 0; 19854246a0b6SChristoph Hellwig lbmIODone(bio); 198695bbb82fSGu Zheng } else { 19874e49ea4aSMike Christie submit_bio(bio); 198895bbb82fSGu Zheng } 19891da177e4SLinus Torvalds 19901da177e4SLinus Torvalds wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD)); 19911da177e4SLinus Torvalds 19921da177e4SLinus Torvalds return 0; 19931da177e4SLinus Torvalds } 19941da177e4SLinus Torvalds 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds /* 19971da177e4SLinus Torvalds * lbmWrite() 19981da177e4SLinus Torvalds * 19991da177e4SLinus Torvalds * buffer at head of pageout queue stays after completion of 20001da177e4SLinus Torvalds * partial-page pageout and redriven by explicit initiation of 20011da177e4SLinus Torvalds * pageout by caller until full-page pageout is completed and 20021da177e4SLinus Torvalds * released. 20031da177e4SLinus Torvalds * 20041da177e4SLinus Torvalds * device driver i/o done redrives pageout of new buffer at 20051da177e4SLinus Torvalds * head of pageout queue when current buffer at head of pageout 20061da177e4SLinus Torvalds * queue is released at the completion of its full-page pageout. 20071da177e4SLinus Torvalds * 20081da177e4SLinus Torvalds * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit(). 20091da177e4SLinus Torvalds * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone() 20101da177e4SLinus Torvalds */ 20111da177e4SLinus Torvalds static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, 20121da177e4SLinus Torvalds int cant_block) 20131da177e4SLinus Torvalds { 20141da177e4SLinus Torvalds struct lbuf *tail; 20151da177e4SLinus Torvalds unsigned long flags; 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds jfs_info("lbmWrite: bp:0x%p flag:0x%x pn:0x%x", bp, flag, bp->l_pn); 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds /* map the logical block address to physical block address */ 20201da177e4SLinus Torvalds bp->l_blkno = 20211da177e4SLinus Torvalds log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds LCACHE_LOCK(flags); /* disable+lock */ 20241da177e4SLinus Torvalds 20251da177e4SLinus Torvalds /* 20261da177e4SLinus Torvalds * initialize buffer for device driver 20271da177e4SLinus Torvalds */ 20281da177e4SLinus Torvalds bp->l_flag = flag; 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds /* 20311da177e4SLinus Torvalds * insert bp at tail of write queue associated with log 20321da177e4SLinus Torvalds * 20331da177e4SLinus Torvalds * (request is either for bp already/currently at head of queue 20341da177e4SLinus Torvalds * or new bp to be inserted at tail) 20351da177e4SLinus Torvalds */ 20361da177e4SLinus Torvalds tail = log->wqueue; 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds /* is buffer not already on write queue ? */ 20391da177e4SLinus Torvalds if (bp->l_wqnext == NULL) { 20401da177e4SLinus Torvalds /* insert at tail of wqueue */ 20411da177e4SLinus Torvalds if (tail == NULL) { 20421da177e4SLinus Torvalds log->wqueue = bp; 20431da177e4SLinus Torvalds bp->l_wqnext = bp; 20441da177e4SLinus Torvalds } else { 20451da177e4SLinus Torvalds log->wqueue = bp; 20461da177e4SLinus Torvalds bp->l_wqnext = tail->l_wqnext; 20471da177e4SLinus Torvalds tail->l_wqnext = bp; 20481da177e4SLinus Torvalds } 20491da177e4SLinus Torvalds 20501da177e4SLinus Torvalds tail = bp; 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds /* is buffer at head of wqueue and for write ? */ 20541da177e4SLinus Torvalds if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) { 20551da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 20561da177e4SLinus Torvalds return; 20571da177e4SLinus Torvalds } 20581da177e4SLinus Torvalds 20591da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 20601da177e4SLinus Torvalds 20611da177e4SLinus Torvalds if (cant_block) 20621da177e4SLinus Torvalds lbmRedrive(bp); 20631da177e4SLinus Torvalds else if (flag & lbmSYNC) 20641da177e4SLinus Torvalds lbmStartIO(bp); 20651da177e4SLinus Torvalds else { 20661da177e4SLinus Torvalds LOGGC_UNLOCK(log); 20671da177e4SLinus Torvalds lbmStartIO(bp); 20681da177e4SLinus Torvalds LOGGC_LOCK(log); 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds } 20711da177e4SLinus Torvalds 20721da177e4SLinus Torvalds 20731da177e4SLinus Torvalds /* 20741da177e4SLinus Torvalds * lbmDirectWrite() 20751da177e4SLinus Torvalds * 20761da177e4SLinus Torvalds * initiate pageout bypassing write queue for sidestream 20771da177e4SLinus Torvalds * (e.g., log superblock) write; 20781da177e4SLinus Torvalds */ 20791da177e4SLinus Torvalds static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag) 20801da177e4SLinus Torvalds { 20811da177e4SLinus Torvalds jfs_info("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x", 20821da177e4SLinus Torvalds bp, flag, bp->l_pn); 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds /* 20851da177e4SLinus Torvalds * initialize buffer for device driver 20861da177e4SLinus Torvalds */ 20871da177e4SLinus Torvalds bp->l_flag = flag | lbmDIRECT; 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds /* map the logical block address to physical block address */ 20901da177e4SLinus Torvalds bp->l_blkno = 20911da177e4SLinus Torvalds log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds /* 20941da177e4SLinus Torvalds * initiate pageout of the page 20951da177e4SLinus Torvalds */ 20961da177e4SLinus Torvalds lbmStartIO(bp); 20971da177e4SLinus Torvalds } 20981da177e4SLinus Torvalds 20991da177e4SLinus Torvalds 21001da177e4SLinus Torvalds /* 21011da177e4SLinus Torvalds * NAME: lbmStartIO() 21021da177e4SLinus Torvalds * 21031da177e4SLinus Torvalds * FUNCTION: Interface to DD strategy routine 21041da177e4SLinus Torvalds * 21051da177e4SLinus Torvalds * RETURN: none 21061da177e4SLinus Torvalds * 21071da177e4SLinus Torvalds * serialization: LCACHE_LOCK() is NOT held during log i/o; 21081da177e4SLinus Torvalds */ 21091da177e4SLinus Torvalds static void lbmStartIO(struct lbuf * bp) 21101da177e4SLinus Torvalds { 21111da177e4SLinus Torvalds struct bio *bio; 21121da177e4SLinus Torvalds struct jfs_log *log = bp->l_log; 21131da177e4SLinus Torvalds 2114b18db6deSJoe Perches jfs_info("lbmStartIO"); 21151da177e4SLinus Torvalds 211607888c66SChristoph Hellwig bio = bio_alloc(log->bdev, 1, REQ_OP_WRITE | REQ_SYNC, GFP_NOFS); 21174f024f37SKent Overstreet bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); 2118*2896db17SJohannes Thumshirn __bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset); 21196cf66b4cSKent Overstreet BUG_ON(bio->bi_iter.bi_size != LOGPSIZE); 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds bio->bi_end_io = lbmIODone; 21221da177e4SLinus Torvalds bio->bi_private = bp; 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds /* check if journaling to disk has been disabled */ 2125dc5798d9SDave Kleikamp if (log->no_integrity) { 21264f024f37SKent Overstreet bio->bi_iter.bi_size = 0; 21274246a0b6SChristoph Hellwig lbmIODone(bio); 2128dc5798d9SDave Kleikamp } else { 21294e49ea4aSMike Christie submit_bio(bio); 21301da177e4SLinus Torvalds INCREMENT(lmStat.submitted); 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds } 21331da177e4SLinus Torvalds 21341da177e4SLinus Torvalds 21351da177e4SLinus Torvalds /* 21361da177e4SLinus Torvalds * lbmIOWait() 21371da177e4SLinus Torvalds */ 21381da177e4SLinus Torvalds static int lbmIOWait(struct lbuf * bp, int flag) 21391da177e4SLinus Torvalds { 21401da177e4SLinus Torvalds unsigned long flags; 21411da177e4SLinus Torvalds int rc = 0; 21421da177e4SLinus Torvalds 21431da177e4SLinus Torvalds jfs_info("lbmIOWait1: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag); 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds LCACHE_LOCK(flags); /* disable+lock */ 21461da177e4SLinus Torvalds 21471da177e4SLinus Torvalds LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags); 21481da177e4SLinus Torvalds 21491da177e4SLinus Torvalds rc = (bp->l_flag & lbmERROR) ? -EIO : 0; 21501da177e4SLinus Torvalds 21511da177e4SLinus Torvalds if (flag & lbmFREE) 21521da177e4SLinus Torvalds lbmfree(bp); 21531da177e4SLinus Torvalds 21541da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 21551da177e4SLinus Torvalds 21561da177e4SLinus Torvalds jfs_info("lbmIOWait2: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag); 21571da177e4SLinus Torvalds return rc; 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds 21601da177e4SLinus Torvalds /* 21611da177e4SLinus Torvalds * lbmIODone() 21621da177e4SLinus Torvalds * 21631da177e4SLinus Torvalds * executed at INTIODONE level 21641da177e4SLinus Torvalds */ 21654246a0b6SChristoph Hellwig static void lbmIODone(struct bio *bio) 21661da177e4SLinus Torvalds { 21671da177e4SLinus Torvalds struct lbuf *bp = bio->bi_private; 21681da177e4SLinus Torvalds struct lbuf *nextbp, *tail; 21691da177e4SLinus Torvalds struct jfs_log *log; 21701da177e4SLinus Torvalds unsigned long flags; 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds /* 21731da177e4SLinus Torvalds * get back jfs buffer bound to the i/o buffer 21741da177e4SLinus Torvalds */ 21751da177e4SLinus Torvalds jfs_info("lbmIODone: bp:0x%p flag:0x%x", bp, bp->l_flag); 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds LCACHE_LOCK(flags); /* disable+lock */ 21781da177e4SLinus Torvalds 21791da177e4SLinus Torvalds bp->l_flag |= lbmDONE; 21801da177e4SLinus Torvalds 21814e4cbee9SChristoph Hellwig if (bio->bi_status) { 21821da177e4SLinus Torvalds bp->l_flag |= lbmERROR; 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds jfs_err("lbmIODone: I/O error in JFS log"); 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds bio_put(bio); 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds /* 21901da177e4SLinus Torvalds * pagein completion 21911da177e4SLinus Torvalds */ 21921da177e4SLinus Torvalds if (bp->l_flag & lbmREAD) { 21931da177e4SLinus Torvalds bp->l_flag &= ~lbmREAD; 21941da177e4SLinus Torvalds 21951da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 21961da177e4SLinus Torvalds 21971da177e4SLinus Torvalds /* wakeup I/O initiator */ 21981da177e4SLinus Torvalds LCACHE_WAKEUP(&bp->l_ioevent); 21998d8fe642SDave Kleikamp 22008d8fe642SDave Kleikamp return; 22011da177e4SLinus Torvalds } 22021da177e4SLinus Torvalds 22031da177e4SLinus Torvalds /* 22041da177e4SLinus Torvalds * pageout completion 22051da177e4SLinus Torvalds * 22061da177e4SLinus Torvalds * the bp at the head of write queue has completed pageout. 22071da177e4SLinus Torvalds * 22081da177e4SLinus Torvalds * if single-commit/full-page pageout, remove the current buffer 22091da177e4SLinus Torvalds * from head of pageout queue, and redrive pageout with 22101da177e4SLinus Torvalds * the new buffer at head of pageout queue; 22111da177e4SLinus Torvalds * otherwise, the partial-page pageout buffer stays at 22121da177e4SLinus Torvalds * the head of pageout queue to be redriven for pageout 22131da177e4SLinus Torvalds * by lmGroupCommit() until full-page pageout is completed. 22141da177e4SLinus Torvalds */ 22151da177e4SLinus Torvalds bp->l_flag &= ~lbmWRITE; 22161da177e4SLinus Torvalds INCREMENT(lmStat.pagedone); 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds /* update committed lsn */ 22191da177e4SLinus Torvalds log = bp->l_log; 22201da177e4SLinus Torvalds log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor; 22211da177e4SLinus Torvalds 22221da177e4SLinus Torvalds if (bp->l_flag & lbmDIRECT) { 22231da177e4SLinus Torvalds LCACHE_WAKEUP(&bp->l_ioevent); 22241da177e4SLinus Torvalds LCACHE_UNLOCK(flags); 22258d8fe642SDave Kleikamp return; 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds tail = log->wqueue; 22291da177e4SLinus Torvalds 22301da177e4SLinus Torvalds /* single element queue */ 22311da177e4SLinus Torvalds if (bp == tail) { 22321da177e4SLinus Torvalds /* remove head buffer of full-page pageout 22331da177e4SLinus Torvalds * from log device write queue 22341da177e4SLinus Torvalds */ 22351da177e4SLinus Torvalds if (bp->l_flag & lbmRELEASE) { 22361da177e4SLinus Torvalds log->wqueue = NULL; 22371da177e4SLinus Torvalds bp->l_wqnext = NULL; 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds /* multi element queue */ 22411da177e4SLinus Torvalds else { 22421da177e4SLinus Torvalds /* remove head buffer of full-page pageout 22431da177e4SLinus Torvalds * from log device write queue 22441da177e4SLinus Torvalds */ 22451da177e4SLinus Torvalds if (bp->l_flag & lbmRELEASE) { 22461da177e4SLinus Torvalds nextbp = tail->l_wqnext = bp->l_wqnext; 22471da177e4SLinus Torvalds bp->l_wqnext = NULL; 22481da177e4SLinus Torvalds 22491da177e4SLinus Torvalds /* 22501da177e4SLinus Torvalds * redrive pageout of next page at head of write queue: 22511da177e4SLinus Torvalds * redrive next page without any bound tblk 22521da177e4SLinus Torvalds * (i.e., page w/o any COMMIT records), or 22531da177e4SLinus Torvalds * first page of new group commit which has been 22541da177e4SLinus Torvalds * queued after current page (subsequent pageout 22551da177e4SLinus Torvalds * is performed synchronously, except page without 22561da177e4SLinus Torvalds * any COMMITs) by lmGroupCommit() as indicated 22571da177e4SLinus Torvalds * by lbmWRITE flag; 22581da177e4SLinus Torvalds */ 22591da177e4SLinus Torvalds if (nextbp->l_flag & lbmWRITE) { 22601da177e4SLinus Torvalds /* 22611da177e4SLinus Torvalds * We can't do the I/O at interrupt time. 22621da177e4SLinus Torvalds * The jfsIO thread can do it 22631da177e4SLinus Torvalds */ 22641da177e4SLinus Torvalds lbmRedrive(nextbp); 22651da177e4SLinus Torvalds } 22661da177e4SLinus Torvalds } 22671da177e4SLinus Torvalds } 22681da177e4SLinus Torvalds 22691da177e4SLinus Torvalds /* 22701da177e4SLinus Torvalds * synchronous pageout: 22711da177e4SLinus Torvalds * 22721da177e4SLinus Torvalds * buffer has not necessarily been removed from write queue 22731da177e4SLinus Torvalds * (e.g., synchronous write of partial-page with COMMIT): 22741da177e4SLinus Torvalds * leave buffer for i/o initiator to dispose 22751da177e4SLinus Torvalds */ 22761da177e4SLinus Torvalds if (bp->l_flag & lbmSYNC) { 22771da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds /* wakeup I/O initiator */ 22801da177e4SLinus Torvalds LCACHE_WAKEUP(&bp->l_ioevent); 22811da177e4SLinus Torvalds } 22821da177e4SLinus Torvalds 22831da177e4SLinus Torvalds /* 22841da177e4SLinus Torvalds * Group Commit pageout: 22851da177e4SLinus Torvalds */ 22861da177e4SLinus Torvalds else if (bp->l_flag & lbmGC) { 22871da177e4SLinus Torvalds LCACHE_UNLOCK(flags); 22881da177e4SLinus Torvalds lmPostGC(bp); 22891da177e4SLinus Torvalds } 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds /* 22921da177e4SLinus Torvalds * asynchronous pageout: 22931da177e4SLinus Torvalds * 22941da177e4SLinus Torvalds * buffer must have been removed from write queue: 22951da177e4SLinus Torvalds * insert buffer at head of freelist where it can be recycled 22961da177e4SLinus Torvalds */ 22971da177e4SLinus Torvalds else { 22981da177e4SLinus Torvalds assert(bp->l_flag & lbmRELEASE); 22991da177e4SLinus Torvalds assert(bp->l_flag & lbmFREE); 23001da177e4SLinus Torvalds lbmfree(bp); 23011da177e4SLinus Torvalds 23021da177e4SLinus Torvalds LCACHE_UNLOCK(flags); /* unlock+enable */ 23031da177e4SLinus Torvalds } 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds int jfsIOWait(void *arg) 23071da177e4SLinus Torvalds { 23081da177e4SLinus Torvalds struct lbuf *bp; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds do { 23111da177e4SLinus Torvalds spin_lock_irq(&log_redrive_lock); 231209aaa749SJoe Perches while ((bp = log_redrive_list)) { 23131da177e4SLinus Torvalds log_redrive_list = bp->l_redrive_next; 23141da177e4SLinus Torvalds bp->l_redrive_next = NULL; 23151da177e4SLinus Torvalds spin_unlock_irq(&log_redrive_lock); 23161da177e4SLinus Torvalds lbmStartIO(bp); 23171da177e4SLinus Torvalds spin_lock_irq(&log_redrive_lock); 23181da177e4SLinus Torvalds } 231991dbb4deSChristoph Hellwig 232091dbb4deSChristoph Hellwig if (freezing(current)) { 232105ec9e26SDave Kleikamp spin_unlock_irq(&log_redrive_lock); 2322a0acae0eSTejun Heo try_to_freeze(); 23231da177e4SLinus Torvalds } else { 23241da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 232505ec9e26SDave Kleikamp spin_unlock_irq(&log_redrive_lock); 23261da177e4SLinus Torvalds schedule(); 23271da177e4SLinus Torvalds } 232891dbb4deSChristoph Hellwig } while (!kthread_should_stop()); 23291da177e4SLinus Torvalds 23301da177e4SLinus Torvalds jfs_info("jfsIOWait being killed!"); 233191dbb4deSChristoph Hellwig return 0; 23321da177e4SLinus Torvalds } 23331da177e4SLinus Torvalds 23341da177e4SLinus Torvalds /* 23351da177e4SLinus Torvalds * NAME: lmLogFormat()/jfs_logform() 23361da177e4SLinus Torvalds * 23371da177e4SLinus Torvalds * FUNCTION: format file system log 23381da177e4SLinus Torvalds * 23391da177e4SLinus Torvalds * PARAMETERS: 23401da177e4SLinus Torvalds * log - volume log 23411da177e4SLinus Torvalds * logAddress - start address of log space in FS block 23421da177e4SLinus Torvalds * logSize - length of log space in FS block; 23431da177e4SLinus Torvalds * 23441da177e4SLinus Torvalds * RETURN: 0 - success 23451da177e4SLinus Torvalds * -EIO - i/o error 23461da177e4SLinus Torvalds * 23471da177e4SLinus Torvalds * XXX: We're synchronously writing one page at a time. This needs to 23481da177e4SLinus Torvalds * be improved by writing multiple pages at once. 23491da177e4SLinus Torvalds */ 23501da177e4SLinus Torvalds int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize) 23511da177e4SLinus Torvalds { 23521da177e4SLinus Torvalds int rc = -EIO; 23531da177e4SLinus Torvalds struct jfs_sb_info *sbi; 23541da177e4SLinus Torvalds struct logsuper *logsuper; 23551da177e4SLinus Torvalds struct logpage *lp; 23561da177e4SLinus Torvalds int lspn; /* log sequence page number */ 23571da177e4SLinus Torvalds struct lrd *lrd_ptr; 23581da177e4SLinus Torvalds int npages = 0; 23591da177e4SLinus Torvalds struct lbuf *bp; 23601da177e4SLinus Torvalds 23611da177e4SLinus Torvalds jfs_info("lmLogFormat: logAddress:%Ld logSize:%d", 23621da177e4SLinus Torvalds (long long)logAddress, logSize); 23631da177e4SLinus Torvalds 23641da177e4SLinus Torvalds sbi = list_entry(log->sb_list.next, struct jfs_sb_info, log_list); 23651da177e4SLinus Torvalds 23661da177e4SLinus Torvalds /* allocate a log buffer */ 23671da177e4SLinus Torvalds bp = lbmAllocate(log, 1); 23681da177e4SLinus Torvalds 23691da177e4SLinus Torvalds npages = logSize >> sbi->l2nbperpage; 23701da177e4SLinus Torvalds 23711da177e4SLinus Torvalds /* 23721da177e4SLinus Torvalds * log space: 23731da177e4SLinus Torvalds * 23741da177e4SLinus Torvalds * page 0 - reserved; 23751da177e4SLinus Torvalds * page 1 - log superblock; 23761da177e4SLinus Torvalds * page 2 - log data page: A SYNC log record is written 23771da177e4SLinus Torvalds * into this page at logform time; 23781da177e4SLinus Torvalds * pages 3-N - log data page: set to empty log data pages; 23791da177e4SLinus Torvalds */ 23801da177e4SLinus Torvalds /* 23811da177e4SLinus Torvalds * init log superblock: log page 1 23821da177e4SLinus Torvalds */ 23831da177e4SLinus Torvalds logsuper = (struct logsuper *) bp->l_ldata; 23841da177e4SLinus Torvalds 23851da177e4SLinus Torvalds logsuper->magic = cpu_to_le32(LOGMAGIC); 23861da177e4SLinus Torvalds logsuper->version = cpu_to_le32(LOGVERSION); 23871da177e4SLinus Torvalds logsuper->state = cpu_to_le32(LOGREDONE); 23881da177e4SLinus Torvalds logsuper->flag = cpu_to_le32(sbi->mntflag); /* ? */ 23891da177e4SLinus Torvalds logsuper->size = cpu_to_le32(npages); 23901da177e4SLinus Torvalds logsuper->bsize = cpu_to_le32(sbi->bsize); 23911da177e4SLinus Torvalds logsuper->l2bsize = cpu_to_le32(sbi->l2bsize); 23921da177e4SLinus Torvalds logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE); 23931da177e4SLinus Torvalds 23941da177e4SLinus Torvalds bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 23951da177e4SLinus Torvalds bp->l_blkno = logAddress + sbi->nbperpage; 23961da177e4SLinus Torvalds lbmStartIO(bp); 23971da177e4SLinus Torvalds if ((rc = lbmIOWait(bp, 0))) 23981da177e4SLinus Torvalds goto exit; 23991da177e4SLinus Torvalds 24001da177e4SLinus Torvalds /* 24011da177e4SLinus Torvalds * init pages 2 to npages-1 as log data pages: 24021da177e4SLinus Torvalds * 24031da177e4SLinus Torvalds * log page sequence number (lpsn) initialization: 24041da177e4SLinus Torvalds * 24051da177e4SLinus Torvalds * pn: 0 1 2 3 n-1 24061da177e4SLinus Torvalds * +-----+-----+=====+=====+===.....===+=====+ 24071da177e4SLinus Torvalds * lspn: N-1 0 1 N-2 24081da177e4SLinus Torvalds * <--- N page circular file ----> 24091da177e4SLinus Torvalds * 24101da177e4SLinus Torvalds * the N (= npages-2) data pages of the log is maintained as 24111da177e4SLinus Torvalds * a circular file for the log records; 24121da177e4SLinus Torvalds * lpsn grows by 1 monotonically as each log page is written 24131da177e4SLinus Torvalds * to the circular file of the log; 24141da177e4SLinus Torvalds * and setLogpage() will not reset the page number even if 24151da177e4SLinus Torvalds * the eor is equal to LOGPHDRSIZE. In order for binary search 24161da177e4SLinus Torvalds * still work in find log end process, we have to simulate the 24171da177e4SLinus Torvalds * log wrap situation at the log format time. 24181da177e4SLinus Torvalds * The 1st log page written will have the highest lpsn. Then 24191da177e4SLinus Torvalds * the succeeding log pages will have ascending order of 24201da177e4SLinus Torvalds * the lspn starting from 0, ... (N-2) 24211da177e4SLinus Torvalds */ 24221da177e4SLinus Torvalds lp = (struct logpage *) bp->l_ldata; 24231da177e4SLinus Torvalds /* 24241da177e4SLinus Torvalds * initialize 1st log page to be written: lpsn = N - 1, 24251da177e4SLinus Torvalds * write a SYNCPT log record is written to this page 24261da177e4SLinus Torvalds */ 24271da177e4SLinus Torvalds lp->h.page = lp->t.page = cpu_to_le32(npages - 3); 24281da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE); 24291da177e4SLinus Torvalds 24301da177e4SLinus Torvalds lrd_ptr = (struct lrd *) &lp->data; 24311da177e4SLinus Torvalds lrd_ptr->logtid = 0; 24321da177e4SLinus Torvalds lrd_ptr->backchain = 0; 24331da177e4SLinus Torvalds lrd_ptr->type = cpu_to_le16(LOG_SYNCPT); 24341da177e4SLinus Torvalds lrd_ptr->length = 0; 24351da177e4SLinus Torvalds lrd_ptr->log.syncpt.sync = 0; 24361da177e4SLinus Torvalds 24371da177e4SLinus Torvalds bp->l_blkno += sbi->nbperpage; 24381da177e4SLinus Torvalds bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 24391da177e4SLinus Torvalds lbmStartIO(bp); 24401da177e4SLinus Torvalds if ((rc = lbmIOWait(bp, 0))) 24411da177e4SLinus Torvalds goto exit; 24421da177e4SLinus Torvalds 24431da177e4SLinus Torvalds /* 24441da177e4SLinus Torvalds * initialize succeeding log pages: lpsn = 0, 1, ..., (N-2) 24451da177e4SLinus Torvalds */ 24461da177e4SLinus Torvalds for (lspn = 0; lspn < npages - 3; lspn++) { 24471da177e4SLinus Torvalds lp->h.page = lp->t.page = cpu_to_le32(lspn); 24481da177e4SLinus Torvalds lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); 24491da177e4SLinus Torvalds 24501da177e4SLinus Torvalds bp->l_blkno += sbi->nbperpage; 24511da177e4SLinus Torvalds bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 24521da177e4SLinus Torvalds lbmStartIO(bp); 24531da177e4SLinus Torvalds if ((rc = lbmIOWait(bp, 0))) 24541da177e4SLinus Torvalds goto exit; 24551da177e4SLinus Torvalds } 24561da177e4SLinus Torvalds 24571da177e4SLinus Torvalds rc = 0; 24581da177e4SLinus Torvalds exit: 24591da177e4SLinus Torvalds /* 24601da177e4SLinus Torvalds * finalize log 24611da177e4SLinus Torvalds */ 24621da177e4SLinus Torvalds /* release the buffer */ 24631da177e4SLinus Torvalds lbmFree(bp); 24641da177e4SLinus Torvalds 24651da177e4SLinus Torvalds return rc; 24661da177e4SLinus Torvalds } 24671da177e4SLinus Torvalds 24681da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS 246907a3b8edSChristoph Hellwig int jfs_lmstats_proc_show(struct seq_file *m, void *v) 24701da177e4SLinus Torvalds { 2471b2e03ca7SAlexey Dobriyan seq_printf(m, 24721da177e4SLinus Torvalds "JFS Logmgr stats\n" 24731da177e4SLinus Torvalds "================\n" 24741da177e4SLinus Torvalds "commits = %d\n" 24751da177e4SLinus Torvalds "writes submitted = %d\n" 24761da177e4SLinus Torvalds "writes completed = %d\n" 24771da177e4SLinus Torvalds "full pages submitted = %d\n" 24781da177e4SLinus Torvalds "partial pages submitted = %d\n", 24791da177e4SLinus Torvalds lmStat.commit, 24801da177e4SLinus Torvalds lmStat.submitted, 24811da177e4SLinus Torvalds lmStat.pagedone, 24821da177e4SLinus Torvalds lmStat.full_page, 24831da177e4SLinus Torvalds lmStat.partial_page); 2484b2e03ca7SAlexey Dobriyan return 0; 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds #endif /* CONFIG_JFS_STATISTICS */ 2487