[Syzbot reported] INFO: task syz-executor394:6204 blocked for more than 143 seconds. Not tainted 6.8.0-rc7-syzkaller-g707081b61156 #0 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:syz-executor394 state:D stack:0 pid:6204 tgid:6204 ppid:6201 flags:0x0000000c Call trace: __switch_to+0x314/0x560 arch/arm64/kernel/process.c:553 context_switch kernel/sched/core.c:5400 [inline] __schedule+0x1498/0x24b4 kernel/sched/core.c:6727 __schedule_loop kernel/sched/core.c:6802 [inline] schedule+0xb8/0x19c kernel/sched/core.c:6817 schedule_preempt_disabled+0x18/0x2c kernel/sched/core.c:6874 __mutex_lock_common+0xbd8/0x21a0 kernel/locking/mutex.c:684 __mutex_lock kernel/locking/mutex.c:752 [inline] mutex_lock_nested+0x2c/0x38 kernel/locking/mutex.c:804 lmLogClose+0xc8/0x4d4 fs/jfs/jfs_logmgr.c:1444 jfs_umount+0x274/0x360 fs/jfs/jfs_umount.c:114 jfs_put_super+0x90/0x188 fs/jfs/super.c:194 generic_shutdown_super+0x128/0x2b8 fs/super.c:641 kill_block_super+0x44/0x90 fs/super.c:1675 deactivate_locked_super+0xc4/0x12c fs/super.c:472 deactivate_super+0xe0/0x100 fs/super.c:505 cleanup_mnt+0x34c/0x3dc fs/namespace.c:1267 __cleanup_mnt+0x20/0x30 fs/namespace.c:1274 task_work_run+0x230/0x2e0 kernel/task_work.c:180 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] do_notify_resume+0x178/0x1f4 arch/arm64/kernel/entry-common.c:151 exit_to_user_mode_prepare arch/arm64/kernel/entry-common.c:169 [inline] exit_to_user_mode arch/arm64/kernel/entry-common.c:178 [inline] el0_svc+0xac/0x168 arch/arm64/kernel/entry-common.c:713 el0t_64_sync_handler+0x84/0xfc arch/arm64/kernel/entry-common.c:730 el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:598 [Fix] The jfs_log_mutex cannot distinguish different superblocks, resulting in multiple different superblocks competing for jfs_log_mutex. Reported-and-tested-by: syzbot+c824290332add8067111@xxxxxxxxxxxxxxxxxxxxxxxxx Signed-off-by: Edward Adam Davis <eadavis@xxxxxx> --- fs/jfs/jfs_incore.h | 1 + fs/jfs/jfs_logmgr.c | 26 +++++++++++++------------- fs/jfs/super.c | 1 + 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 10934f9a11be..56d336a49985 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -197,6 +197,7 @@ struct jfs_sb_info { kgid_t gid; /* gid to override on-disk gid */ uint umask; /* umask to override on-disk umask */ uint minblks_trim; /* minimum blocks, for online trim */ + struct mutex simutex; }; /* jfs_sb_info commit_state */ diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 73389c68e251..b5609a7618e5 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -155,7 +155,6 @@ do { \ */ static LIST_HEAD(jfs_external_logs); static struct jfs_log *dummy_log; -static DEFINE_MUTEX(jfs_log_mutex); /* * forward references @@ -1068,19 +1067,19 @@ int lmLogOpen(struct super_block *sb) if (sbi->mntflag & JFS_INLINELOG) return open_inline_log(sb); - mutex_lock(&jfs_log_mutex); + mutex_lock(&sbi->simutex); list_for_each_entry(log, &jfs_external_logs, journal_list) { if (file_bdev(log->bdev_file)->bd_dev == sbi->logdev) { if (!uuid_equal(&log->uuid, &sbi->loguuid)) { jfs_warn("wrong uuid on JFS journal"); - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return -EINVAL; } /* * add file system to log active file system list */ if ((rc = lmLogFileSystem(log, sbi, 1))) { - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return rc; } goto journal_found; @@ -1088,7 +1087,7 @@ int lmLogOpen(struct super_block *sb) } if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) { - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return -ENOMEM; } INIT_LIST_HEAD(&log->sb_list); @@ -1130,7 +1129,7 @@ int lmLogOpen(struct super_block *sb) sbi->log = log; LOG_UNLOCK(log); - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return 0; /* @@ -1144,7 +1143,7 @@ int lmLogOpen(struct super_block *sb) fput(bdev_file); free: /* free log descriptor */ - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); kfree(log); jfs_warn("lmLogOpen: exit(%d)", rc); @@ -1187,12 +1186,13 @@ static int open_inline_log(struct super_block *sb) static int open_dummy_log(struct super_block *sb) { int rc; + struct jfs_sb_info *sbi = JFS_SBI(sb); - mutex_lock(&jfs_log_mutex); + mutex_lock(&sbi->simutex); if (!dummy_log) { dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL); if (!dummy_log) { - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return -ENOMEM; } INIT_LIST_HEAD(&dummy_log->sb_list); @@ -1205,7 +1205,7 @@ static int open_dummy_log(struct super_block *sb) if (rc) { kfree(dummy_log); dummy_log = NULL; - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return rc; } } @@ -1214,7 +1214,7 @@ static int open_dummy_log(struct super_block *sb) list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list); JFS_SBI(sb)->log = dummy_log; LOG_UNLOCK(dummy_log); - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); return 0; } @@ -1441,7 +1441,7 @@ int lmLogClose(struct super_block *sb) jfs_info("lmLogClose: log:0x%p", log); - mutex_lock(&jfs_log_mutex); + mutex_lock(&sbi->simutex); LOG_LOCK(log); list_del(&sbi->log_list); LOG_UNLOCK(log); @@ -1490,7 +1490,7 @@ int lmLogClose(struct super_block *sb) kfree(log); out: - mutex_unlock(&jfs_log_mutex); + mutex_unlock(&sbi->simutex); jfs_info("lmLogClose: exit(%d)", rc); return rc; } diff --git a/fs/jfs/super.c b/fs/jfs/super.c index e1be21ca5d6e..23628ca3990c 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -504,6 +504,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) sbi->uid = INVALID_UID; sbi->gid = INVALID_GID; sbi->umask = -1; + mutex_init(&sbi->simutex); /* initialize the mount flag and determine the default error handler */ flag = JFS_ERR_REMOUNT_RO; -- 2.43.0