Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Two defects in vfs_getnewfsid():



details:   https://anonhg.NetBSD.org/src/rev/a1844342c436
branches:  trunk
changeset: 369641:a1844342c436
user:      hannken <hannken%NetBSD.org@localhost>
date:      Fri Aug 26 11:03:53 2022 +0000

description:
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.

diffstat:

 sys/kern/vfs_mount.c |  36 +++++++++++++++++++++++++++---------
 1 files changed, 27 insertions(+), 9 deletions(-)

diffs (67 lines):

diff -r 29ef1673bef8 -r a1844342c436 sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c      Fri Aug 26 08:32:22 2022 +0000
+++ b/sys/kern/vfs_mount.c      Fri Aug 26 11:03:53 2022 +0000
@@ -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 @@
 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);
 }



Home | Main Index | Thread Index | Old Index