Module Name: src
Committed By: hannken
Date: Fri Aug 26 11:03:53 UTC 2022
Modified Files:
src/sys/kern: vfs_mount.c
Log Message:
Two defects in vfs_getnewfsid():
- Parallel mounts may get the same fsid. Always increment "xxxfs_mntid"
to make it unlikely.
- Directly walk "mountlist" to prevent a rare deadlock where one thread
holds a vnode locked, calls vfs_getnewfsid() and the iterator has to
wait for a suspended file system while the thread suspending needs
this vnode lock.
To generate a diff of this commit:
cvs rdiff -u -r1.95 -r1.96 src/sys/kern/vfs_mount.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/vfs_mount.c
diff -u src/sys/kern/vfs_mount.c:1.95 src/sys/kern/vfs_mount.c:1.96
--- src/sys/kern/vfs_mount.c:1.95 Mon Aug 22 09:14:24 2022
+++ src/sys/kern/vfs_mount.c Fri Aug 26 11:03:53 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_mount.c,v 1.95 2022/08/22 09:14:24 hannken Exp $ */
+/* $NetBSD: vfs_mount.c,v 1.96 2022/08/26 11:03:53 hannken Exp $ */
/*-
* Copyright (c) 1997-2020 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.95 2022/08/22 09:14:24 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.96 2022/08/26 11:03:53 hannken Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -220,23 +220,41 @@ void
vfs_getnewfsid(struct mount *mp)
{
static u_short xxxfs_mntid;
+ struct mountlist_entry *me;
fsid_t tfsid;
int mtype;
mutex_enter(&mntid_lock);
- mtype = makefstype(mp->mnt_op->vfs_name);
- mp->mnt_stat.f_fsidx.__fsid_val[0] = makedev(mtype, 0);
- mp->mnt_stat.f_fsidx.__fsid_val[1] = mtype;
- mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
if (xxxfs_mntid == 0)
++xxxfs_mntid;
+ mtype = makefstype(mp->mnt_op->vfs_name);
tfsid.__fsid_val[0] = makedev(mtype & 0xff, xxxfs_mntid);
tfsid.__fsid_val[1] = mtype;
- while (vfs_getvfs(&tfsid)) {
- tfsid.__fsid_val[0]++;
- xxxfs_mntid++;
+ /* Always increment to not return the same fsid to parallel mounts. */
+ xxxfs_mntid++;
+
+ /*
+ * Directly walk mountlist to prevent deadlock through
+ * mountlist_iterator_next() -> vfs_busy().
+ */
+ mutex_enter(&mountlist_lock);
+ for (me = TAILQ_FIRST(&mountlist); me != TAILQ_END(&mountlist); ) {
+ if (me->me_type == ME_MOUNT &&
+ me->me_mount->mnt_stat.f_fsidx.__fsid_val[0] ==
+ tfsid.__fsid_val[0] &&
+ me->me_mount->mnt_stat.f_fsidx.__fsid_val[1] ==
+ tfsid.__fsid_val[1]) {
+ tfsid.__fsid_val[0]++;
+ xxxfs_mntid++;
+ me = TAILQ_FIRST(&mountlist);
+ } else {
+ me = TAILQ_NEXT(me, me_list);
+ }
}
+ mutex_exit(&mountlist_lock);
+
mp->mnt_stat.f_fsidx.__fsid_val[0] = tfsid.__fsid_val[0];
+ mp->mnt_stat.f_fsidx.__fsid_val[1] = tfsid.__fsid_val[1];
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mutex_exit(&mntid_lock);
}