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