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