162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2000-2004 462306a36Sopenharmony_ci * Portions Copyright (C) Christoph Hellwig, 2001-2002 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * jfs_logmgr.c: log manager 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * for related information, see transaction manager (jfs_txnmgr.c), and 1162306a36Sopenharmony_ci * recovery manager (jfs_logredo.c). 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * note: for detail, RTFS. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * log buffer manager: 1662306a36Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements. 1762306a36Sopenharmony_ci * per log serial pageout of logpage 1862306a36Sopenharmony_ci * queuing i/o requests and redrive i/o at iodone 1962306a36Sopenharmony_ci * maintain current logpage buffer 2062306a36Sopenharmony_ci * no caching since append only 2162306a36Sopenharmony_ci * appropriate jfs buffer cache buffers as needed 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * group commit: 2462306a36Sopenharmony_ci * transactions which wrote COMMIT records in the same in-memory 2562306a36Sopenharmony_ci * log page during the pageout of previous/current log page(s) are 2662306a36Sopenharmony_ci * committed together by the pageout of the page. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * TBD lazy commit: 2962306a36Sopenharmony_ci * transactions are committed asynchronously when the log page 3062306a36Sopenharmony_ci * containing it COMMIT is paged out when it becomes full; 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * serialization: 3362306a36Sopenharmony_ci * . a per log lock serialize log write. 3462306a36Sopenharmony_ci * . a per log lock serialize group commit. 3562306a36Sopenharmony_ci * . a per log lock serialize log open/close; 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * TBD log integrity: 3862306a36Sopenharmony_ci * careful-write (ping-pong) of last logpage to recover from crash 3962306a36Sopenharmony_ci * in overwrite. 4062306a36Sopenharmony_ci * detection of split (out-of-order) write of physical sectors 4162306a36Sopenharmony_ci * of last logpage via timestamp at end of each sector 4262306a36Sopenharmony_ci * with its mirror data array at trailer). 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * alternatives: 4562306a36Sopenharmony_ci * lsn - 64-bit monotonically increasing integer vs 4662306a36Sopenharmony_ci * 32-bit lspn and page eor. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <linux/fs.h> 5062306a36Sopenharmony_ci#include <linux/blkdev.h> 5162306a36Sopenharmony_ci#include <linux/interrupt.h> 5262306a36Sopenharmony_ci#include <linux/completion.h> 5362306a36Sopenharmony_ci#include <linux/kthread.h> 5462306a36Sopenharmony_ci#include <linux/buffer_head.h> /* for sync_blockdev() */ 5562306a36Sopenharmony_ci#include <linux/bio.h> 5662306a36Sopenharmony_ci#include <linux/freezer.h> 5762306a36Sopenharmony_ci#include <linux/export.h> 5862306a36Sopenharmony_ci#include <linux/delay.h> 5962306a36Sopenharmony_ci#include <linux/mutex.h> 6062306a36Sopenharmony_ci#include <linux/seq_file.h> 6162306a36Sopenharmony_ci#include <linux/slab.h> 6262306a36Sopenharmony_ci#include "jfs_incore.h" 6362306a36Sopenharmony_ci#include "jfs_filsys.h" 6462306a36Sopenharmony_ci#include "jfs_metapage.h" 6562306a36Sopenharmony_ci#include "jfs_superblock.h" 6662306a36Sopenharmony_ci#include "jfs_txnmgr.h" 6762306a36Sopenharmony_ci#include "jfs_debug.h" 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread) 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic struct lbuf *log_redrive_list; 7462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(log_redrive_lock); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * log read/write serialization (per log) 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) 8162306a36Sopenharmony_ci#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) 8262306a36Sopenharmony_ci#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * log group commit serialization (per log) 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define LOGGC_LOCK_INIT(log) spin_lock_init(&(log)->gclock) 9062306a36Sopenharmony_ci#define LOGGC_LOCK(log) spin_lock_irq(&(log)->gclock) 9162306a36Sopenharmony_ci#define LOGGC_UNLOCK(log) spin_unlock_irq(&(log)->gclock) 9262306a36Sopenharmony_ci#define LOGGC_WAKEUP(tblk) wake_up_all(&(tblk)->gcwait) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * log sync serialization (per log) 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci#define LOGSYNC_DELTA(logsize) min((logsize)/8, 128*LOGPSIZE) 9862306a36Sopenharmony_ci#define LOGSYNC_BARRIER(logsize) ((logsize)/4) 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci#define LOGSYNC_DELTA(logsize) min((logsize)/4, 256*LOGPSIZE) 10162306a36Sopenharmony_ci#define LOGSYNC_BARRIER(logsize) ((logsize)/2) 10262306a36Sopenharmony_ci*/ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * log buffer cache synchronization 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(jfsLCacheLock); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags) 11162306a36Sopenharmony_ci#define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * See __SLEEP_COND in jfs_locks.h 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci#define LCACHE_SLEEP_COND(wq, cond, flags) \ 11762306a36Sopenharmony_cido { \ 11862306a36Sopenharmony_ci if (cond) \ 11962306a36Sopenharmony_ci break; \ 12062306a36Sopenharmony_ci __SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \ 12162306a36Sopenharmony_ci} while (0) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define LCACHE_WAKEUP(event) wake_up(event) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * lbuf buffer cache (lCache) control 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci/* log buffer manager pageout control (cumulative, inclusive) */ 13062306a36Sopenharmony_ci#define lbmREAD 0x0001 13162306a36Sopenharmony_ci#define lbmWRITE 0x0002 /* enqueue at tail of write queue; 13262306a36Sopenharmony_ci * init pageout if at head of queue; 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci#define lbmRELEASE 0x0004 /* remove from write queue 13562306a36Sopenharmony_ci * at completion of pageout; 13662306a36Sopenharmony_ci * do not free/recycle it yet: 13762306a36Sopenharmony_ci * caller will free it; 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci#define lbmSYNC 0x0008 /* do not return to freelist 14062306a36Sopenharmony_ci * when removed from write queue; 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci#define lbmFREE 0x0010 /* return to freelist 14362306a36Sopenharmony_ci * at completion of pageout; 14462306a36Sopenharmony_ci * the buffer may be recycled; 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci#define lbmDONE 0x0020 14762306a36Sopenharmony_ci#define lbmERROR 0x0040 14862306a36Sopenharmony_ci#define lbmGC 0x0080 /* lbmIODone to perform post-GC processing 14962306a36Sopenharmony_ci * of log page 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci#define lbmDIRECT 0x0100 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * Global list of active external journals 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic LIST_HEAD(jfs_external_logs); 15762306a36Sopenharmony_cistatic struct jfs_log *dummy_log; 15862306a36Sopenharmony_cistatic DEFINE_MUTEX(jfs_log_mutex); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* 16162306a36Sopenharmony_ci * forward references 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int lmWriteRecord(struct jfs_log * log, struct tblock * tblk, 16462306a36Sopenharmony_ci struct lrd * lrd, struct tlock * tlck); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int lmNextPage(struct jfs_log * log); 16762306a36Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi, 16862306a36Sopenharmony_ci int activate); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int open_inline_log(struct super_block *sb); 17162306a36Sopenharmony_cistatic int open_dummy_log(struct super_block *sb); 17262306a36Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log); 17362306a36Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log); 17462306a36Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int); 17562306a36Sopenharmony_cistatic void lbmFree(struct lbuf * bp); 17662306a36Sopenharmony_cistatic void lbmfree(struct lbuf * bp); 17762306a36Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp); 17862306a36Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block); 17962306a36Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag); 18062306a36Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag); 18162306a36Sopenharmony_cistatic bio_end_io_t lbmIODone; 18262306a36Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp); 18362306a36Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_block); 18462306a36Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * statistics 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS 19262306a36Sopenharmony_cistatic struct lmStat { 19362306a36Sopenharmony_ci uint commit; /* # of commit */ 19462306a36Sopenharmony_ci uint pagedone; /* # of page written */ 19562306a36Sopenharmony_ci uint submitted; /* # of pages submitted */ 19662306a36Sopenharmony_ci uint full_page; /* # of full pages submitted */ 19762306a36Sopenharmony_ci uint partial_page; /* # of partial pages submitted */ 19862306a36Sopenharmony_ci} lmStat; 19962306a36Sopenharmony_ci#endif 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void write_special_inodes(struct jfs_log *log, 20262306a36Sopenharmony_ci int (*writer)(struct address_space *)) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct jfs_sb_info *sbi; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci list_for_each_entry(sbi, &log->sb_list, log_list) { 20762306a36Sopenharmony_ci writer(sbi->ipbmap->i_mapping); 20862306a36Sopenharmony_ci writer(sbi->ipimap->i_mapping); 20962306a36Sopenharmony_ci writer(sbi->direct_inode->i_mapping); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * NAME: lmLog() 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * FUNCTION: write a log record; 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * PARAMETER: 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * RETURN: lsn - offset to the next log record to write (end-of-log); 22162306a36Sopenharmony_ci * -1 - error; 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * note: todo: log error handler 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ciint lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, 22662306a36Sopenharmony_ci struct tlock * tlck) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int lsn; 22962306a36Sopenharmony_ci int diffp, difft; 23062306a36Sopenharmony_ci struct metapage *mp = NULL; 23162306a36Sopenharmony_ci unsigned long flags; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p", 23462306a36Sopenharmony_ci log, tblk, lrd, tlck); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci LOG_LOCK(log); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* log by (out-of-transaction) JFS ? */ 23962306a36Sopenharmony_ci if (tblk == NULL) 24062306a36Sopenharmony_ci goto writeRecord; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* log from page ? */ 24362306a36Sopenharmony_ci if (tlck == NULL || 24462306a36Sopenharmony_ci tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL) 24562306a36Sopenharmony_ci goto writeRecord; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * initialize/update page/transaction recovery lsn 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci lsn = log->lsn; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci LOGSYNC_LOCK(log, flags); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* 25562306a36Sopenharmony_ci * initialize page lsn if first log write of the page 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci if (mp->lsn == 0) { 25862306a36Sopenharmony_ci mp->log = log; 25962306a36Sopenharmony_ci mp->lsn = lsn; 26062306a36Sopenharmony_ci log->count++; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* insert page at tail of logsynclist */ 26362306a36Sopenharmony_ci list_add_tail(&mp->synclist, &log->synclist); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * initialize/update lsn of tblock of the page 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * transaction inherits oldest lsn of pages associated 27062306a36Sopenharmony_ci * with allocation/deallocation of resources (their 27162306a36Sopenharmony_ci * log records are used to reconstruct allocation map 27262306a36Sopenharmony_ci * at recovery time: inode for inode allocation map, 27362306a36Sopenharmony_ci * B+-tree index of extent descriptors for block 27462306a36Sopenharmony_ci * allocation map); 27562306a36Sopenharmony_ci * allocation map pages inherit transaction lsn at 27662306a36Sopenharmony_ci * commit time to allow forwarding log syncpt past log 27762306a36Sopenharmony_ci * records associated with allocation/deallocation of 27862306a36Sopenharmony_ci * resources only after persistent map of these map pages 27962306a36Sopenharmony_ci * have been updated and propagated to home. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * initialize transaction lsn: 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci if (tblk->lsn == 0) { 28562306a36Sopenharmony_ci /* inherit lsn of its first page logged */ 28662306a36Sopenharmony_ci tblk->lsn = mp->lsn; 28762306a36Sopenharmony_ci log->count++; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* insert tblock after the page on logsynclist */ 29062306a36Sopenharmony_ci list_add(&tblk->synclist, &mp->synclist); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * update transaction lsn: 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci else { 29662306a36Sopenharmony_ci /* inherit oldest/smallest lsn of page */ 29762306a36Sopenharmony_ci logdiff(diffp, mp->lsn, log); 29862306a36Sopenharmony_ci logdiff(difft, tblk->lsn, log); 29962306a36Sopenharmony_ci if (diffp < difft) { 30062306a36Sopenharmony_ci /* update tblock lsn with page lsn */ 30162306a36Sopenharmony_ci tblk->lsn = mp->lsn; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* move tblock after page on logsynclist */ 30462306a36Sopenharmony_ci list_move(&tblk->synclist, &mp->synclist); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci LOGSYNC_UNLOCK(log, flags); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* 31162306a36Sopenharmony_ci * write the log record 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ci writeRecord: 31462306a36Sopenharmony_ci lsn = lmWriteRecord(log, tblk, lrd, tlck); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * forward log syncpt if log reached next syncpt trigger 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci logdiff(diffp, lsn, log); 32062306a36Sopenharmony_ci if (diffp >= log->nextsync) 32162306a36Sopenharmony_ci lsn = lmLogSync(log, 0); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* update end-of-log lsn */ 32462306a36Sopenharmony_ci log->lsn = lsn; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci LOG_UNLOCK(log); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* return end-of-log address */ 32962306a36Sopenharmony_ci return lsn; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* 33362306a36Sopenharmony_ci * NAME: lmWriteRecord() 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * FUNCTION: move the log record to current log page 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * PARAMETER: cd - commit descriptor 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * RETURN: end-of-log address 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic int 34462306a36Sopenharmony_cilmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, 34562306a36Sopenharmony_ci struct tlock * tlck) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci int lsn = 0; /* end-of-log address */ 34862306a36Sopenharmony_ci struct lbuf *bp; /* dst log page buffer */ 34962306a36Sopenharmony_ci struct logpage *lp; /* dst log page */ 35062306a36Sopenharmony_ci caddr_t dst; /* destination address in log page */ 35162306a36Sopenharmony_ci int dstoffset; /* end-of-log offset in log page */ 35262306a36Sopenharmony_ci int freespace; /* free space in log page */ 35362306a36Sopenharmony_ci caddr_t p; /* src meta-data page */ 35462306a36Sopenharmony_ci caddr_t src; 35562306a36Sopenharmony_ci int srclen; 35662306a36Sopenharmony_ci int nbytes; /* number of bytes to move */ 35762306a36Sopenharmony_ci int i; 35862306a36Sopenharmony_ci int len; 35962306a36Sopenharmony_ci struct linelock *linelock; 36062306a36Sopenharmony_ci struct lv *lv; 36162306a36Sopenharmony_ci struct lvd *lvd; 36262306a36Sopenharmony_ci int l2linesize; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci len = 0; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* retrieve destination log page to write */ 36762306a36Sopenharmony_ci bp = (struct lbuf *) log->bp; 36862306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 36962306a36Sopenharmony_ci dstoffset = log->eor; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* any log data to write ? */ 37262306a36Sopenharmony_ci if (tlck == NULL) 37362306a36Sopenharmony_ci goto moveLrd; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * move log record data 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci /* retrieve source meta-data page to log */ 37962306a36Sopenharmony_ci if (tlck->flag & tlckPAGELOCK) { 38062306a36Sopenharmony_ci p = (caddr_t) (tlck->mp->data); 38162306a36Sopenharmony_ci linelock = (struct linelock *) & tlck->lock; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci /* retrieve source in-memory inode to log */ 38462306a36Sopenharmony_ci else if (tlck->flag & tlckINODELOCK) { 38562306a36Sopenharmony_ci if (tlck->type & tlckDTREE) 38662306a36Sopenharmony_ci p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot; 38762306a36Sopenharmony_ci else 38862306a36Sopenharmony_ci p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot; 38962306a36Sopenharmony_ci linelock = (struct linelock *) & tlck->lock; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci else { 39262306a36Sopenharmony_ci jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck); 39362306a36Sopenharmony_ci return 0; /* Probably should trap */ 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci l2linesize = linelock->l2linesize; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci moveData: 39862306a36Sopenharmony_ci ASSERT(linelock->index <= linelock->maxcnt); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci lv = linelock->lv; 40162306a36Sopenharmony_ci for (i = 0; i < linelock->index; i++, lv++) { 40262306a36Sopenharmony_ci if (lv->length == 0) 40362306a36Sopenharmony_ci continue; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* is page full ? */ 40662306a36Sopenharmony_ci if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) { 40762306a36Sopenharmony_ci /* page become full: move on to next page */ 40862306a36Sopenharmony_ci lmNextPage(log); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci bp = log->bp; 41162306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 41262306a36Sopenharmony_ci dstoffset = LOGPHDRSIZE; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* 41662306a36Sopenharmony_ci * move log vector data 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci src = (u8 *) p + (lv->offset << l2linesize); 41962306a36Sopenharmony_ci srclen = lv->length << l2linesize; 42062306a36Sopenharmony_ci len += srclen; 42162306a36Sopenharmony_ci while (srclen > 0) { 42262306a36Sopenharmony_ci freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; 42362306a36Sopenharmony_ci nbytes = min(freespace, srclen); 42462306a36Sopenharmony_ci dst = (caddr_t) lp + dstoffset; 42562306a36Sopenharmony_ci memcpy(dst, src, nbytes); 42662306a36Sopenharmony_ci dstoffset += nbytes; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* is page not full ? */ 42962306a36Sopenharmony_ci if (dstoffset < LOGPSIZE - LOGPTLRSIZE) 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* page become full: move on to next page */ 43362306a36Sopenharmony_ci lmNextPage(log); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci bp = (struct lbuf *) log->bp; 43662306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 43762306a36Sopenharmony_ci dstoffset = LOGPHDRSIZE; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci srclen -= nbytes; 44062306a36Sopenharmony_ci src += nbytes; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* 44462306a36Sopenharmony_ci * move log vector descriptor 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci len += 4; 44762306a36Sopenharmony_ci lvd = (struct lvd *) ((caddr_t) lp + dstoffset); 44862306a36Sopenharmony_ci lvd->offset = cpu_to_le16(lv->offset); 44962306a36Sopenharmony_ci lvd->length = cpu_to_le16(lv->length); 45062306a36Sopenharmony_ci dstoffset += 4; 45162306a36Sopenharmony_ci jfs_info("lmWriteRecord: lv offset:%d length:%d", 45262306a36Sopenharmony_ci lv->offset, lv->length); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if ((i = linelock->next)) { 45662306a36Sopenharmony_ci linelock = (struct linelock *) lid_to_tlock(i); 45762306a36Sopenharmony_ci goto moveData; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * move log record descriptor 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci moveLrd: 46462306a36Sopenharmony_ci lrd->length = cpu_to_le16(len); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci src = (caddr_t) lrd; 46762306a36Sopenharmony_ci srclen = LOGRDSIZE; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci while (srclen > 0) { 47062306a36Sopenharmony_ci freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; 47162306a36Sopenharmony_ci nbytes = min(freespace, srclen); 47262306a36Sopenharmony_ci dst = (caddr_t) lp + dstoffset; 47362306a36Sopenharmony_ci memcpy(dst, src, nbytes); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci dstoffset += nbytes; 47662306a36Sopenharmony_ci srclen -= nbytes; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* are there more to move than freespace of page ? */ 47962306a36Sopenharmony_ci if (srclen) 48062306a36Sopenharmony_ci goto pageFull; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * end of log record descriptor 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* update last log record eor */ 48762306a36Sopenharmony_ci log->eor = dstoffset; 48862306a36Sopenharmony_ci bp->l_eor = dstoffset; 48962306a36Sopenharmony_ci lsn = (log->page << L2LOGPSIZE) + dstoffset; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (lrd->type & cpu_to_le16(LOG_COMMIT)) { 49262306a36Sopenharmony_ci tblk->clsn = lsn; 49362306a36Sopenharmony_ci jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn, 49462306a36Sopenharmony_ci bp->l_eor); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci INCREMENT(lmStat.commit); /* # of commit */ 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* 49962306a36Sopenharmony_ci * enqueue tblock for group commit: 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * enqueue tblock of non-trivial/synchronous COMMIT 50262306a36Sopenharmony_ci * at tail of group commit queue 50362306a36Sopenharmony_ci * (trivial/asynchronous COMMITs are ignored by 50462306a36Sopenharmony_ci * group commit.) 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci LOGGC_LOCK(log); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* init tblock gc state */ 50962306a36Sopenharmony_ci tblk->flag = tblkGC_QUEUE; 51062306a36Sopenharmony_ci tblk->bp = log->bp; 51162306a36Sopenharmony_ci tblk->pn = log->page; 51262306a36Sopenharmony_ci tblk->eor = log->eor; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* enqueue transaction to commit queue */ 51562306a36Sopenharmony_ci list_add_tail(&tblk->cqueue, &log->cqueue); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci LOGGC_UNLOCK(log); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x", 52162306a36Sopenharmony_ci le16_to_cpu(lrd->type), log->bp, log->page, dstoffset); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* page not full ? */ 52462306a36Sopenharmony_ci if (dstoffset < LOGPSIZE - LOGPTLRSIZE) 52562306a36Sopenharmony_ci return lsn; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci pageFull: 52862306a36Sopenharmony_ci /* page become full: move on to next page */ 52962306a36Sopenharmony_ci lmNextPage(log); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci bp = (struct lbuf *) log->bp; 53262306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 53362306a36Sopenharmony_ci dstoffset = LOGPHDRSIZE; 53462306a36Sopenharmony_ci src += nbytes; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return lsn; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/* 54262306a36Sopenharmony_ci * NAME: lmNextPage() 54362306a36Sopenharmony_ci * 54462306a36Sopenharmony_ci * FUNCTION: write current page and allocate next page. 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * PARAMETER: log 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * RETURN: 0 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic int lmNextPage(struct jfs_log * log) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct logpage *lp; 55562306a36Sopenharmony_ci int lspn; /* log sequence page number */ 55662306a36Sopenharmony_ci int pn; /* current page number */ 55762306a36Sopenharmony_ci struct lbuf *bp; 55862306a36Sopenharmony_ci struct lbuf *nextbp; 55962306a36Sopenharmony_ci struct tblock *tblk; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* get current log page number and log sequence page number */ 56262306a36Sopenharmony_ci pn = log->page; 56362306a36Sopenharmony_ci bp = log->bp; 56462306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 56562306a36Sopenharmony_ci lspn = le32_to_cpu(lp->h.page); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci LOGGC_LOCK(log); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * write or queue the full page at the tail of write queue 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci /* get the tail tblk on commit queue */ 57362306a36Sopenharmony_ci if (list_empty(&log->cqueue)) 57462306a36Sopenharmony_ci tblk = NULL; 57562306a36Sopenharmony_ci else 57662306a36Sopenharmony_ci tblk = list_entry(log->cqueue.prev, struct tblock, cqueue); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* every tblk who has COMMIT record on the current page, 57962306a36Sopenharmony_ci * and has not been committed, must be on commit queue 58062306a36Sopenharmony_ci * since tblk is queued at commit queueu at the time 58162306a36Sopenharmony_ci * of writing its COMMIT record on the page before 58262306a36Sopenharmony_ci * page becomes full (even though the tblk thread 58362306a36Sopenharmony_ci * who wrote COMMIT record may have been suspended 58462306a36Sopenharmony_ci * currently); 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* is page bound with outstanding tail tblk ? */ 58862306a36Sopenharmony_ci if (tblk && tblk->pn == pn) { 58962306a36Sopenharmony_ci /* mark tblk for end-of-page */ 59062306a36Sopenharmony_ci tblk->flag |= tblkGC_EOP; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (log->cflag & logGC_PAGEOUT) { 59362306a36Sopenharmony_ci /* if page is not already on write queue, 59462306a36Sopenharmony_ci * just enqueue (no lbmWRITE to prevent redrive) 59562306a36Sopenharmony_ci * buffer to wqueue to ensure correct serial order 59662306a36Sopenharmony_ci * of the pages since log pages will be added 59762306a36Sopenharmony_ci * continuously 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci if (bp->l_wqnext == NULL) 60062306a36Sopenharmony_ci lbmWrite(log, bp, 0, 0); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * No current GC leader, initiate group commit 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci log->cflag |= logGC_PAGEOUT; 60662306a36Sopenharmony_ci lmGCwrite(log, 0); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci /* page is not bound with outstanding tblk: 61062306a36Sopenharmony_ci * init write or mark it to be redriven (lbmWRITE) 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci else { 61362306a36Sopenharmony_ci /* finalize the page */ 61462306a36Sopenharmony_ci bp->l_ceor = bp->l_eor; 61562306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 61662306a36Sopenharmony_ci lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci LOGGC_UNLOCK(log); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * allocate/initialize next page 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci /* if log wraps, the first data page of log is 2 62462306a36Sopenharmony_ci * (0 never used, 1 is superblock). 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci log->page = (pn == log->size - 1) ? 2 : pn + 1; 62762306a36Sopenharmony_ci log->eor = LOGPHDRSIZE; /* ? valid page empty/full at logRedo() */ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* allocate/initialize next log page buffer */ 63062306a36Sopenharmony_ci nextbp = lbmAllocate(log, log->page); 63162306a36Sopenharmony_ci nextbp->l_eor = log->eor; 63262306a36Sopenharmony_ci log->bp = nextbp; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* initialize next log page */ 63562306a36Sopenharmony_ci lp = (struct logpage *) nextbp->l_ldata; 63662306a36Sopenharmony_ci lp->h.page = lp->t.page = cpu_to_le32(lspn + 1); 63762306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* 64462306a36Sopenharmony_ci * NAME: lmGroupCommit() 64562306a36Sopenharmony_ci * 64662306a36Sopenharmony_ci * FUNCTION: group commit 64762306a36Sopenharmony_ci * initiate pageout of the pages with COMMIT in the order of 64862306a36Sopenharmony_ci * page number - redrive pageout of the page at the head of 64962306a36Sopenharmony_ci * pageout queue until full page has been written. 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * RETURN: 65262306a36Sopenharmony_ci * 65362306a36Sopenharmony_ci * NOTE: 65462306a36Sopenharmony_ci * LOGGC_LOCK serializes log group commit queue, and 65562306a36Sopenharmony_ci * transaction blocks on the commit queue. 65662306a36Sopenharmony_ci * N.B. LOG_LOCK is NOT held during lmGroupCommit(). 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ciint lmGroupCommit(struct jfs_log * log, struct tblock * tblk) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci int rc = 0; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci LOGGC_LOCK(log); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* group committed already ? */ 66562306a36Sopenharmony_ci if (tblk->flag & tblkGC_COMMITTED) { 66662306a36Sopenharmony_ci if (tblk->flag & tblkGC_ERROR) 66762306a36Sopenharmony_ci rc = -EIO; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci LOGGC_UNLOCK(log); 67062306a36Sopenharmony_ci return rc; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (tblk->xflag & COMMIT_LAZY) 67562306a36Sopenharmony_ci tblk->flag |= tblkGC_LAZY; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) && 67862306a36Sopenharmony_ci (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag) 67962306a36Sopenharmony_ci || jfs_tlocks_low)) { 68062306a36Sopenharmony_ci /* 68162306a36Sopenharmony_ci * No pageout in progress 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * start group commit as its group leader. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci log->cflag |= logGC_PAGEOUT; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci lmGCwrite(log, 0); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (tblk->xflag & COMMIT_LAZY) { 69162306a36Sopenharmony_ci /* 69262306a36Sopenharmony_ci * Lazy transactions can leave now 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ci LOGGC_UNLOCK(log); 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* lmGCwrite gives up LOGGC_LOCK, check again */ 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (tblk->flag & tblkGC_COMMITTED) { 70162306a36Sopenharmony_ci if (tblk->flag & tblkGC_ERROR) 70262306a36Sopenharmony_ci rc = -EIO; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci LOGGC_UNLOCK(log); 70562306a36Sopenharmony_ci return rc; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* upcount transaction waiting for completion 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci log->gcrtc++; 71162306a36Sopenharmony_ci tblk->flag |= tblkGC_READY; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci __SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED), 71462306a36Sopenharmony_ci LOGGC_LOCK(log), LOGGC_UNLOCK(log)); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* removed from commit queue */ 71762306a36Sopenharmony_ci if (tblk->flag & tblkGC_ERROR) 71862306a36Sopenharmony_ci rc = -EIO; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci LOGGC_UNLOCK(log); 72162306a36Sopenharmony_ci return rc; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/* 72562306a36Sopenharmony_ci * NAME: lmGCwrite() 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * FUNCTION: group commit write 72862306a36Sopenharmony_ci * initiate write of log page, building a group of all transactions 72962306a36Sopenharmony_ci * with commit records on that page. 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * RETURN: None 73262306a36Sopenharmony_ci * 73362306a36Sopenharmony_ci * NOTE: 73462306a36Sopenharmony_ci * LOGGC_LOCK must be held by caller. 73562306a36Sopenharmony_ci * N.B. LOG_LOCK is NOT held during lmGroupCommit(). 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_cistatic void lmGCwrite(struct jfs_log * log, int cant_write) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct lbuf *bp; 74062306a36Sopenharmony_ci struct logpage *lp; 74162306a36Sopenharmony_ci int gcpn; /* group commit page number */ 74262306a36Sopenharmony_ci struct tblock *tblk; 74362306a36Sopenharmony_ci struct tblock *xtblk = NULL; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* 74662306a36Sopenharmony_ci * build the commit group of a log page 74762306a36Sopenharmony_ci * 74862306a36Sopenharmony_ci * scan commit queue and make a commit group of all 74962306a36Sopenharmony_ci * transactions with COMMIT records on the same log page. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci /* get the head tblk on the commit queue */ 75262306a36Sopenharmony_ci gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci list_for_each_entry(tblk, &log->cqueue, cqueue) { 75562306a36Sopenharmony_ci if (tblk->pn != gcpn) 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci xtblk = tblk; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* state transition: (QUEUE, READY) -> COMMIT */ 76162306a36Sopenharmony_ci tblk->flag |= tblkGC_COMMIT; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci tblk = xtblk; /* last tblk of the page */ 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* 76662306a36Sopenharmony_ci * pageout to commit transactions on the log page. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci bp = (struct lbuf *) tblk->bp; 76962306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 77062306a36Sopenharmony_ci /* is page already full ? */ 77162306a36Sopenharmony_ci if (tblk->flag & tblkGC_EOP) { 77262306a36Sopenharmony_ci /* mark page to free at end of group commit of the page */ 77362306a36Sopenharmony_ci tblk->flag &= ~tblkGC_EOP; 77462306a36Sopenharmony_ci tblk->flag |= tblkGC_FREE; 77562306a36Sopenharmony_ci bp->l_ceor = bp->l_eor; 77662306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 77762306a36Sopenharmony_ci lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC, 77862306a36Sopenharmony_ci cant_write); 77962306a36Sopenharmony_ci INCREMENT(lmStat.full_page); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci /* page is not yet full */ 78262306a36Sopenharmony_ci else { 78362306a36Sopenharmony_ci bp->l_ceor = tblk->eor; /* ? bp->l_ceor = bp->l_eor; */ 78462306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); 78562306a36Sopenharmony_ci lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write); 78662306a36Sopenharmony_ci INCREMENT(lmStat.partial_page); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci/* 79162306a36Sopenharmony_ci * NAME: lmPostGC() 79262306a36Sopenharmony_ci * 79362306a36Sopenharmony_ci * FUNCTION: group commit post-processing 79462306a36Sopenharmony_ci * Processes transactions after their commit records have been written 79562306a36Sopenharmony_ci * to disk, redriving log I/O if necessary. 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci * RETURN: None 79862306a36Sopenharmony_ci * 79962306a36Sopenharmony_ci * NOTE: 80062306a36Sopenharmony_ci * This routine is called a interrupt time by lbmIODone 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_cistatic void lmPostGC(struct lbuf * bp) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci unsigned long flags; 80562306a36Sopenharmony_ci struct jfs_log *log = bp->l_log; 80662306a36Sopenharmony_ci struct logpage *lp; 80762306a36Sopenharmony_ci struct tblock *tblk, *temp; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci //LOGGC_LOCK(log); 81062306a36Sopenharmony_ci spin_lock_irqsave(&log->gclock, flags); 81162306a36Sopenharmony_ci /* 81262306a36Sopenharmony_ci * current pageout of group commit completed. 81362306a36Sopenharmony_ci * 81462306a36Sopenharmony_ci * remove/wakeup transactions from commit queue who were 81562306a36Sopenharmony_ci * group committed with the current log page 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) { 81862306a36Sopenharmony_ci if (!(tblk->flag & tblkGC_COMMIT)) 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci /* if transaction was marked GC_COMMIT then 82162306a36Sopenharmony_ci * it has been shipped in the current pageout 82262306a36Sopenharmony_ci * and made it to disk - it is committed. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (bp->l_flag & lbmERROR) 82662306a36Sopenharmony_ci tblk->flag |= tblkGC_ERROR; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* remove it from the commit queue */ 82962306a36Sopenharmony_ci list_del(&tblk->cqueue); 83062306a36Sopenharmony_ci tblk->flag &= ~tblkGC_QUEUE; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (tblk == log->flush_tblk) { 83362306a36Sopenharmony_ci /* we can stop flushing the log now */ 83462306a36Sopenharmony_ci clear_bit(log_FLUSH, &log->flag); 83562306a36Sopenharmony_ci log->flush_tblk = NULL; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk, 83962306a36Sopenharmony_ci tblk->flag); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (!(tblk->xflag & COMMIT_FORCE)) 84262306a36Sopenharmony_ci /* 84362306a36Sopenharmony_ci * Hand tblk over to lazy commit thread 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci txLazyUnlock(tblk); 84662306a36Sopenharmony_ci else { 84762306a36Sopenharmony_ci /* state transition: COMMIT -> COMMITTED */ 84862306a36Sopenharmony_ci tblk->flag |= tblkGC_COMMITTED; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (tblk->flag & tblkGC_READY) 85162306a36Sopenharmony_ci log->gcrtc--; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci LOGGC_WAKEUP(tblk); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* was page full before pageout ? 85762306a36Sopenharmony_ci * (and this is the last tblk bound with the page) 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci if (tblk->flag & tblkGC_FREE) 86062306a36Sopenharmony_ci lbmFree(bp); 86162306a36Sopenharmony_ci /* did page become full after pageout ? 86262306a36Sopenharmony_ci * (and this is the last tblk bound with the page) 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci else if (tblk->flag & tblkGC_EOP) { 86562306a36Sopenharmony_ci /* finalize the page */ 86662306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 86762306a36Sopenharmony_ci bp->l_ceor = bp->l_eor; 86862306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 86962306a36Sopenharmony_ci jfs_info("lmPostGC: calling lbmWrite"); 87062306a36Sopenharmony_ci lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 87162306a36Sopenharmony_ci 1); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* are there any transactions who have entered lnGroupCommit() 87762306a36Sopenharmony_ci * (whose COMMITs are after that of the last log page written. 87862306a36Sopenharmony_ci * They are waiting for new group commit (above at (SLEEP 1)) 87962306a36Sopenharmony_ci * or lazy transactions are on a full (queued) log page, 88062306a36Sopenharmony_ci * select the latest ready transaction as new group leader and 88162306a36Sopenharmony_ci * wake her up to lead her group. 88262306a36Sopenharmony_ci */ 88362306a36Sopenharmony_ci if ((!list_empty(&log->cqueue)) && 88462306a36Sopenharmony_ci ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) || 88562306a36Sopenharmony_ci test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low)) 88662306a36Sopenharmony_ci /* 88762306a36Sopenharmony_ci * Call lmGCwrite with new group leader 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_ci lmGCwrite(log, 1); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* no transaction are ready yet (transactions are only just 89262306a36Sopenharmony_ci * queued (GC_QUEUE) and not entered for group commit yet). 89362306a36Sopenharmony_ci * the first transaction entering group commit 89462306a36Sopenharmony_ci * will elect herself as new group leader. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci else 89762306a36Sopenharmony_ci log->cflag &= ~logGC_PAGEOUT; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci //LOGGC_UNLOCK(log); 90062306a36Sopenharmony_ci spin_unlock_irqrestore(&log->gclock, flags); 90162306a36Sopenharmony_ci return; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/* 90562306a36Sopenharmony_ci * NAME: lmLogSync() 90662306a36Sopenharmony_ci * 90762306a36Sopenharmony_ci * FUNCTION: write log SYNCPT record for specified log 90862306a36Sopenharmony_ci * if new sync address is available 90962306a36Sopenharmony_ci * (normally the case if sync() is executed by back-ground 91062306a36Sopenharmony_ci * process). 91162306a36Sopenharmony_ci * calculate new value of i_nextsync which determines when 91262306a36Sopenharmony_ci * this code is called again. 91362306a36Sopenharmony_ci * 91462306a36Sopenharmony_ci * PARAMETERS: log - log structure 91562306a36Sopenharmony_ci * hard_sync - 1 to force all metadata to be written 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * RETURN: 0 91862306a36Sopenharmony_ci * 91962306a36Sopenharmony_ci * serialization: LOG_LOCK() held on entry/exit 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_cistatic int lmLogSync(struct jfs_log * log, int hard_sync) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci int logsize; 92462306a36Sopenharmony_ci int written; /* written since last syncpt */ 92562306a36Sopenharmony_ci int free; /* free space left available */ 92662306a36Sopenharmony_ci int delta; /* additional delta to write normally */ 92762306a36Sopenharmony_ci int more; /* additional write granted */ 92862306a36Sopenharmony_ci struct lrd lrd; 92962306a36Sopenharmony_ci int lsn; 93062306a36Sopenharmony_ci struct logsyncblk *lp; 93162306a36Sopenharmony_ci unsigned long flags; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* push dirty metapages out to disk */ 93462306a36Sopenharmony_ci if (hard_sync) 93562306a36Sopenharmony_ci write_special_inodes(log, filemap_fdatawrite); 93662306a36Sopenharmony_ci else 93762306a36Sopenharmony_ci write_special_inodes(log, filemap_flush); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * forward syncpt 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci /* if last sync is same as last syncpt, 94362306a36Sopenharmony_ci * invoke sync point forward processing to update sync. 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (log->sync == log->syncpt) { 94762306a36Sopenharmony_ci LOGSYNC_LOCK(log, flags); 94862306a36Sopenharmony_ci if (list_empty(&log->synclist)) 94962306a36Sopenharmony_ci log->sync = log->lsn; 95062306a36Sopenharmony_ci else { 95162306a36Sopenharmony_ci lp = list_entry(log->synclist.next, 95262306a36Sopenharmony_ci struct logsyncblk, synclist); 95362306a36Sopenharmony_ci log->sync = lp->lsn; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci LOGSYNC_UNLOCK(log, flags); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* if sync is different from last syncpt, 96062306a36Sopenharmony_ci * write a SYNCPT record with syncpt = sync. 96162306a36Sopenharmony_ci * reset syncpt = sync 96262306a36Sopenharmony_ci */ 96362306a36Sopenharmony_ci if (log->sync != log->syncpt) { 96462306a36Sopenharmony_ci lrd.logtid = 0; 96562306a36Sopenharmony_ci lrd.backchain = 0; 96662306a36Sopenharmony_ci lrd.type = cpu_to_le16(LOG_SYNCPT); 96762306a36Sopenharmony_ci lrd.length = 0; 96862306a36Sopenharmony_ci lrd.log.syncpt.sync = cpu_to_le32(log->sync); 96962306a36Sopenharmony_ci lsn = lmWriteRecord(log, NULL, &lrd, NULL); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci log->syncpt = log->sync; 97262306a36Sopenharmony_ci } else 97362306a36Sopenharmony_ci lsn = log->lsn; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* 97662306a36Sopenharmony_ci * setup next syncpt trigger (SWAG) 97762306a36Sopenharmony_ci */ 97862306a36Sopenharmony_ci logsize = log->logsize; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci logdiff(written, lsn, log); 98162306a36Sopenharmony_ci free = logsize - written; 98262306a36Sopenharmony_ci delta = LOGSYNC_DELTA(logsize); 98362306a36Sopenharmony_ci more = min(free / 2, delta); 98462306a36Sopenharmony_ci if (more < 2 * LOGPSIZE) { 98562306a36Sopenharmony_ci jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n"); 98662306a36Sopenharmony_ci /* 98762306a36Sopenharmony_ci * log wrapping 98862306a36Sopenharmony_ci * 98962306a36Sopenharmony_ci * option 1 - panic ? No.! 99062306a36Sopenharmony_ci * option 2 - shutdown file systems 99162306a36Sopenharmony_ci * associated with log ? 99262306a36Sopenharmony_ci * option 3 - extend log ? 99362306a36Sopenharmony_ci * option 4 - second chance 99462306a36Sopenharmony_ci * 99562306a36Sopenharmony_ci * mark log wrapped, and continue. 99662306a36Sopenharmony_ci * when all active transactions are completed, 99762306a36Sopenharmony_ci * mark log valid for recovery. 99862306a36Sopenharmony_ci * if crashed during invalid state, log state 99962306a36Sopenharmony_ci * implies invalid log, forcing fsck(). 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci /* mark log state log wrap in log superblock */ 100262306a36Sopenharmony_ci /* log->state = LOGWRAP; */ 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* reset sync point computation */ 100562306a36Sopenharmony_ci log->syncpt = log->sync = lsn; 100662306a36Sopenharmony_ci log->nextsync = delta; 100762306a36Sopenharmony_ci } else 100862306a36Sopenharmony_ci /* next syncpt trigger = written + more */ 100962306a36Sopenharmony_ci log->nextsync = written + more; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* if number of bytes written from last sync point is more 101262306a36Sopenharmony_ci * than 1/4 of the log size, stop new transactions from 101362306a36Sopenharmony_ci * starting until all current transactions are completed 101462306a36Sopenharmony_ci * by setting syncbarrier flag. 101562306a36Sopenharmony_ci */ 101662306a36Sopenharmony_ci if (!test_bit(log_SYNCBARRIER, &log->flag) && 101762306a36Sopenharmony_ci (written > LOGSYNC_BARRIER(logsize)) && log->active) { 101862306a36Sopenharmony_ci set_bit(log_SYNCBARRIER, &log->flag); 101962306a36Sopenharmony_ci jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn, 102062306a36Sopenharmony_ci log->syncpt); 102162306a36Sopenharmony_ci /* 102262306a36Sopenharmony_ci * We may have to initiate group commit 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci jfs_flush_journal(log, 0); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return lsn; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/* 103162306a36Sopenharmony_ci * NAME: jfs_syncpt 103262306a36Sopenharmony_ci * 103362306a36Sopenharmony_ci * FUNCTION: write log SYNCPT record for specified log 103462306a36Sopenharmony_ci * 103562306a36Sopenharmony_ci * PARAMETERS: log - log structure 103662306a36Sopenharmony_ci * hard_sync - set to 1 to force metadata to be written 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_civoid jfs_syncpt(struct jfs_log *log, int hard_sync) 103962306a36Sopenharmony_ci{ LOG_LOCK(log); 104062306a36Sopenharmony_ci if (!test_bit(log_QUIESCE, &log->flag)) 104162306a36Sopenharmony_ci lmLogSync(log, hard_sync); 104262306a36Sopenharmony_ci LOG_UNLOCK(log); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci/* 104662306a36Sopenharmony_ci * NAME: lmLogOpen() 104762306a36Sopenharmony_ci * 104862306a36Sopenharmony_ci * FUNCTION: open the log on first open; 104962306a36Sopenharmony_ci * insert filesystem in the active list of the log. 105062306a36Sopenharmony_ci * 105162306a36Sopenharmony_ci * PARAMETER: ipmnt - file system mount inode 105262306a36Sopenharmony_ci * iplog - log inode (out) 105362306a36Sopenharmony_ci * 105462306a36Sopenharmony_ci * RETURN: 105562306a36Sopenharmony_ci * 105662306a36Sopenharmony_ci * serialization: 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ciint lmLogOpen(struct super_block *sb) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci int rc; 106162306a36Sopenharmony_ci struct block_device *bdev; 106262306a36Sopenharmony_ci struct jfs_log *log; 106362306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (sbi->flag & JFS_NOINTEGRITY) 106662306a36Sopenharmony_ci return open_dummy_log(sb); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci if (sbi->mntflag & JFS_INLINELOG) 106962306a36Sopenharmony_ci return open_inline_log(sb); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci mutex_lock(&jfs_log_mutex); 107262306a36Sopenharmony_ci list_for_each_entry(log, &jfs_external_logs, journal_list) { 107362306a36Sopenharmony_ci if (log->bdev->bd_dev == sbi->logdev) { 107462306a36Sopenharmony_ci if (!uuid_equal(&log->uuid, &sbi->loguuid)) { 107562306a36Sopenharmony_ci jfs_warn("wrong uuid on JFS journal"); 107662306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 107762306a36Sopenharmony_ci return -EINVAL; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci /* 108062306a36Sopenharmony_ci * add file system to log active file system list 108162306a36Sopenharmony_ci */ 108262306a36Sopenharmony_ci if ((rc = lmLogFileSystem(log, sbi, 1))) { 108362306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 108462306a36Sopenharmony_ci return rc; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci goto journal_found; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) { 109162306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 109262306a36Sopenharmony_ci return -ENOMEM; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci INIT_LIST_HEAD(&log->sb_list); 109562306a36Sopenharmony_ci init_waitqueue_head(&log->syncwait); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * external log as separate logical volume 109962306a36Sopenharmony_ci * 110062306a36Sopenharmony_ci * file systems to log may have n-to-1 relationship; 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci bdev = blkdev_get_by_dev(sbi->logdev, BLK_OPEN_READ | BLK_OPEN_WRITE, 110462306a36Sopenharmony_ci log, NULL); 110562306a36Sopenharmony_ci if (IS_ERR(bdev)) { 110662306a36Sopenharmony_ci rc = PTR_ERR(bdev); 110762306a36Sopenharmony_ci goto free; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci log->bdev = bdev; 111162306a36Sopenharmony_ci uuid_copy(&log->uuid, &sbi->loguuid); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * initialize log: 111562306a36Sopenharmony_ci */ 111662306a36Sopenharmony_ci if ((rc = lmLogInit(log))) 111762306a36Sopenharmony_ci goto close; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci list_add(&log->journal_list, &jfs_external_logs); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* 112262306a36Sopenharmony_ci * add file system to log active file system list 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci if ((rc = lmLogFileSystem(log, sbi, 1))) 112562306a36Sopenharmony_ci goto shutdown; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cijournal_found: 112862306a36Sopenharmony_ci LOG_LOCK(log); 112962306a36Sopenharmony_ci list_add(&sbi->log_list, &log->sb_list); 113062306a36Sopenharmony_ci sbi->log = log; 113162306a36Sopenharmony_ci LOG_UNLOCK(log); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 113462306a36Sopenharmony_ci return 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* 113762306a36Sopenharmony_ci * unwind on error 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_ci shutdown: /* unwind lbmLogInit() */ 114062306a36Sopenharmony_ci list_del(&log->journal_list); 114162306a36Sopenharmony_ci lbmLogShutdown(log); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci close: /* close external log device */ 114462306a36Sopenharmony_ci blkdev_put(bdev, log); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci free: /* free log descriptor */ 114762306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 114862306a36Sopenharmony_ci kfree(log); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci jfs_warn("lmLogOpen: exit(%d)", rc); 115162306a36Sopenharmony_ci return rc; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int open_inline_log(struct super_block *sb) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct jfs_log *log; 115762306a36Sopenharmony_ci int rc; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) 116062306a36Sopenharmony_ci return -ENOMEM; 116162306a36Sopenharmony_ci INIT_LIST_HEAD(&log->sb_list); 116262306a36Sopenharmony_ci init_waitqueue_head(&log->syncwait); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci set_bit(log_INLINELOG, &log->flag); 116562306a36Sopenharmony_ci log->bdev = sb->s_bdev; 116662306a36Sopenharmony_ci log->base = addressPXD(&JFS_SBI(sb)->logpxd); 116762306a36Sopenharmony_ci log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >> 116862306a36Sopenharmony_ci (L2LOGPSIZE - sb->s_blocksize_bits); 116962306a36Sopenharmony_ci log->l2bsize = sb->s_blocksize_bits; 117062306a36Sopenharmony_ci ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* 117362306a36Sopenharmony_ci * initialize log. 117462306a36Sopenharmony_ci */ 117562306a36Sopenharmony_ci if ((rc = lmLogInit(log))) { 117662306a36Sopenharmony_ci kfree(log); 117762306a36Sopenharmony_ci jfs_warn("lmLogOpen: exit(%d)", rc); 117862306a36Sopenharmony_ci return rc; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci list_add(&JFS_SBI(sb)->log_list, &log->sb_list); 118262306a36Sopenharmony_ci JFS_SBI(sb)->log = log; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci return rc; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic int open_dummy_log(struct super_block *sb) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci int rc; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci mutex_lock(&jfs_log_mutex); 119262306a36Sopenharmony_ci if (!dummy_log) { 119362306a36Sopenharmony_ci dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL); 119462306a36Sopenharmony_ci if (!dummy_log) { 119562306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 119662306a36Sopenharmony_ci return -ENOMEM; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci INIT_LIST_HEAD(&dummy_log->sb_list); 119962306a36Sopenharmony_ci init_waitqueue_head(&dummy_log->syncwait); 120062306a36Sopenharmony_ci dummy_log->no_integrity = 1; 120162306a36Sopenharmony_ci /* Make up some stuff */ 120262306a36Sopenharmony_ci dummy_log->base = 0; 120362306a36Sopenharmony_ci dummy_log->size = 1024; 120462306a36Sopenharmony_ci rc = lmLogInit(dummy_log); 120562306a36Sopenharmony_ci if (rc) { 120662306a36Sopenharmony_ci kfree(dummy_log); 120762306a36Sopenharmony_ci dummy_log = NULL; 120862306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 120962306a36Sopenharmony_ci return rc; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci LOG_LOCK(dummy_log); 121462306a36Sopenharmony_ci list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list); 121562306a36Sopenharmony_ci JFS_SBI(sb)->log = dummy_log; 121662306a36Sopenharmony_ci LOG_UNLOCK(dummy_log); 121762306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci return 0; 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci/* 122362306a36Sopenharmony_ci * NAME: lmLogInit() 122462306a36Sopenharmony_ci * 122562306a36Sopenharmony_ci * FUNCTION: log initialization at first log open. 122662306a36Sopenharmony_ci * 122762306a36Sopenharmony_ci * logredo() (or logformat()) should have been run previously. 122862306a36Sopenharmony_ci * initialize the log from log superblock. 122962306a36Sopenharmony_ci * set the log state in the superblock to LOGMOUNT and 123062306a36Sopenharmony_ci * write SYNCPT log record. 123162306a36Sopenharmony_ci * 123262306a36Sopenharmony_ci * PARAMETER: log - log structure 123362306a36Sopenharmony_ci * 123462306a36Sopenharmony_ci * RETURN: 0 - if ok 123562306a36Sopenharmony_ci * -EINVAL - bad log magic number or superblock dirty 123662306a36Sopenharmony_ci * error returned from logwait() 123762306a36Sopenharmony_ci * 123862306a36Sopenharmony_ci * serialization: single first open thread 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_ciint lmLogInit(struct jfs_log * log) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci int rc = 0; 124362306a36Sopenharmony_ci struct lrd lrd; 124462306a36Sopenharmony_ci struct logsuper *logsuper; 124562306a36Sopenharmony_ci struct lbuf *bpsuper; 124662306a36Sopenharmony_ci struct lbuf *bp; 124762306a36Sopenharmony_ci struct logpage *lp; 124862306a36Sopenharmony_ci int lsn = 0; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci jfs_info("lmLogInit: log:0x%p", log); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* initialize the group commit serialization lock */ 125362306a36Sopenharmony_ci LOGGC_LOCK_INIT(log); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci /* allocate/initialize the log write serialization lock */ 125662306a36Sopenharmony_ci LOG_LOCK_INIT(log); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci LOGSYNC_LOCK_INIT(log); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci INIT_LIST_HEAD(&log->synclist); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci INIT_LIST_HEAD(&log->cqueue); 126362306a36Sopenharmony_ci log->flush_tblk = NULL; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci log->count = 0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* 126862306a36Sopenharmony_ci * initialize log i/o 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci if ((rc = lbmLogInit(log))) 127162306a36Sopenharmony_ci return rc; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (!test_bit(log_INLINELOG, &log->flag)) 127462306a36Sopenharmony_ci log->l2bsize = L2LOGPSIZE; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* check for disabled journaling to disk */ 127762306a36Sopenharmony_ci if (log->no_integrity) { 127862306a36Sopenharmony_ci /* 127962306a36Sopenharmony_ci * Journal pages will still be filled. When the time comes 128062306a36Sopenharmony_ci * to actually do the I/O, the write is not done, and the 128162306a36Sopenharmony_ci * endio routine is called directly. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ci bp = lbmAllocate(log , 0); 128462306a36Sopenharmony_ci log->bp = bp; 128562306a36Sopenharmony_ci bp->l_pn = bp->l_eor = 0; 128662306a36Sopenharmony_ci } else { 128762306a36Sopenharmony_ci /* 128862306a36Sopenharmony_ci * validate log superblock 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_ci if ((rc = lbmRead(log, 1, &bpsuper))) 129162306a36Sopenharmony_ci goto errout10; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci logsuper = (struct logsuper *) bpsuper->l_ldata; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (logsuper->magic != cpu_to_le32(LOGMAGIC)) { 129662306a36Sopenharmony_ci jfs_warn("*** Log Format Error ! ***"); 129762306a36Sopenharmony_ci rc = -EINVAL; 129862306a36Sopenharmony_ci goto errout20; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* logredo() should have been run successfully. */ 130262306a36Sopenharmony_ci if (logsuper->state != cpu_to_le32(LOGREDONE)) { 130362306a36Sopenharmony_ci jfs_warn("*** Log Is Dirty ! ***"); 130462306a36Sopenharmony_ci rc = -EINVAL; 130562306a36Sopenharmony_ci goto errout20; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* initialize log from log superblock */ 130962306a36Sopenharmony_ci if (test_bit(log_INLINELOG,&log->flag)) { 131062306a36Sopenharmony_ci if (log->size != le32_to_cpu(logsuper->size)) { 131162306a36Sopenharmony_ci rc = -EINVAL; 131262306a36Sopenharmony_ci goto errout20; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x", 131562306a36Sopenharmony_ci log, (unsigned long long)log->base, log->size); 131662306a36Sopenharmony_ci } else { 131762306a36Sopenharmony_ci if (!uuid_equal(&logsuper->uuid, &log->uuid)) { 131862306a36Sopenharmony_ci jfs_warn("wrong uuid on JFS log device"); 131962306a36Sopenharmony_ci rc = -EINVAL; 132062306a36Sopenharmony_ci goto errout20; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci log->size = le32_to_cpu(logsuper->size); 132362306a36Sopenharmony_ci log->l2bsize = le32_to_cpu(logsuper->l2bsize); 132462306a36Sopenharmony_ci jfs_info("lmLogInit: external log:0x%p base:0x%Lx size:0x%x", 132562306a36Sopenharmony_ci log, (unsigned long long)log->base, log->size); 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci log->page = le32_to_cpu(logsuper->end) / LOGPSIZE; 132962306a36Sopenharmony_ci log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* 133262306a36Sopenharmony_ci * initialize for log append write mode 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci /* establish current/end-of-log page/buffer */ 133562306a36Sopenharmony_ci if ((rc = lbmRead(log, log->page, &bp))) 133662306a36Sopenharmony_ci goto errout20; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci jfs_info("lmLogInit: lsn:0x%x page:%d eor:%d:%d", 134162306a36Sopenharmony_ci le32_to_cpu(logsuper->end), log->page, log->eor, 134262306a36Sopenharmony_ci le16_to_cpu(lp->h.eor)); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci log->bp = bp; 134562306a36Sopenharmony_ci bp->l_pn = log->page; 134662306a36Sopenharmony_ci bp->l_eor = log->eor; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* if current page is full, move on to next page */ 134962306a36Sopenharmony_ci if (log->eor >= LOGPSIZE - LOGPTLRSIZE) 135062306a36Sopenharmony_ci lmNextPage(log); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* 135362306a36Sopenharmony_ci * initialize log syncpoint 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci /* 135662306a36Sopenharmony_ci * write the first SYNCPT record with syncpoint = 0 135762306a36Sopenharmony_ci * (i.e., log redo up to HERE !); 135862306a36Sopenharmony_ci * remove current page from lbm write queue at end of pageout 135962306a36Sopenharmony_ci * (to write log superblock update), but do not release to 136062306a36Sopenharmony_ci * freelist; 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci lrd.logtid = 0; 136362306a36Sopenharmony_ci lrd.backchain = 0; 136462306a36Sopenharmony_ci lrd.type = cpu_to_le16(LOG_SYNCPT); 136562306a36Sopenharmony_ci lrd.length = 0; 136662306a36Sopenharmony_ci lrd.log.syncpt.sync = 0; 136762306a36Sopenharmony_ci lsn = lmWriteRecord(log, NULL, &lrd, NULL); 136862306a36Sopenharmony_ci bp = log->bp; 136962306a36Sopenharmony_ci bp->l_ceor = bp->l_eor; 137062306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 137162306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 137262306a36Sopenharmony_ci lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0); 137362306a36Sopenharmony_ci if ((rc = lbmIOWait(bp, 0))) 137462306a36Sopenharmony_ci goto errout30; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* 137762306a36Sopenharmony_ci * update/write superblock 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_ci logsuper->state = cpu_to_le32(LOGMOUNT); 138062306a36Sopenharmony_ci log->serial = le32_to_cpu(logsuper->serial) + 1; 138162306a36Sopenharmony_ci logsuper->serial = cpu_to_le32(log->serial); 138262306a36Sopenharmony_ci lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 138362306a36Sopenharmony_ci if ((rc = lbmIOWait(bpsuper, lbmFREE))) 138462306a36Sopenharmony_ci goto errout30; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* initialize logsync parameters */ 138862306a36Sopenharmony_ci log->logsize = (log->size - 2) << L2LOGPSIZE; 138962306a36Sopenharmony_ci log->lsn = lsn; 139062306a36Sopenharmony_ci log->syncpt = lsn; 139162306a36Sopenharmony_ci log->sync = log->syncpt; 139262306a36Sopenharmony_ci log->nextsync = LOGSYNC_DELTA(log->logsize); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci jfs_info("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x", 139562306a36Sopenharmony_ci log->lsn, log->syncpt, log->sync); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* 139862306a36Sopenharmony_ci * initialize for lazy/group commit 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_ci log->clsn = lsn; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return 0; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci /* 140562306a36Sopenharmony_ci * unwind on error 140662306a36Sopenharmony_ci */ 140762306a36Sopenharmony_ci errout30: /* release log page */ 140862306a36Sopenharmony_ci log->wqueue = NULL; 140962306a36Sopenharmony_ci bp->l_wqnext = NULL; 141062306a36Sopenharmony_ci lbmFree(bp); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci errout20: /* release log superblock */ 141362306a36Sopenharmony_ci lbmFree(bpsuper); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci errout10: /* unwind lbmLogInit() */ 141662306a36Sopenharmony_ci lbmLogShutdown(log); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci jfs_warn("lmLogInit: exit(%d)", rc); 141962306a36Sopenharmony_ci return rc; 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci/* 142462306a36Sopenharmony_ci * NAME: lmLogClose() 142562306a36Sopenharmony_ci * 142662306a36Sopenharmony_ci * FUNCTION: remove file system <ipmnt> from active list of log <iplog> 142762306a36Sopenharmony_ci * and close it on last close. 142862306a36Sopenharmony_ci * 142962306a36Sopenharmony_ci * PARAMETER: sb - superblock 143062306a36Sopenharmony_ci * 143162306a36Sopenharmony_ci * RETURN: errors from subroutines 143262306a36Sopenharmony_ci * 143362306a36Sopenharmony_ci * serialization: 143462306a36Sopenharmony_ci */ 143562306a36Sopenharmony_ciint lmLogClose(struct super_block *sb) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 143862306a36Sopenharmony_ci struct jfs_log *log = sbi->log; 143962306a36Sopenharmony_ci struct block_device *bdev; 144062306a36Sopenharmony_ci int rc = 0; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci jfs_info("lmLogClose: log:0x%p", log); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci mutex_lock(&jfs_log_mutex); 144562306a36Sopenharmony_ci LOG_LOCK(log); 144662306a36Sopenharmony_ci list_del(&sbi->log_list); 144762306a36Sopenharmony_ci LOG_UNLOCK(log); 144862306a36Sopenharmony_ci sbi->log = NULL; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci /* 145162306a36Sopenharmony_ci * We need to make sure all of the "written" metapages 145262306a36Sopenharmony_ci * actually make it to disk 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_ci sync_blockdev(sb->s_bdev); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (test_bit(log_INLINELOG, &log->flag)) { 145762306a36Sopenharmony_ci /* 145862306a36Sopenharmony_ci * in-line log in host file system 145962306a36Sopenharmony_ci */ 146062306a36Sopenharmony_ci rc = lmLogShutdown(log); 146162306a36Sopenharmony_ci kfree(log); 146262306a36Sopenharmony_ci goto out; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (!log->no_integrity) 146662306a36Sopenharmony_ci lmLogFileSystem(log, sbi, 0); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (!list_empty(&log->sb_list)) 146962306a36Sopenharmony_ci goto out; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* 147262306a36Sopenharmony_ci * TODO: ensure that the dummy_log is in a state to allow 147362306a36Sopenharmony_ci * lbmLogShutdown to deallocate all the buffers and call 147462306a36Sopenharmony_ci * kfree against dummy_log. For now, leave dummy_log & its 147562306a36Sopenharmony_ci * buffers in memory, and resuse if another no-integrity mount 147662306a36Sopenharmony_ci * is requested. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_ci if (log->no_integrity) 147962306a36Sopenharmony_ci goto out; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci /* 148262306a36Sopenharmony_ci * external log as separate logical volume 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_ci list_del(&log->journal_list); 148562306a36Sopenharmony_ci bdev = log->bdev; 148662306a36Sopenharmony_ci rc = lmLogShutdown(log); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci blkdev_put(bdev, log); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci kfree(log); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci out: 149362306a36Sopenharmony_ci mutex_unlock(&jfs_log_mutex); 149462306a36Sopenharmony_ci jfs_info("lmLogClose: exit(%d)", rc); 149562306a36Sopenharmony_ci return rc; 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci/* 150062306a36Sopenharmony_ci * NAME: jfs_flush_journal() 150162306a36Sopenharmony_ci * 150262306a36Sopenharmony_ci * FUNCTION: initiate write of any outstanding transactions to the journal 150362306a36Sopenharmony_ci * and optionally wait until they are all written to disk 150462306a36Sopenharmony_ci * 150562306a36Sopenharmony_ci * wait == 0 flush until latest txn is committed, don't wait 150662306a36Sopenharmony_ci * wait == 1 flush until latest txn is committed, wait 150762306a36Sopenharmony_ci * wait > 1 flush until all txn's are complete, wait 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_civoid jfs_flush_journal(struct jfs_log *log, int wait) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci int i; 151262306a36Sopenharmony_ci struct tblock *target = NULL; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* jfs_write_inode may call us during read-only mount */ 151562306a36Sopenharmony_ci if (!log) 151662306a36Sopenharmony_ci return; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci LOGGC_LOCK(log); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (!list_empty(&log->cqueue)) { 152362306a36Sopenharmony_ci /* 152462306a36Sopenharmony_ci * This ensures that we will keep writing to the journal as long 152562306a36Sopenharmony_ci * as there are unwritten commit records 152662306a36Sopenharmony_ci */ 152762306a36Sopenharmony_ci target = list_entry(log->cqueue.prev, struct tblock, cqueue); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (test_bit(log_FLUSH, &log->flag)) { 153062306a36Sopenharmony_ci /* 153162306a36Sopenharmony_ci * We're already flushing. 153262306a36Sopenharmony_ci * if flush_tblk is NULL, we are flushing everything, 153362306a36Sopenharmony_ci * so leave it that way. Otherwise, update it to the 153462306a36Sopenharmony_ci * latest transaction 153562306a36Sopenharmony_ci */ 153662306a36Sopenharmony_ci if (log->flush_tblk) 153762306a36Sopenharmony_ci log->flush_tblk = target; 153862306a36Sopenharmony_ci } else { 153962306a36Sopenharmony_ci /* Only flush until latest transaction is committed */ 154062306a36Sopenharmony_ci log->flush_tblk = target; 154162306a36Sopenharmony_ci set_bit(log_FLUSH, &log->flag); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* 154462306a36Sopenharmony_ci * Initiate I/O on outstanding transactions 154562306a36Sopenharmony_ci */ 154662306a36Sopenharmony_ci if (!(log->cflag & logGC_PAGEOUT)) { 154762306a36Sopenharmony_ci log->cflag |= logGC_PAGEOUT; 154862306a36Sopenharmony_ci lmGCwrite(log, 0); 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) { 155362306a36Sopenharmony_ci /* Flush until all activity complete */ 155462306a36Sopenharmony_ci set_bit(log_FLUSH, &log->flag); 155562306a36Sopenharmony_ci log->flush_tblk = NULL; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (wait && target && !(target->flag & tblkGC_COMMITTED)) { 155962306a36Sopenharmony_ci DECLARE_WAITQUEUE(__wait, current); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci add_wait_queue(&target->gcwait, &__wait); 156262306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 156362306a36Sopenharmony_ci LOGGC_UNLOCK(log); 156462306a36Sopenharmony_ci schedule(); 156562306a36Sopenharmony_ci LOGGC_LOCK(log); 156662306a36Sopenharmony_ci remove_wait_queue(&target->gcwait, &__wait); 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci LOGGC_UNLOCK(log); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (wait < 2) 157162306a36Sopenharmony_ci return; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci write_special_inodes(log, filemap_fdatawrite); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* 157662306a36Sopenharmony_ci * If there was recent activity, we may need to wait 157762306a36Sopenharmony_ci * for the lazycommit thread to catch up 157862306a36Sopenharmony_ci */ 157962306a36Sopenharmony_ci if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { 158062306a36Sopenharmony_ci for (i = 0; i < 200; i++) { /* Too much? */ 158162306a36Sopenharmony_ci msleep(250); 158262306a36Sopenharmony_ci write_special_inodes(log, filemap_fdatawrite); 158362306a36Sopenharmony_ci if (list_empty(&log->cqueue) && 158462306a36Sopenharmony_ci list_empty(&log->synclist)) 158562306a36Sopenharmony_ci break; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci assert(list_empty(&log->cqueue)); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci#ifdef CONFIG_JFS_DEBUG 159162306a36Sopenharmony_ci if (!list_empty(&log->synclist)) { 159262306a36Sopenharmony_ci struct logsyncblk *lp; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci printk(KERN_ERR "jfs_flush_journal: synclist not empty\n"); 159562306a36Sopenharmony_ci list_for_each_entry(lp, &log->synclist, synclist) { 159662306a36Sopenharmony_ci if (lp->xflag & COMMIT_PAGE) { 159762306a36Sopenharmony_ci struct metapage *mp = (struct metapage *)lp; 159862306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "metapage: ", 159962306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, 160062306a36Sopenharmony_ci mp, sizeof(struct metapage), 0); 160162306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "page: ", 160262306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 160362306a36Sopenharmony_ci sizeof(long), mp->page, 160462306a36Sopenharmony_ci sizeof(struct page), 0); 160562306a36Sopenharmony_ci } else 160662306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "tblock:", 160762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, 160862306a36Sopenharmony_ci lp, sizeof(struct tblock), 0); 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci#else 161262306a36Sopenharmony_ci WARN_ON(!list_empty(&log->synclist)); 161362306a36Sopenharmony_ci#endif 161462306a36Sopenharmony_ci clear_bit(log_FLUSH, &log->flag); 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci/* 161862306a36Sopenharmony_ci * NAME: lmLogShutdown() 161962306a36Sopenharmony_ci * 162062306a36Sopenharmony_ci * FUNCTION: log shutdown at last LogClose(). 162162306a36Sopenharmony_ci * 162262306a36Sopenharmony_ci * write log syncpt record. 162362306a36Sopenharmony_ci * update super block to set redone flag to 0. 162462306a36Sopenharmony_ci * 162562306a36Sopenharmony_ci * PARAMETER: log - log inode 162662306a36Sopenharmony_ci * 162762306a36Sopenharmony_ci * RETURN: 0 - success 162862306a36Sopenharmony_ci * 162962306a36Sopenharmony_ci * serialization: single last close thread 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ciint lmLogShutdown(struct jfs_log * log) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci int rc; 163462306a36Sopenharmony_ci struct lrd lrd; 163562306a36Sopenharmony_ci int lsn; 163662306a36Sopenharmony_ci struct logsuper *logsuper; 163762306a36Sopenharmony_ci struct lbuf *bpsuper; 163862306a36Sopenharmony_ci struct lbuf *bp; 163962306a36Sopenharmony_ci struct logpage *lp; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci jfs_info("lmLogShutdown: log:0x%p", log); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci jfs_flush_journal(log, 2); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* 164662306a36Sopenharmony_ci * write the last SYNCPT record with syncpoint = 0 164762306a36Sopenharmony_ci * (i.e., log redo up to HERE !) 164862306a36Sopenharmony_ci */ 164962306a36Sopenharmony_ci lrd.logtid = 0; 165062306a36Sopenharmony_ci lrd.backchain = 0; 165162306a36Sopenharmony_ci lrd.type = cpu_to_le16(LOG_SYNCPT); 165262306a36Sopenharmony_ci lrd.length = 0; 165362306a36Sopenharmony_ci lrd.log.syncpt.sync = 0; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci lsn = lmWriteRecord(log, NULL, &lrd, NULL); 165662306a36Sopenharmony_ci bp = log->bp; 165762306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 165862306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); 165962306a36Sopenharmony_ci lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0); 166062306a36Sopenharmony_ci lbmIOWait(log->bp, lbmFREE); 166162306a36Sopenharmony_ci log->bp = NULL; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* 166462306a36Sopenharmony_ci * synchronous update log superblock 166562306a36Sopenharmony_ci * mark log state as shutdown cleanly 166662306a36Sopenharmony_ci * (i.e., Log does not need to be replayed). 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ci if ((rc = lbmRead(log, 1, &bpsuper))) 166962306a36Sopenharmony_ci goto out; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci logsuper = (struct logsuper *) bpsuper->l_ldata; 167262306a36Sopenharmony_ci logsuper->state = cpu_to_le32(LOGREDONE); 167362306a36Sopenharmony_ci logsuper->end = cpu_to_le32(lsn); 167462306a36Sopenharmony_ci lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 167562306a36Sopenharmony_ci rc = lbmIOWait(bpsuper, lbmFREE); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d", 167862306a36Sopenharmony_ci lsn, log->page, log->eor); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci out: 168162306a36Sopenharmony_ci /* 168262306a36Sopenharmony_ci * shutdown per log i/o 168362306a36Sopenharmony_ci */ 168462306a36Sopenharmony_ci lbmLogShutdown(log); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (rc) { 168762306a36Sopenharmony_ci jfs_warn("lmLogShutdown: exit(%d)", rc); 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci return rc; 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci/* 169462306a36Sopenharmony_ci * NAME: lmLogFileSystem() 169562306a36Sopenharmony_ci * 169662306a36Sopenharmony_ci * FUNCTION: insert (<activate> = true)/remove (<activate> = false) 169762306a36Sopenharmony_ci * file system into/from log active file system list. 169862306a36Sopenharmony_ci * 169962306a36Sopenharmony_ci * PARAMETE: log - pointer to logs inode. 170062306a36Sopenharmony_ci * fsdev - kdev_t of filesystem. 170162306a36Sopenharmony_ci * serial - pointer to returned log serial number 170262306a36Sopenharmony_ci * activate - insert/remove device from active list. 170362306a36Sopenharmony_ci * 170462306a36Sopenharmony_ci * RETURN: 0 - success 170562306a36Sopenharmony_ci * errors returned by vms_iowait(). 170662306a36Sopenharmony_ci */ 170762306a36Sopenharmony_cistatic int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi, 170862306a36Sopenharmony_ci int activate) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci int rc = 0; 171162306a36Sopenharmony_ci int i; 171262306a36Sopenharmony_ci struct logsuper *logsuper; 171362306a36Sopenharmony_ci struct lbuf *bpsuper; 171462306a36Sopenharmony_ci uuid_t *uuid = &sbi->uuid; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* 171762306a36Sopenharmony_ci * insert/remove file system device to log active file system list. 171862306a36Sopenharmony_ci */ 171962306a36Sopenharmony_ci if ((rc = lbmRead(log, 1, &bpsuper))) 172062306a36Sopenharmony_ci return rc; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci logsuper = (struct logsuper *) bpsuper->l_ldata; 172362306a36Sopenharmony_ci if (activate) { 172462306a36Sopenharmony_ci for (i = 0; i < MAX_ACTIVE; i++) 172562306a36Sopenharmony_ci if (uuid_is_null(&logsuper->active[i].uuid)) { 172662306a36Sopenharmony_ci uuid_copy(&logsuper->active[i].uuid, uuid); 172762306a36Sopenharmony_ci sbi->aggregate = i; 172862306a36Sopenharmony_ci break; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci if (i == MAX_ACTIVE) { 173162306a36Sopenharmony_ci jfs_warn("Too many file systems sharing journal!"); 173262306a36Sopenharmony_ci lbmFree(bpsuper); 173362306a36Sopenharmony_ci return -EMFILE; /* Is there a better rc? */ 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci } else { 173662306a36Sopenharmony_ci for (i = 0; i < MAX_ACTIVE; i++) 173762306a36Sopenharmony_ci if (uuid_equal(&logsuper->active[i].uuid, uuid)) { 173862306a36Sopenharmony_ci uuid_copy(&logsuper->active[i].uuid, 173962306a36Sopenharmony_ci &uuid_null); 174062306a36Sopenharmony_ci break; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci if (i == MAX_ACTIVE) { 174362306a36Sopenharmony_ci jfs_warn("Somebody stomped on the journal!"); 174462306a36Sopenharmony_ci lbmFree(bpsuper); 174562306a36Sopenharmony_ci return -EIO; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci /* 175162306a36Sopenharmony_ci * synchronous write log superblock: 175262306a36Sopenharmony_ci * 175362306a36Sopenharmony_ci * write sidestream bypassing write queue: 175462306a36Sopenharmony_ci * at file system mount, log super block is updated for 175562306a36Sopenharmony_ci * activation of the file system before any log record 175662306a36Sopenharmony_ci * (MOUNT record) of the file system, and at file system 175762306a36Sopenharmony_ci * unmount, all meta data for the file system has been 175862306a36Sopenharmony_ci * flushed before log super block is updated for deactivation 175962306a36Sopenharmony_ci * of the file system. 176062306a36Sopenharmony_ci */ 176162306a36Sopenharmony_ci lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); 176262306a36Sopenharmony_ci rc = lbmIOWait(bpsuper, lbmFREE); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci return rc; 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci/* 176862306a36Sopenharmony_ci * log buffer manager (lbm) 176962306a36Sopenharmony_ci * ------------------------ 177062306a36Sopenharmony_ci * 177162306a36Sopenharmony_ci * special purpose buffer manager supporting log i/o requirements. 177262306a36Sopenharmony_ci * 177362306a36Sopenharmony_ci * per log write queue: 177462306a36Sopenharmony_ci * log pageout occurs in serial order by fifo write queue and 177562306a36Sopenharmony_ci * restricting to a single i/o in pregress at any one time. 177662306a36Sopenharmony_ci * a circular singly-linked list 177762306a36Sopenharmony_ci * (log->wrqueue points to the tail, and buffers are linked via 177862306a36Sopenharmony_ci * bp->wrqueue field), and 177962306a36Sopenharmony_ci * maintains log page in pageout ot waiting for pageout in serial pageout. 178062306a36Sopenharmony_ci */ 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci/* 178362306a36Sopenharmony_ci * lbmLogInit() 178462306a36Sopenharmony_ci * 178562306a36Sopenharmony_ci * initialize per log I/O setup at lmLogInit() 178662306a36Sopenharmony_ci */ 178762306a36Sopenharmony_cistatic int lbmLogInit(struct jfs_log * log) 178862306a36Sopenharmony_ci{ /* log inode */ 178962306a36Sopenharmony_ci int i; 179062306a36Sopenharmony_ci struct lbuf *lbuf; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci jfs_info("lbmLogInit: log:0x%p", log); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci /* initialize current buffer cursor */ 179562306a36Sopenharmony_ci log->bp = NULL; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci /* initialize log device write queue */ 179862306a36Sopenharmony_ci log->wqueue = NULL; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* 180162306a36Sopenharmony_ci * Each log has its own buffer pages allocated to it. These are 180262306a36Sopenharmony_ci * not managed by the page cache. This ensures that a transaction 180362306a36Sopenharmony_ci * writing to the log does not block trying to allocate a page from 180462306a36Sopenharmony_ci * the page cache (for the log). This would be bad, since page 180562306a36Sopenharmony_ci * allocation waits on the kswapd thread that may be committing inodes 180662306a36Sopenharmony_ci * which would cause log activity. Was that clear? I'm trying to 180762306a36Sopenharmony_ci * avoid deadlock here. 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_ci init_waitqueue_head(&log->free_wait); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci log->lbuf_free = NULL; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci for (i = 0; i < LOGPAGES;) { 181462306a36Sopenharmony_ci char *buffer; 181562306a36Sopenharmony_ci uint offset; 181662306a36Sopenharmony_ci struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (!page) 181962306a36Sopenharmony_ci goto error; 182062306a36Sopenharmony_ci buffer = page_address(page); 182162306a36Sopenharmony_ci for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) { 182262306a36Sopenharmony_ci lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL); 182362306a36Sopenharmony_ci if (lbuf == NULL) { 182462306a36Sopenharmony_ci if (offset == 0) 182562306a36Sopenharmony_ci __free_page(page); 182662306a36Sopenharmony_ci goto error; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci if (offset) /* we already have one reference */ 182962306a36Sopenharmony_ci get_page(page); 183062306a36Sopenharmony_ci lbuf->l_offset = offset; 183162306a36Sopenharmony_ci lbuf->l_ldata = buffer + offset; 183262306a36Sopenharmony_ci lbuf->l_page = page; 183362306a36Sopenharmony_ci lbuf->l_log = log; 183462306a36Sopenharmony_ci init_waitqueue_head(&lbuf->l_ioevent); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci lbuf->l_freelist = log->lbuf_free; 183762306a36Sopenharmony_ci log->lbuf_free = lbuf; 183862306a36Sopenharmony_ci i++; 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci return (0); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci error: 184562306a36Sopenharmony_ci lbmLogShutdown(log); 184662306a36Sopenharmony_ci return -ENOMEM; 184762306a36Sopenharmony_ci} 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci/* 185162306a36Sopenharmony_ci * lbmLogShutdown() 185262306a36Sopenharmony_ci * 185362306a36Sopenharmony_ci * finalize per log I/O setup at lmLogShutdown() 185462306a36Sopenharmony_ci */ 185562306a36Sopenharmony_cistatic void lbmLogShutdown(struct jfs_log * log) 185662306a36Sopenharmony_ci{ 185762306a36Sopenharmony_ci struct lbuf *lbuf; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci jfs_info("lbmLogShutdown: log:0x%p", log); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci lbuf = log->lbuf_free; 186262306a36Sopenharmony_ci while (lbuf) { 186362306a36Sopenharmony_ci struct lbuf *next = lbuf->l_freelist; 186462306a36Sopenharmony_ci __free_page(lbuf->l_page); 186562306a36Sopenharmony_ci kfree(lbuf); 186662306a36Sopenharmony_ci lbuf = next; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci/* 187262306a36Sopenharmony_ci * lbmAllocate() 187362306a36Sopenharmony_ci * 187462306a36Sopenharmony_ci * allocate an empty log buffer 187562306a36Sopenharmony_ci */ 187662306a36Sopenharmony_cistatic struct lbuf *lbmAllocate(struct jfs_log * log, int pn) 187762306a36Sopenharmony_ci{ 187862306a36Sopenharmony_ci struct lbuf *bp; 187962306a36Sopenharmony_ci unsigned long flags; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* 188262306a36Sopenharmony_ci * recycle from log buffer freelist if any 188362306a36Sopenharmony_ci */ 188462306a36Sopenharmony_ci LCACHE_LOCK(flags); 188562306a36Sopenharmony_ci LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags); 188662306a36Sopenharmony_ci log->lbuf_free = bp->l_freelist; 188762306a36Sopenharmony_ci LCACHE_UNLOCK(flags); 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci bp->l_flag = 0; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci bp->l_wqnext = NULL; 189262306a36Sopenharmony_ci bp->l_freelist = NULL; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci bp->l_pn = pn; 189562306a36Sopenharmony_ci bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize)); 189662306a36Sopenharmony_ci bp->l_ceor = 0; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci return bp; 189962306a36Sopenharmony_ci} 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci/* 190362306a36Sopenharmony_ci * lbmFree() 190462306a36Sopenharmony_ci * 190562306a36Sopenharmony_ci * release a log buffer to freelist 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_cistatic void lbmFree(struct lbuf * bp) 190862306a36Sopenharmony_ci{ 190962306a36Sopenharmony_ci unsigned long flags; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci LCACHE_LOCK(flags); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci lbmfree(bp); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci LCACHE_UNLOCK(flags); 191662306a36Sopenharmony_ci} 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic void lbmfree(struct lbuf * bp) 191962306a36Sopenharmony_ci{ 192062306a36Sopenharmony_ci struct jfs_log *log = bp->l_log; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci assert(bp->l_wqnext == NULL); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci /* 192562306a36Sopenharmony_ci * return the buffer to head of freelist 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci bp->l_freelist = log->lbuf_free; 192862306a36Sopenharmony_ci log->lbuf_free = bp; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci wake_up(&log->free_wait); 193162306a36Sopenharmony_ci return; 193262306a36Sopenharmony_ci} 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci/* 193662306a36Sopenharmony_ci * NAME: lbmRedrive 193762306a36Sopenharmony_ci * 193862306a36Sopenharmony_ci * FUNCTION: add a log buffer to the log redrive list 193962306a36Sopenharmony_ci * 194062306a36Sopenharmony_ci * PARAMETER: 194162306a36Sopenharmony_ci * bp - log buffer 194262306a36Sopenharmony_ci * 194362306a36Sopenharmony_ci * NOTES: 194462306a36Sopenharmony_ci * Takes log_redrive_lock. 194562306a36Sopenharmony_ci */ 194662306a36Sopenharmony_cistatic inline void lbmRedrive(struct lbuf *bp) 194762306a36Sopenharmony_ci{ 194862306a36Sopenharmony_ci unsigned long flags; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci spin_lock_irqsave(&log_redrive_lock, flags); 195162306a36Sopenharmony_ci bp->l_redrive_next = log_redrive_list; 195262306a36Sopenharmony_ci log_redrive_list = bp; 195362306a36Sopenharmony_ci spin_unlock_irqrestore(&log_redrive_lock, flags); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci wake_up_process(jfsIOthread); 195662306a36Sopenharmony_ci} 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci/* 196062306a36Sopenharmony_ci * lbmRead() 196162306a36Sopenharmony_ci */ 196262306a36Sopenharmony_cistatic int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) 196362306a36Sopenharmony_ci{ 196462306a36Sopenharmony_ci struct bio *bio; 196562306a36Sopenharmony_ci struct lbuf *bp; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* 196862306a36Sopenharmony_ci * allocate a log buffer 196962306a36Sopenharmony_ci */ 197062306a36Sopenharmony_ci *bpp = bp = lbmAllocate(log, pn); 197162306a36Sopenharmony_ci jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci bp->l_flag |= lbmREAD; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci bio = bio_alloc(log->bdev, 1, REQ_OP_READ, GFP_NOFS); 197662306a36Sopenharmony_ci bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); 197762306a36Sopenharmony_ci __bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset); 197862306a36Sopenharmony_ci BUG_ON(bio->bi_iter.bi_size != LOGPSIZE); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci bio->bi_end_io = lbmIODone; 198162306a36Sopenharmony_ci bio->bi_private = bp; 198262306a36Sopenharmony_ci /*check if journaling to disk has been disabled*/ 198362306a36Sopenharmony_ci if (log->no_integrity) { 198462306a36Sopenharmony_ci bio->bi_iter.bi_size = 0; 198562306a36Sopenharmony_ci lbmIODone(bio); 198662306a36Sopenharmony_ci } else { 198762306a36Sopenharmony_ci submit_bio(bio); 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD)); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci return 0; 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci/* 199762306a36Sopenharmony_ci * lbmWrite() 199862306a36Sopenharmony_ci * 199962306a36Sopenharmony_ci * buffer at head of pageout queue stays after completion of 200062306a36Sopenharmony_ci * partial-page pageout and redriven by explicit initiation of 200162306a36Sopenharmony_ci * pageout by caller until full-page pageout is completed and 200262306a36Sopenharmony_ci * released. 200362306a36Sopenharmony_ci * 200462306a36Sopenharmony_ci * device driver i/o done redrives pageout of new buffer at 200562306a36Sopenharmony_ci * head of pageout queue when current buffer at head of pageout 200662306a36Sopenharmony_ci * queue is released at the completion of its full-page pageout. 200762306a36Sopenharmony_ci * 200862306a36Sopenharmony_ci * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit(). 200962306a36Sopenharmony_ci * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone() 201062306a36Sopenharmony_ci */ 201162306a36Sopenharmony_cistatic void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, 201262306a36Sopenharmony_ci int cant_block) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci struct lbuf *tail; 201562306a36Sopenharmony_ci unsigned long flags; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci jfs_info("lbmWrite: bp:0x%p flag:0x%x pn:0x%x", bp, flag, bp->l_pn); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci /* map the logical block address to physical block address */ 202062306a36Sopenharmony_ci bp->l_blkno = 202162306a36Sopenharmony_ci log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci LCACHE_LOCK(flags); /* disable+lock */ 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci /* 202662306a36Sopenharmony_ci * initialize buffer for device driver 202762306a36Sopenharmony_ci */ 202862306a36Sopenharmony_ci bp->l_flag = flag; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci /* 203162306a36Sopenharmony_ci * insert bp at tail of write queue associated with log 203262306a36Sopenharmony_ci * 203362306a36Sopenharmony_ci * (request is either for bp already/currently at head of queue 203462306a36Sopenharmony_ci * or new bp to be inserted at tail) 203562306a36Sopenharmony_ci */ 203662306a36Sopenharmony_ci tail = log->wqueue; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci /* is buffer not already on write queue ? */ 203962306a36Sopenharmony_ci if (bp->l_wqnext == NULL) { 204062306a36Sopenharmony_ci /* insert at tail of wqueue */ 204162306a36Sopenharmony_ci if (tail == NULL) { 204262306a36Sopenharmony_ci log->wqueue = bp; 204362306a36Sopenharmony_ci bp->l_wqnext = bp; 204462306a36Sopenharmony_ci } else { 204562306a36Sopenharmony_ci log->wqueue = bp; 204662306a36Sopenharmony_ci bp->l_wqnext = tail->l_wqnext; 204762306a36Sopenharmony_ci tail->l_wqnext = bp; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci tail = bp; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci /* is buffer at head of wqueue and for write ? */ 205462306a36Sopenharmony_ci if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) { 205562306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 205662306a36Sopenharmony_ci return; 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci if (cant_block) 206262306a36Sopenharmony_ci lbmRedrive(bp); 206362306a36Sopenharmony_ci else if (flag & lbmSYNC) 206462306a36Sopenharmony_ci lbmStartIO(bp); 206562306a36Sopenharmony_ci else { 206662306a36Sopenharmony_ci LOGGC_UNLOCK(log); 206762306a36Sopenharmony_ci lbmStartIO(bp); 206862306a36Sopenharmony_ci LOGGC_LOCK(log); 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci} 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci/* 207462306a36Sopenharmony_ci * lbmDirectWrite() 207562306a36Sopenharmony_ci * 207662306a36Sopenharmony_ci * initiate pageout bypassing write queue for sidestream 207762306a36Sopenharmony_ci * (e.g., log superblock) write; 207862306a36Sopenharmony_ci */ 207962306a36Sopenharmony_cistatic void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci jfs_info("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x", 208262306a36Sopenharmony_ci bp, flag, bp->l_pn); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* 208562306a36Sopenharmony_ci * initialize buffer for device driver 208662306a36Sopenharmony_ci */ 208762306a36Sopenharmony_ci bp->l_flag = flag | lbmDIRECT; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* map the logical block address to physical block address */ 209062306a36Sopenharmony_ci bp->l_blkno = 209162306a36Sopenharmony_ci log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci /* 209462306a36Sopenharmony_ci * initiate pageout of the page 209562306a36Sopenharmony_ci */ 209662306a36Sopenharmony_ci lbmStartIO(bp); 209762306a36Sopenharmony_ci} 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci/* 210162306a36Sopenharmony_ci * NAME: lbmStartIO() 210262306a36Sopenharmony_ci * 210362306a36Sopenharmony_ci * FUNCTION: Interface to DD strategy routine 210462306a36Sopenharmony_ci * 210562306a36Sopenharmony_ci * RETURN: none 210662306a36Sopenharmony_ci * 210762306a36Sopenharmony_ci * serialization: LCACHE_LOCK() is NOT held during log i/o; 210862306a36Sopenharmony_ci */ 210962306a36Sopenharmony_cistatic void lbmStartIO(struct lbuf * bp) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci struct bio *bio; 211262306a36Sopenharmony_ci struct jfs_log *log = bp->l_log; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci jfs_info("lbmStartIO"); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci bio = bio_alloc(log->bdev, 1, REQ_OP_WRITE | REQ_SYNC, GFP_NOFS); 211762306a36Sopenharmony_ci bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); 211862306a36Sopenharmony_ci __bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset); 211962306a36Sopenharmony_ci BUG_ON(bio->bi_iter.bi_size != LOGPSIZE); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci bio->bi_end_io = lbmIODone; 212262306a36Sopenharmony_ci bio->bi_private = bp; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci /* check if journaling to disk has been disabled */ 212562306a36Sopenharmony_ci if (log->no_integrity) { 212662306a36Sopenharmony_ci bio->bi_iter.bi_size = 0; 212762306a36Sopenharmony_ci lbmIODone(bio); 212862306a36Sopenharmony_ci } else { 212962306a36Sopenharmony_ci submit_bio(bio); 213062306a36Sopenharmony_ci INCREMENT(lmStat.submitted); 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci} 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci/* 213662306a36Sopenharmony_ci * lbmIOWait() 213762306a36Sopenharmony_ci */ 213862306a36Sopenharmony_cistatic int lbmIOWait(struct lbuf * bp, int flag) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci unsigned long flags; 214162306a36Sopenharmony_ci int rc = 0; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci jfs_info("lbmIOWait1: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci LCACHE_LOCK(flags); /* disable+lock */ 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci rc = (bp->l_flag & lbmERROR) ? -EIO : 0; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci if (flag & lbmFREE) 215262306a36Sopenharmony_ci lbmfree(bp); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci jfs_info("lbmIOWait2: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag); 215762306a36Sopenharmony_ci return rc; 215862306a36Sopenharmony_ci} 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci/* 216162306a36Sopenharmony_ci * lbmIODone() 216262306a36Sopenharmony_ci * 216362306a36Sopenharmony_ci * executed at INTIODONE level 216462306a36Sopenharmony_ci */ 216562306a36Sopenharmony_cistatic void lbmIODone(struct bio *bio) 216662306a36Sopenharmony_ci{ 216762306a36Sopenharmony_ci struct lbuf *bp = bio->bi_private; 216862306a36Sopenharmony_ci struct lbuf *nextbp, *tail; 216962306a36Sopenharmony_ci struct jfs_log *log; 217062306a36Sopenharmony_ci unsigned long flags; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* 217362306a36Sopenharmony_ci * get back jfs buffer bound to the i/o buffer 217462306a36Sopenharmony_ci */ 217562306a36Sopenharmony_ci jfs_info("lbmIODone: bp:0x%p flag:0x%x", bp, bp->l_flag); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci LCACHE_LOCK(flags); /* disable+lock */ 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci bp->l_flag |= lbmDONE; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if (bio->bi_status) { 218262306a36Sopenharmony_ci bp->l_flag |= lbmERROR; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci jfs_err("lbmIODone: I/O error in JFS log"); 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci bio_put(bio); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci /* 219062306a36Sopenharmony_ci * pagein completion 219162306a36Sopenharmony_ci */ 219262306a36Sopenharmony_ci if (bp->l_flag & lbmREAD) { 219362306a36Sopenharmony_ci bp->l_flag &= ~lbmREAD; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci /* wakeup I/O initiator */ 219862306a36Sopenharmony_ci LCACHE_WAKEUP(&bp->l_ioevent); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci return; 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci /* 220462306a36Sopenharmony_ci * pageout completion 220562306a36Sopenharmony_ci * 220662306a36Sopenharmony_ci * the bp at the head of write queue has completed pageout. 220762306a36Sopenharmony_ci * 220862306a36Sopenharmony_ci * if single-commit/full-page pageout, remove the current buffer 220962306a36Sopenharmony_ci * from head of pageout queue, and redrive pageout with 221062306a36Sopenharmony_ci * the new buffer at head of pageout queue; 221162306a36Sopenharmony_ci * otherwise, the partial-page pageout buffer stays at 221262306a36Sopenharmony_ci * the head of pageout queue to be redriven for pageout 221362306a36Sopenharmony_ci * by lmGroupCommit() until full-page pageout is completed. 221462306a36Sopenharmony_ci */ 221562306a36Sopenharmony_ci bp->l_flag &= ~lbmWRITE; 221662306a36Sopenharmony_ci INCREMENT(lmStat.pagedone); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci /* update committed lsn */ 221962306a36Sopenharmony_ci log = bp->l_log; 222062306a36Sopenharmony_ci log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (bp->l_flag & lbmDIRECT) { 222362306a36Sopenharmony_ci LCACHE_WAKEUP(&bp->l_ioevent); 222462306a36Sopenharmony_ci LCACHE_UNLOCK(flags); 222562306a36Sopenharmony_ci return; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci tail = log->wqueue; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci /* single element queue */ 223162306a36Sopenharmony_ci if (bp == tail) { 223262306a36Sopenharmony_ci /* remove head buffer of full-page pageout 223362306a36Sopenharmony_ci * from log device write queue 223462306a36Sopenharmony_ci */ 223562306a36Sopenharmony_ci if (bp->l_flag & lbmRELEASE) { 223662306a36Sopenharmony_ci log->wqueue = NULL; 223762306a36Sopenharmony_ci bp->l_wqnext = NULL; 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci /* multi element queue */ 224162306a36Sopenharmony_ci else { 224262306a36Sopenharmony_ci /* remove head buffer of full-page pageout 224362306a36Sopenharmony_ci * from log device write queue 224462306a36Sopenharmony_ci */ 224562306a36Sopenharmony_ci if (bp->l_flag & lbmRELEASE) { 224662306a36Sopenharmony_ci nextbp = tail->l_wqnext = bp->l_wqnext; 224762306a36Sopenharmony_ci bp->l_wqnext = NULL; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci /* 225062306a36Sopenharmony_ci * redrive pageout of next page at head of write queue: 225162306a36Sopenharmony_ci * redrive next page without any bound tblk 225262306a36Sopenharmony_ci * (i.e., page w/o any COMMIT records), or 225362306a36Sopenharmony_ci * first page of new group commit which has been 225462306a36Sopenharmony_ci * queued after current page (subsequent pageout 225562306a36Sopenharmony_ci * is performed synchronously, except page without 225662306a36Sopenharmony_ci * any COMMITs) by lmGroupCommit() as indicated 225762306a36Sopenharmony_ci * by lbmWRITE flag; 225862306a36Sopenharmony_ci */ 225962306a36Sopenharmony_ci if (nextbp->l_flag & lbmWRITE) { 226062306a36Sopenharmony_ci /* 226162306a36Sopenharmony_ci * We can't do the I/O at interrupt time. 226262306a36Sopenharmony_ci * The jfsIO thread can do it 226362306a36Sopenharmony_ci */ 226462306a36Sopenharmony_ci lbmRedrive(nextbp); 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci } 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci /* 227062306a36Sopenharmony_ci * synchronous pageout: 227162306a36Sopenharmony_ci * 227262306a36Sopenharmony_ci * buffer has not necessarily been removed from write queue 227362306a36Sopenharmony_ci * (e.g., synchronous write of partial-page with COMMIT): 227462306a36Sopenharmony_ci * leave buffer for i/o initiator to dispose 227562306a36Sopenharmony_ci */ 227662306a36Sopenharmony_ci if (bp->l_flag & lbmSYNC) { 227762306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci /* wakeup I/O initiator */ 228062306a36Sopenharmony_ci LCACHE_WAKEUP(&bp->l_ioevent); 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci /* 228462306a36Sopenharmony_ci * Group Commit pageout: 228562306a36Sopenharmony_ci */ 228662306a36Sopenharmony_ci else if (bp->l_flag & lbmGC) { 228762306a36Sopenharmony_ci LCACHE_UNLOCK(flags); 228862306a36Sopenharmony_ci lmPostGC(bp); 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* 229262306a36Sopenharmony_ci * asynchronous pageout: 229362306a36Sopenharmony_ci * 229462306a36Sopenharmony_ci * buffer must have been removed from write queue: 229562306a36Sopenharmony_ci * insert buffer at head of freelist where it can be recycled 229662306a36Sopenharmony_ci */ 229762306a36Sopenharmony_ci else { 229862306a36Sopenharmony_ci assert(bp->l_flag & lbmRELEASE); 229962306a36Sopenharmony_ci assert(bp->l_flag & lbmFREE); 230062306a36Sopenharmony_ci lbmfree(bp); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci LCACHE_UNLOCK(flags); /* unlock+enable */ 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci} 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ciint jfsIOWait(void *arg) 230762306a36Sopenharmony_ci{ 230862306a36Sopenharmony_ci struct lbuf *bp; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci do { 231162306a36Sopenharmony_ci spin_lock_irq(&log_redrive_lock); 231262306a36Sopenharmony_ci while ((bp = log_redrive_list)) { 231362306a36Sopenharmony_ci log_redrive_list = bp->l_redrive_next; 231462306a36Sopenharmony_ci bp->l_redrive_next = NULL; 231562306a36Sopenharmony_ci spin_unlock_irq(&log_redrive_lock); 231662306a36Sopenharmony_ci lbmStartIO(bp); 231762306a36Sopenharmony_ci spin_lock_irq(&log_redrive_lock); 231862306a36Sopenharmony_ci } 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci if (freezing(current)) { 232162306a36Sopenharmony_ci spin_unlock_irq(&log_redrive_lock); 232262306a36Sopenharmony_ci try_to_freeze(); 232362306a36Sopenharmony_ci } else { 232462306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 232562306a36Sopenharmony_ci spin_unlock_irq(&log_redrive_lock); 232662306a36Sopenharmony_ci schedule(); 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci } while (!kthread_should_stop()); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci jfs_info("jfsIOWait being killed!"); 233162306a36Sopenharmony_ci return 0; 233262306a36Sopenharmony_ci} 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci/* 233562306a36Sopenharmony_ci * NAME: lmLogFormat()/jfs_logform() 233662306a36Sopenharmony_ci * 233762306a36Sopenharmony_ci * FUNCTION: format file system log 233862306a36Sopenharmony_ci * 233962306a36Sopenharmony_ci * PARAMETERS: 234062306a36Sopenharmony_ci * log - volume log 234162306a36Sopenharmony_ci * logAddress - start address of log space in FS block 234262306a36Sopenharmony_ci * logSize - length of log space in FS block; 234362306a36Sopenharmony_ci * 234462306a36Sopenharmony_ci * RETURN: 0 - success 234562306a36Sopenharmony_ci * -EIO - i/o error 234662306a36Sopenharmony_ci * 234762306a36Sopenharmony_ci * XXX: We're synchronously writing one page at a time. This needs to 234862306a36Sopenharmony_ci * be improved by writing multiple pages at once. 234962306a36Sopenharmony_ci */ 235062306a36Sopenharmony_ciint lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize) 235162306a36Sopenharmony_ci{ 235262306a36Sopenharmony_ci int rc = -EIO; 235362306a36Sopenharmony_ci struct jfs_sb_info *sbi; 235462306a36Sopenharmony_ci struct logsuper *logsuper; 235562306a36Sopenharmony_ci struct logpage *lp; 235662306a36Sopenharmony_ci int lspn; /* log sequence page number */ 235762306a36Sopenharmony_ci struct lrd *lrd_ptr; 235862306a36Sopenharmony_ci int npages = 0; 235962306a36Sopenharmony_ci struct lbuf *bp; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci jfs_info("lmLogFormat: logAddress:%Ld logSize:%d", 236262306a36Sopenharmony_ci (long long)logAddress, logSize); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci sbi = list_entry(log->sb_list.next, struct jfs_sb_info, log_list); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci /* allocate a log buffer */ 236762306a36Sopenharmony_ci bp = lbmAllocate(log, 1); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci npages = logSize >> sbi->l2nbperpage; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci /* 237262306a36Sopenharmony_ci * log space: 237362306a36Sopenharmony_ci * 237462306a36Sopenharmony_ci * page 0 - reserved; 237562306a36Sopenharmony_ci * page 1 - log superblock; 237662306a36Sopenharmony_ci * page 2 - log data page: A SYNC log record is written 237762306a36Sopenharmony_ci * into this page at logform time; 237862306a36Sopenharmony_ci * pages 3-N - log data page: set to empty log data pages; 237962306a36Sopenharmony_ci */ 238062306a36Sopenharmony_ci /* 238162306a36Sopenharmony_ci * init log superblock: log page 1 238262306a36Sopenharmony_ci */ 238362306a36Sopenharmony_ci logsuper = (struct logsuper *) bp->l_ldata; 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci logsuper->magic = cpu_to_le32(LOGMAGIC); 238662306a36Sopenharmony_ci logsuper->version = cpu_to_le32(LOGVERSION); 238762306a36Sopenharmony_ci logsuper->state = cpu_to_le32(LOGREDONE); 238862306a36Sopenharmony_ci logsuper->flag = cpu_to_le32(sbi->mntflag); /* ? */ 238962306a36Sopenharmony_ci logsuper->size = cpu_to_le32(npages); 239062306a36Sopenharmony_ci logsuper->bsize = cpu_to_le32(sbi->bsize); 239162306a36Sopenharmony_ci logsuper->l2bsize = cpu_to_le32(sbi->l2bsize); 239262306a36Sopenharmony_ci logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE); 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 239562306a36Sopenharmony_ci bp->l_blkno = logAddress + sbi->nbperpage; 239662306a36Sopenharmony_ci lbmStartIO(bp); 239762306a36Sopenharmony_ci if ((rc = lbmIOWait(bp, 0))) 239862306a36Sopenharmony_ci goto exit; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* 240162306a36Sopenharmony_ci * init pages 2 to npages-1 as log data pages: 240262306a36Sopenharmony_ci * 240362306a36Sopenharmony_ci * log page sequence number (lpsn) initialization: 240462306a36Sopenharmony_ci * 240562306a36Sopenharmony_ci * pn: 0 1 2 3 n-1 240662306a36Sopenharmony_ci * +-----+-----+=====+=====+===.....===+=====+ 240762306a36Sopenharmony_ci * lspn: N-1 0 1 N-2 240862306a36Sopenharmony_ci * <--- N page circular file ----> 240962306a36Sopenharmony_ci * 241062306a36Sopenharmony_ci * the N (= npages-2) data pages of the log is maintained as 241162306a36Sopenharmony_ci * a circular file for the log records; 241262306a36Sopenharmony_ci * lpsn grows by 1 monotonically as each log page is written 241362306a36Sopenharmony_ci * to the circular file of the log; 241462306a36Sopenharmony_ci * and setLogpage() will not reset the page number even if 241562306a36Sopenharmony_ci * the eor is equal to LOGPHDRSIZE. In order for binary search 241662306a36Sopenharmony_ci * still work in find log end process, we have to simulate the 241762306a36Sopenharmony_ci * log wrap situation at the log format time. 241862306a36Sopenharmony_ci * The 1st log page written will have the highest lpsn. Then 241962306a36Sopenharmony_ci * the succeeding log pages will have ascending order of 242062306a36Sopenharmony_ci * the lspn starting from 0, ... (N-2) 242162306a36Sopenharmony_ci */ 242262306a36Sopenharmony_ci lp = (struct logpage *) bp->l_ldata; 242362306a36Sopenharmony_ci /* 242462306a36Sopenharmony_ci * initialize 1st log page to be written: lpsn = N - 1, 242562306a36Sopenharmony_ci * write a SYNCPT log record is written to this page 242662306a36Sopenharmony_ci */ 242762306a36Sopenharmony_ci lp->h.page = lp->t.page = cpu_to_le32(npages - 3); 242862306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci lrd_ptr = (struct lrd *) &lp->data; 243162306a36Sopenharmony_ci lrd_ptr->logtid = 0; 243262306a36Sopenharmony_ci lrd_ptr->backchain = 0; 243362306a36Sopenharmony_ci lrd_ptr->type = cpu_to_le16(LOG_SYNCPT); 243462306a36Sopenharmony_ci lrd_ptr->length = 0; 243562306a36Sopenharmony_ci lrd_ptr->log.syncpt.sync = 0; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci bp->l_blkno += sbi->nbperpage; 243862306a36Sopenharmony_ci bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 243962306a36Sopenharmony_ci lbmStartIO(bp); 244062306a36Sopenharmony_ci if ((rc = lbmIOWait(bp, 0))) 244162306a36Sopenharmony_ci goto exit; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* 244462306a36Sopenharmony_ci * initialize succeeding log pages: lpsn = 0, 1, ..., (N-2) 244562306a36Sopenharmony_ci */ 244662306a36Sopenharmony_ci for (lspn = 0; lspn < npages - 3; lspn++) { 244762306a36Sopenharmony_ci lp->h.page = lp->t.page = cpu_to_le32(lspn); 244862306a36Sopenharmony_ci lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci bp->l_blkno += sbi->nbperpage; 245162306a36Sopenharmony_ci bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; 245262306a36Sopenharmony_ci lbmStartIO(bp); 245362306a36Sopenharmony_ci if ((rc = lbmIOWait(bp, 0))) 245462306a36Sopenharmony_ci goto exit; 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci rc = 0; 245862306a36Sopenharmony_ciexit: 245962306a36Sopenharmony_ci /* 246062306a36Sopenharmony_ci * finalize log 246162306a36Sopenharmony_ci */ 246262306a36Sopenharmony_ci /* release the buffer */ 246362306a36Sopenharmony_ci lbmFree(bp); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci return rc; 246662306a36Sopenharmony_ci} 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci#ifdef CONFIG_JFS_STATISTICS 246962306a36Sopenharmony_ciint jfs_lmstats_proc_show(struct seq_file *m, void *v) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci seq_printf(m, 247262306a36Sopenharmony_ci "JFS Logmgr stats\n" 247362306a36Sopenharmony_ci "================\n" 247462306a36Sopenharmony_ci "commits = %d\n" 247562306a36Sopenharmony_ci "writes submitted = %d\n" 247662306a36Sopenharmony_ci "writes completed = %d\n" 247762306a36Sopenharmony_ci "full pages submitted = %d\n" 247862306a36Sopenharmony_ci "partial pages submitted = %d\n", 247962306a36Sopenharmony_ci lmStat.commit, 248062306a36Sopenharmony_ci lmStat.submitted, 248162306a36Sopenharmony_ci lmStat.pagedone, 248262306a36Sopenharmony_ci lmStat.full_page, 248362306a36Sopenharmony_ci lmStat.partial_page); 248462306a36Sopenharmony_ci return 0; 248562306a36Sopenharmony_ci} 248662306a36Sopenharmony_ci#endif /* CONFIG_JFS_STATISTICS */ 2487