summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Kleikamp <shaggy@austin.ibm.com>2002-05-08 18:12:07 -0700
committerDave Kleikamp <shaggy@austin.ibm.com>2002-05-08 18:12:07 -0700
commit3686a39856c6f5ca34547b7e79f02eb1287f4bd5 (patch)
tree0ce77ad43e6a773212d56b31857517d1be4f87c6
parent4ce6b618012e4649b858bf2884f7fa060aee692b (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.c47
-rw-r--r--fs/jfs/jfs_logmgr.h1
-rw-r--r--fs/jfs/jfs_umount.c45
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);
}