diff options
| author | Dave Kleikamp <shaggy@austin.ibm.com> | 2002-05-08 18:12:07 -0700 |
|---|---|---|
| committer | Dave Kleikamp <shaggy@austin.ibm.com> | 2002-05-08 18:12:07 -0700 |
| commit | 3686a39856c6f5ca34547b7e79f02eb1287f4bd5 (patch) | |
| tree | 0ce77ad43e6a773212d56b31857517d1be4f87c6 | |
| parent | 4ce6b618012e4649b858bf2884f7fa060aee692b (diff) | |
[PATCH] Fix JFS file system corruption
JFS: Flush dirty metadata to disk when remounting from read-write
to read-only. Also fix umount ordering to make sure metadata is
written before journal closed.
With Andrew Morton's recent changes, JFS is no longer writing much
of its dirty metadata when remounting from read-write to read-only.
This causes severe file system corruption. A JFS root file system
will be corrupted on shutdown.
This patch fixes the problem by explicitly writing the dirty metadata
before the journal is closed. It also fixes the ordering so that
the dirty metadata is completely written before the journal is closed
for the normal unmount case as well.
| -rw-r--r-- | fs/jfs/jfs_logmgr.c | 47 | ||||
| -rw-r--r-- | fs/jfs/jfs_logmgr.h | 1 | ||||
| -rw-r--r-- | fs/jfs/jfs_umount.c | 45 |
3 files changed, 62 insertions, 31 deletions
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 7270bd48729e..a2e91a853516 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1386,6 +1386,35 @@ int lmLogClose(struct super_block *sb, log_t * log) /* + * NAME: lmLogWait() + * + * FUNCTION: wait for all outstanding log records to be written to disk + */ +void lmLogWait(log_t *log) +{ + int i; + + jFYI(1, ("lmLogWait: log:0x%p\n", log)); + + if (log->cqueue.head || !list_empty(&log->synclist)) { + /* + * If there was very recent activity, we may need to wait + * for the lazycommit thread to catch up + */ + + for (i = 0; i < 800; i++) { /* Too much? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 4); + if ((log->cqueue.head == NULL) && + list_empty(&log->synclist)) + break; + } + } + assert(log->cqueue.head == NULL); + assert(list_empty(&log->synclist)); +} + +/* * NAME: lmLogShutdown() * * FUNCTION: log shutdown at last LogClose(). @@ -1411,23 +1440,7 @@ static int lmLogShutdown(log_t * log) jFYI(1, ("lmLogShutdown: log:0x%p\n", log)); - if (log->cqueue.head || !list_empty(&log->synclist)) { - /* - * If there was very recent activity, we may need to wait - * for the lazycommit thread to catch up - */ - int i; - - for (i = 0; i < 800; i++) { /* Too much? */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 4); - if ((log->cqueue.head == NULL) && - list_empty(&log->synclist)) - break; - } - } - assert(log->cqueue.head == NULL); - assert(list_empty(&log->synclist)); + lmLogWait(log); /* * We need to make sure all of the "written" metapages diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index b5a147dfcb9f..3be17d70e6ff 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -489,6 +489,7 @@ typedef struct logsyncblk { } extern int lmLogOpen(struct super_block *sb, log_t ** log); +extern void lmLogWait(log_t * log); extern int lmLogClose(struct super_block *sb, log_t * log); extern int lmLogSync(log_t * log, int nosyncwait); extern int lmLogQuiesce(log_t * log); diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index 9b0b258ad8f9..1ccd0fd4905f 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c @@ -64,15 +64,11 @@ int jfs_umount(struct super_block *sb) * * if mounted read-write and log based recovery was enabled */ - if ((log = sbi->log)) { + if ((log = sbi->log)) /* - * close log: - * - * remove file system from log active file system list. + * Wait for outstanding transactions to be written to log: */ - log = sbi->log; - rc = lmLogClose(sb, log); - } + lmLogWait(log); /* * close fileset inode allocation map (aka fileset inode) @@ -113,6 +109,14 @@ int jfs_umount(struct super_block *sb) sbi->ipimap = NULL; /* + * Make sure all metadata makes it to disk before we mark + * the superblock as clean + */ + filemap_fdatawait(sbi->direct_inode->i_mapping); + filemap_fdatawrite(sbi->direct_inode->i_mapping); + filemap_fdatawait(sbi->direct_inode->i_mapping); + + /* * ensure all file system file pages are propagated to their * home blocks on disk (and their in-memory buffer pages are * invalidated) BEFORE updating file system superblock state @@ -120,10 +124,16 @@ int jfs_umount(struct super_block *sb) * consistent state) and log superblock active file system * list (to signify skip logredo()). */ - if (log) /* log = NULL if read-only mount */ + if (log) { /* log = NULL if read-only mount */ rc = updateSuper(sb, FM_CLEAN); - + /* + * close log: + * + * remove file system from log active file system list. + */ + rc = lmLogClose(sb, log); + } jFYI(0, (" UnMount JFS Complete: %d\n", rc)); return rc; } @@ -132,8 +142,9 @@ int jfs_umount(struct super_block *sb) int jfs_umount_rw(struct super_block *sb) { struct jfs_sb_info *sbi = JFS_SBI(sb); + log_t *log = sbi->log; - if (!sbi->log) + if (!log) return 0; /* @@ -141,13 +152,19 @@ int jfs_umount_rw(struct super_block *sb) * * remove file system from log active file system list. */ - lmLogClose(sb, sbi->log); + lmLogWait(log); + /* + * Make sure all metadata makes it to disk + */ dbSync(sbi->ipbmap); diSync(sbi->ipimap); + filemap_fdatawait(sbi->direct_inode->i_mapping); + filemap_fdatawrite(sbi->direct_inode->i_mapping); + filemap_fdatawait(sbi->direct_inode->i_mapping); - sbi->log = 0; + updateSuper(sb, FM_CLEAN); + sbi->log = NULL; - return updateSuper(sb, FM_CLEAN); - + return lmLogClose(sb, log); } |
