#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
} lmStat;
#endif
+static void write_special_inodes(struct jfs_log *log,
+ int (*writer)(struct address_space *))
+{
+ struct jfs_sb_info *sbi;
+
+ list_for_each_entry(sbi, &log->sb_list, log_list) {
+ writer(sbi->ipbmap->i_mapping);
+ writer(sbi->ipimap->i_mapping);
+ writer(sbi->direct_inode->i_mapping);
+ }
+}
/*
* NAME: lmLog()
goto writeRecord;
/*
- * initialize/update page/transaction recovery lsn
+ * initialize/update page/transaction recovery lsn
*/
lsn = log->lsn;
}
/*
- * initialize/update lsn of tblock of the page
+ * initialize/update lsn of tblock of the page
*
* transaction inherits oldest lsn of pages associated
* with allocation/deallocation of resources (their
LOGSYNC_UNLOCK(log, flags);
/*
- * write the log record
+ * write the log record
*/
writeRecord:
lsn = lmWriteRecord(log, tblk, lrd, tlck);
goto moveLrd;
/*
- * move log record data
+ * move log record data
*/
/* retrieve source meta-data page to log */
if (tlck->flag & tlckPAGELOCK) {
}
/*
- * move log record descriptor
+ * move log record descriptor
*/
moveLrd:
lrd->length = cpu_to_le16(len);
LOGGC_LOCK(log);
/*
- * write or queue the full page at the tail of write queue
+ * write or queue the full page at the tail of write queue
*/
/* get the tail tblk on commit queue */
if (list_empty(&log->cqueue))
LOGGC_UNLOCK(log);
/*
- * allocate/initialize next page
+ * allocate/initialize next page
*/
/* if log wraps, the first data page of log is 2
* (0 never used, 1 is superblock).
struct lrd lrd;
int lsn;
struct logsyncblk *lp;
- struct jfs_sb_info *sbi;
unsigned long flags;
/* push dirty metapages out to disk */
if (hard_sync)
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_fdatawrite(sbi->ipbmap->i_mapping);
- filemap_fdatawrite(sbi->ipimap->i_mapping);
- filemap_fdatawrite(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_fdatawrite);
else
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_flush(sbi->ipbmap->i_mapping);
- filemap_flush(sbi->ipimap->i_mapping);
- filemap_flush(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_flush);
/*
- * forward syncpt
+ * forward syncpt
*/
/* if last sync is same as last syncpt,
* invoke sync point forward processing to update sync.
lsn = log->lsn;
/*
- * setup next syncpt trigger (SWAG)
+ * setup next syncpt trigger (SWAG)
*/
logsize = log->logsize;
if (more < 2 * LOGPSIZE) {
jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
/*
- * log wrapping
+ * log wrapping
*
* option 1 - panic ? No.!
* option 2 - shutdown file systems
- * associated with log ?
+ * associated with log ?
* option 3 - extend log ?
*/
/*
/*
* NAME: lmLogOpen()
*
- * FUNCTION: open the log on first open;
+ * FUNCTION: open the log on first open;
* insert filesystem in the active list of the log.
*
* PARAMETER: ipmnt - file system mount inode
init_waitqueue_head(&log->syncwait);
/*
- * external log as separate logical volume
+ * external log as separate logical volume
*
* file systems to log may have n-to-1 relationship;
*/
return 0;
/*
- * unwind on error
+ * unwind on error
*/
shutdown: /* unwind lbmLogInit() */
list_del(&log->journal_list);
return 0;
/*
- * unwind on error
+ * unwind on error
*/
errout30: /* release log page */
log->wqueue = NULL;
if (test_bit(log_INLINELOG, &log->flag)) {
/*
- * in-line log in host file system
+ * in-line log in host file system
*/
rc = lmLogShutdown(log);
kfree(log);
goto out;
/*
- * external log as separate logical volume
+ * external log as separate logical volume
*/
list_del(&log->journal_list);
bdev = log->bdev;
{
int i;
struct tblock *target = NULL;
- struct jfs_sb_info *sbi;
/* jfs_write_inode may call us during read-only mount */
if (!log)
if (wait < 2)
return;
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_fdatawrite(sbi->ipbmap->i_mapping);
- filemap_fdatawrite(sbi->ipimap->i_mapping);
- filemap_fdatawrite(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_fdatawrite);
/*
* If there was recent activity, we may need to wait
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
+ write_special_inodes(log, filemap_fdatawrite);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
if (!list_empty(&log->synclist)) {
struct logsyncblk *lp;
+ printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
list_for_each_entry(lp, &log->synclist, synclist) {
if (lp->xflag & COMMIT_PAGE) {
struct metapage *mp = (struct metapage *)lp;
- dump_mem("orphan metapage", lp,
- sizeof(struct metapage));
- dump_mem("page", mp->page, sizeof(struct page));
- }
- else
- dump_mem("orphan tblock", lp,
- sizeof(struct tblock));
+ print_hex_dump(KERN_ERR, "metapage: ",
+ DUMP_PREFIX_ADDRESS, 16, 4,
+ mp, sizeof(struct metapage), 0);
+ print_hex_dump(KERN_ERR, "page: ",
+ DUMP_PREFIX_ADDRESS, 16,
+ sizeof(long), mp->page,
+ sizeof(struct page), 0);
+ } else
+ print_hex_dump(KERN_ERR, "tblock:",
+ DUMP_PREFIX_ADDRESS, 16, 4,
+ lp, sizeof(struct tblock), 0);
}
}
+#else
+ WARN_ON(!list_empty(&log->synclist));
#endif
- //assert(list_empty(&log->synclist));
clear_bit(log_FLUSH, &log->flag);
}
*
* PARAMETE: log - pointer to logs inode.
* fsdev - kdev_t of filesystem.
- * serial - pointer to returned log serial number
+ * serial - pointer to returned log serial number
* activate - insert/remove device from active list.
*
* RETURN: 0 - success
* FUNCTION: add a log buffer to the log redrive list
*
* PARAMETER:
- * bp - log buffer
+ * bp - log buffer
*
* NOTES:
* Takes log_redrive_lock.
bp->l_flag = flag;
/*
- * insert bp at tail of write queue associated with log
+ * insert bp at tail of write queue associated with log
*
* (request is either for bp already/currently at head of queue
* or new bp to be inserted at tail)
log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
/*
- * initiate pageout of the page
+ * initiate pageout of the page
*/
lbmStartIO(bp);
}
*
* FUNCTION: Interface to DD strategy routine
*
- * RETURN: none
+ * RETURN: none
*
* serialization: LCACHE_LOCK() is NOT held during log i/o;
*/
/* check if journaling to disk has been disabled */
if (log->no_integrity) {
bio->bi_size = 0;
- lbmIODone(bio, 0, 0);
+ lbmIODone(bio, 0);
} else {
submit_bio(WRITE_SYNC, bio);
INCREMENT(lmStat.submitted);
*
* executed at INTIODONE level
*/
-static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
+static void lbmIODone(struct bio *bio, int error)
{
struct lbuf *bp = bio->bi_private;
struct lbuf *nextbp, *tail;
struct jfs_log *log;
unsigned long flags;
- if (bio->bi_size)
- return 1;
-
/*
* get back jfs buffer bound to the i/o buffer
*/
bio_put(bio);
/*
- * pagein completion
+ * pagein completion
*/
if (bp->l_flag & lbmREAD) {
bp->l_flag &= ~lbmREAD;
/* wakeup I/O initiator */
LCACHE_WAKEUP(&bp->l_ioevent);
- return 0;
+ return;
}
/*
- * pageout completion
+ * pageout completion
*
* the bp at the head of write queue has completed pageout.
*
if (bp->l_flag & lbmDIRECT) {
LCACHE_WAKEUP(&bp->l_ioevent);
LCACHE_UNLOCK(flags);
- return 0;
+ return;
}
tail = log->wqueue;
}
/*
- * synchronous pageout:
+ * synchronous pageout:
*
* buffer has not necessarily been removed from write queue
* (e.g., synchronous write of partial-page with COMMIT):
}
/*
- * Group Commit pageout:
+ * Group Commit pageout:
*/
else if (bp->l_flag & lbmGC) {
LCACHE_UNLOCK(flags);
}
/*
- * asynchronous pageout:
+ * asynchronous pageout:
*
* buffer must have been removed from write queue:
* insert buffer at head of freelist where it can be recycled
LCACHE_UNLOCK(flags); /* unlock+enable */
}
-
- return 0;
}
int jfsIOWait(void *arg)
do {
spin_lock_irq(&log_redrive_lock);
- while ((bp = log_redrive_list) != 0) {
+ while ((bp = log_redrive_list)) {
log_redrive_list = bp->l_redrive_next;
bp->l_redrive_next = NULL;
spin_unlock_irq(&log_redrive_lock);
* FUNCTION: format file system log
*
* PARAMETERS:
- * log - volume log
+ * log - volume log
* logAddress - start address of log space in FS block
* logSize - length of log space in FS block;
*
npages = logSize >> sbi->l2nbperpage;
/*
- * log space:
+ * log space:
*
* page 0 - reserved;
* page 1 - log superblock;
* page 2 - log data page: A SYNC log record is written
- * into this page at logform time;
+ * into this page at logform time;
* pages 3-N - log data page: set to empty log data pages;
*/
/*
- * init log superblock: log page 1
+ * init log superblock: log page 1
*/
logsuper = (struct logsuper *) bp->l_ldata;
goto exit;
/*
- * init pages 2 to npages-1 as log data pages:
+ * init pages 2 to npages-1 as log data pages:
*
* log page sequence number (lpsn) initialization:
*
goto exit;
/*
- * initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
+ * initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
*/
for (lspn = 0; lspn < npages - 3; lspn++) {
lp->h.page = lp->t.page = cpu_to_le32(lspn);
rc = 0;
exit:
/*
- * finalize log
+ * finalize log
*/
/* release the buffer */
lbmFree(bp);
}
#ifdef CONFIG_JFS_STATISTICS
-int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_lmstats_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
-
- len += sprintf(buffer,
+ seq_printf(m,
"JFS Logmgr stats\n"
"================\n"
"commits = %d\n"
lmStat.pagedone,
lmStat.full_page,
lmStat.partial_page);
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_lmstats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_lmstats_proc_show, NULL);
}
+
+const struct file_operations jfs_lmstats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_lmstats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_JFS_STATISTICS */