#include <linux/buffer_head.h> /* for sync_blockdev() */
#include <linux/bio.h>
#include <linux/suspend.h>
+#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
+#include "jfs_superblock.h"
#include "jfs_txnmgr.h"
#include "jfs_debug.h"
* lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread)
*/
static struct lbuf *log_redrive_list;
-static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(log_redrive_lock);
DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait);
/*
* log buffer cache synchronization
*/
-static spinlock_t jfsLCacheLock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(jfsLCacheLock);
#define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags)
#define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags)
static struct jfs_log *dummy_log = NULL;
static DECLARE_MUTEX(jfs_log_sem);
-/*
- * external references
- */
-extern void txLazyUnlock(struct tblock * tblk);
-extern int jfs_stop_threads;
-extern struct completion jfsIOwait;
-extern int jfs_tlocks_low;
-
/*
* forward references
*/
static bio_end_io_t lbmIODone;
static void lbmStartIO(struct lbuf * bp);
static void lmGCwrite(struct jfs_log * log, int cant_block);
-static int lmLogSync(struct jfs_log * log, int nosyncwait);
+static int lmLogSync(struct jfs_log * log, int hard_sync);
int lsn;
int diffp, difft;
struct metapage *mp = NULL;
+ unsigned long flags;
jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
log, tblk, lrd, tlck);
*/
lsn = log->lsn;
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
/*
* initialize page lsn if first log write of the page
}
}
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
/*
* write the log record
return lsn;
}
-
/*
* NAME: lmWriteRecord()
*
* if new sync address is available
* (normally the case if sync() is executed by back-ground
* process).
- * if not, explicitly run jfs_blogsync() to initiate
- * getting of new sync address.
* calculate new value of i_nextsync which determines when
* this code is called again.
*
- * this is called only from lmLog().
- *
- * PARAMETER: ip - pointer to logs inode.
+ * PARAMETERS: log - log structure
+ * hard_sync - 1 to force all metadata to be written
*
* RETURN: 0
*
* serialization: LOG_LOCK() held on entry/exit
*/
-static int lmLogSync(struct jfs_log * log, int nosyncwait)
+static int lmLogSync(struct jfs_log * log, int hard_sync)
{
int logsize;
int written; /* written since last syncpt */
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);
+ }
+ 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);
+ }
/*
* forward syncpt
*/
if (log->sync == log->syncpt) {
- LOGSYNC_LOCK(log);
- /* ToDo: push dirty metapages out to disk */
-// bmLogSync(log);
-
+ LOGSYNC_LOCK(log, flags);
if (list_empty(&log->synclist))
log->sync = log->lsn;
else {
struct logsyncblk, synclist);
log->sync = lp->lsn;
}
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
}
* reset syncpt = sync
*/
if (log->sync != log->syncpt) {
- struct jfs_sb_info *sbi;
-
- /*
- * We need to make sure all of the "written" metapages
- * actually make it to disk
- */
- 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->sb->s_bdev->bd_inode->i_mapping);
- }
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_fdatawait(sbi->ipbmap->i_mapping);
- filemap_fdatawait(sbi->ipimap->i_mapping);
- filemap_fdatawait(sbi->sb->s_bdev->bd_inode->i_mapping);
- }
-
lrd.logtid = 0;
lrd.backchain = 0;
lrd.type = cpu_to_le16(LOG_SYNCPT);
/* next syncpt trigger = written + more */
log->nextsync = written + more;
- /* return if lmLogSync() from outside of transaction, e.g., sync() */
- if (nosyncwait)
- return lsn;
-
/* if number of bytes written from last sync point is more
* than 1/4 of the log size, stop new transactions from
* starting until all current transactions are completed
* by setting syncbarrier flag.
*/
- if (written > LOGSYNC_BARRIER(logsize) && logsize > 32 * LOGPSIZE) {
+ if (!test_bit(log_SYNCBARRIER, &log->flag) &&
+ (written > LOGSYNC_BARRIER(logsize)) && log->active) {
set_bit(log_SYNCBARRIER, &log->flag);
jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn,
log->syncpt);
return lsn;
}
+/*
+ * NAME: jfs_syncpt
+ *
+ * FUNCTION: write log SYNCPT record for specified log
+ *
+ * PARAMETERS: log - log structure
+ * hard_sync - set to 1 to force metadata to be written
+ */
+void jfs_syncpt(struct jfs_log *log, int hard_sync)
+{ LOG_LOCK(log);
+ lmLogSync(log, hard_sync);
+ LOG_UNLOCK(log);
+}
/*
* NAME: lmLogOpen()
}
memset(log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&log->sb_list);
+ init_waitqueue_head(&log->syncwait);
/*
* external log as separate logical volume
return -ENOMEM;
memset(log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&log->sb_list);
+ init_waitqueue_head(&log->syncwait);
set_bit(log_INLINELOG, &log->flag);
log->bdev = sb->s_bdev;
}
memset(dummy_log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&dummy_log->sb_list);
+ init_waitqueue_head(&dummy_log->syncwait);
dummy_log->no_integrity = 1;
/* Make up some stuff */
dummy_log->base = 0;
INIT_LIST_HEAD(&log->synclist);
- init_waitqueue_head(&log->syncwait);
-
INIT_LIST_HEAD(&log->cqueue);
log->flush_tblk = NULL;
{
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);
+ }
+
/*
* If there was recent activity, we may need to wait
* for the lazycommit thread to catch up
*/
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
- for (i = 0; i < 800; i++) { /* Too much? */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 4);
+ for (i = 0; i < 200; i++) { /* Too much? */
+ msleep(250);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
}
}
assert(list_empty(&log->cqueue));
- assert(list_empty(&log->synclist));
+
+#ifdef CONFIG_JFS_DEBUG
+ if (!list_empty(&log->synclist)) {
+ struct logsyncblk *lp;
+
+ 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));
+ }
+ }
+#endif
+ //assert(list_empty(&log->synclist));
clear_bit(log_FLUSH, &log->flag);
}
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
lbmIOWait(log->bp, lbmFREE);
+ log->bp = NULL;
/*
* synchronous update log superblock
log->lbuf_free = NULL;
- for (i = 0; i < LOGPAGES; i++) {
- lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
- if (lbuf == 0)
- goto error;
- lbuf->l_ldata = (char *) get_zeroed_page(GFP_KERNEL);
- if (lbuf->l_ldata == 0) {
- kfree(lbuf);
+ for (i = 0; i < LOGPAGES;) {
+ char *buffer;
+ uint offset;
+ struct page *page;
+
+ buffer = (char *) get_zeroed_page(GFP_KERNEL);
+ if (buffer == NULL)
goto error;
+ page = virt_to_page(buffer);
+ for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
+ lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
+ if (lbuf == NULL) {
+ if (offset == 0)
+ free_page((unsigned long) buffer);
+ goto error;
+ }
+ if (offset) /* we already have one reference */
+ get_page(page);
+ lbuf->l_offset = offset;
+ lbuf->l_ldata = buffer + offset;
+ lbuf->l_page = page;
+ lbuf->l_log = log;
+ init_waitqueue_head(&lbuf->l_ioevent);
+
+ lbuf->l_freelist = log->lbuf_free;
+ log->lbuf_free = lbuf;
+ i++;
}
- lbuf->l_log = log;
- init_waitqueue_head(&lbuf->l_ioevent);
-
- lbuf->l_freelist = log->lbuf_free;
- log->lbuf_free = lbuf;
}
return (0);
lbuf = log->lbuf_free;
while (lbuf) {
struct lbuf *next = lbuf->l_freelist;
- free_page((unsigned long) lbuf->l_ldata);
+ __free_page(lbuf->l_page);
kfree(lbuf);
lbuf = next;
}
-
- log->bp = NULL;
}
bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
- bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+ bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
- bio->bi_io_vec[0].bv_offset = 0;
+ bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
bio->bi_idx = 0;
bio = bio_alloc(GFP_NOFS, 1);
bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
- bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+ bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
- bio->bi_io_vec[0].bv_offset = 0;
+ bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
bio->bi_idx = 0;
bio->bi_private = bp;
/* check if journaling to disk has been disabled */
- if (!log->no_integrity) {
+ if (log->no_integrity) {
+ bio->bi_size = 0;
+ lbmIODone(bio, 0, 0);
+ } else {
submit_bio(WRITE_SYNC, bio);
INCREMENT(lmStat.submitted);
}
- else {
- bio->bi_size = 0;
- lbmIODone(bio, 0, 0); /* 2nd argument appears to not be used => 0
- * 3rd argument appears to not be used => 0
- */
- }
}
lbmStartIO(bp);
spin_lock_irq(&log_redrive_lock);
}
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
spin_unlock_irq(&log_redrive_lock);
- refrigerator(PF_FREEZE);
+ refrigerator();
} else {
add_wait_queue(&jfs_IO_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);