Commit 3686a398 authored by Dave Kleikamp's avatar Dave Kleikamp

[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.
parent 4ce6b618
...@@ -1385,6 +1385,35 @@ int lmLogClose(struct super_block *sb, log_t * log) ...@@ -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() * NAME: lmLogShutdown()
* *
...@@ -1411,23 +1440,7 @@ static int lmLogShutdown(log_t * log) ...@@ -1411,23 +1440,7 @@ static int lmLogShutdown(log_t * log)
jFYI(1, ("lmLogShutdown: log:0x%p\n", log)); jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
if (log->cqueue.head || !list_empty(&log->synclist)) { lmLogWait(log);
/*
* 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));
/* /*
* We need to make sure all of the "written" metapages * We need to make sure all of the "written" metapages
......
...@@ -489,6 +489,7 @@ typedef struct logsyncblk { ...@@ -489,6 +489,7 @@ typedef struct logsyncblk {
} }
extern int lmLogOpen(struct super_block *sb, log_t ** log); 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 lmLogClose(struct super_block *sb, log_t * log);
extern int lmLogSync(log_t * log, int nosyncwait); extern int lmLogSync(log_t * log, int nosyncwait);
extern int lmLogQuiesce(log_t * log); extern int lmLogQuiesce(log_t * log);
......
...@@ -64,15 +64,11 @@ int jfs_umount(struct super_block *sb) ...@@ -64,15 +64,11 @@ int jfs_umount(struct super_block *sb)
* *
* if mounted read-write and log based recovery was enabled * if mounted read-write and log based recovery was enabled
*/ */
if ((log = sbi->log)) { if ((log = sbi->log))
/* /*
* close log: * Wait for outstanding transactions to be written to log:
*
* remove file system from log active file system list.
*/ */
log = sbi->log; lmLogWait(log);
rc = lmLogClose(sb, log);
}
/* /*
* close fileset inode allocation map (aka fileset inode) * close fileset inode allocation map (aka fileset inode)
...@@ -112,6 +108,14 @@ int jfs_umount(struct super_block *sb) ...@@ -112,6 +108,14 @@ int jfs_umount(struct super_block *sb)
diFreeSpecial(ipbmap); diFreeSpecial(ipbmap);
sbi->ipimap = NULL; 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 * ensure all file system file pages are propagated to their
* home blocks on disk (and their in-memory buffer pages are * home blocks on disk (and their in-memory buffer pages are
...@@ -120,10 +124,16 @@ int jfs_umount(struct super_block *sb) ...@@ -120,10 +124,16 @@ int jfs_umount(struct super_block *sb)
* consistent state) and log superblock active file system * consistent state) and log superblock active file system
* list (to signify skip logredo()). * 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); 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)); jFYI(0, (" UnMount JFS Complete: %d\n", rc));
return rc; return rc;
} }
...@@ -132,8 +142,9 @@ int jfs_umount(struct super_block *sb) ...@@ -132,8 +142,9 @@ int jfs_umount(struct super_block *sb)
int jfs_umount_rw(struct super_block *sb) int jfs_umount_rw(struct super_block *sb)
{ {
struct jfs_sb_info *sbi = JFS_SBI(sb); struct jfs_sb_info *sbi = JFS_SBI(sb);
log_t *log = sbi->log;
if (!sbi->log) if (!log)
return 0; return 0;
/* /*
...@@ -141,13 +152,19 @@ int jfs_umount_rw(struct super_block *sb) ...@@ -141,13 +152,19 @@ int jfs_umount_rw(struct super_block *sb)
* *
* remove file system from log active file system list. * 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); dbSync(sbi->ipbmap);
diSync(sbi->ipimap); 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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment