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