]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Fix JFS file system corruption
authorDave Kleikamp <shaggy@austin.ibm.com>
Thu, 9 May 2002 01:12:07 +0000 (18:12 -0700)
committerDave Kleikamp <shaggy@austin.ibm.com>
Thu, 9 May 2002 01:12:07 +0000 (18:12 -0700)
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.

fs/jfs/jfs_logmgr.c
fs/jfs/jfs_logmgr.h
fs/jfs/jfs_umount.c

index 7270bd48729e88370554ddbaef325d5317b6037b..a2e91a8535162d2cdb2c2c2352b01c7d6ef26219 100644 (file)
@@ -1385,6 +1385,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()
  *
@@ -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
index b5a147dfcb9f5b8e4762c1eaa5e98e1905aa00b6..3be17d70e6ffce990a01bb426d9a22b006401212 100644 (file)
@@ -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);
index 9b0b258ad8f9389b2eb30597f397113ba7d03ec3..1ccd0fd4905fb5faa342bdffa84733e46796a447 100644 (file)
@@ -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)
@@ -112,6 +108,14 @@ int jfs_umount(struct super_block *sb)
        diFreeSpecial(ipbmap);
        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 
@@ -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);
 }