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