diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 083dbbb0c3268..e3b2cee416c19 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -2791,6 +2791,40 @@ void txLazyUnlock(struct tblock * tblk) LAZY_UNLOCK(flags); } + +/* + * txLazyDrain + * + * Wait for all pending lazy commit entries for this superblock + * to be processed by the jfsCommit thread. Must be called + * before freeing per-filesystem structures during unmount. + */ +void txLazyDrain(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct tblock *tblk; + unsigned long flags; + bool found; + + do { + found = false; + LAZY_LOCK(flags); + list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) { + if (tblk->sb == sb) { + found = true; + break; + } + } + if (!found && (sbi->commit_state & IN_LAZYCOMMIT)) + found = true; + LAZY_UNLOCK(flags); + + if (found) { + wake_up(&jfs_commit_thread_wait); + schedule_timeout_uninterruptible(1); + } + } while (found); +} static void LogSyncRelease(struct metapage * mp) { struct jfs_log *log = mp->log; diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h index ba71eb5ced567..fbbaed26c52bd 100644 --- a/fs/jfs/jfs_txnmgr.h +++ b/fs/jfs/jfs_txnmgr.h @@ -291,6 +291,7 @@ extern void txFreelock(struct inode *); extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *, struct tlock *); extern void txQuiesce(struct super_block *); +extern void txLazyDrain(struct super_block *); extern void txResume(struct super_block *); extern void txLazyUnlock(struct tblock *); extern int jfs_lazycommit(void *); diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index 18569f1eaabdb..657707361be2a 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c @@ -58,6 +58,13 @@ int jfs_umount(struct super_block *sb) */ jfs_flush_journal(log, 2); + /* + * Drain any pending lazy commit entries for this filesystem so + * the jfsCommit thread does not access freed structures. + */ + if (log) + txLazyDrain(sb); + /* * Hold log lock so write_special_inodes (lmLogSync) cannot see * this sbi with a NULL inode pointer while iterating log->sb_list. @@ -142,6 +149,7 @@ int jfs_umount_rw(struct super_block *sb) * remove file system from log active file system list. */ jfs_flush_journal(log, 2); + txLazyDrain(sb); /* * Make sure all metadata makes it to disk