Source-Changes-HG archive

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

[src/trunk]: src/sys/miscfs/specfs specfs: Take an I/O reference in spec_node...



details:   https://anonhg.NetBSD.org/src/rev/dbe8bce6a8b7
branches:  trunk
changeset: 364514:dbe8bce6a8b7
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Mar 28 12:37:01 2022 +0000

description:
specfs: Take an I/O reference in spec_node_setmountedfs.

This is not quite correct.  We _should_ require the caller to hold a
vnode lock around spec_node_getmountedfs, and an exclusive vnode lock
around spec_node_setmountedfs, so that it is only necessary to check
whether revoke has already happened, not hold an I/O reference.

Unfortunately, various callers in various file systems don't follow
this sensible rule.  So let's at least make sure the vnode can't be
revoked in spec_node_setmountedfs, while we're in bdev_ioctl, and
leave a comment explaining what the sorry state of affairs is and how
to fix it later.

diffstat:

 sys/miscfs/specfs/spec_vnops.c |  47 +++++++++++++++++++++++++++++++++++------
 1 files changed, 40 insertions(+), 7 deletions(-)

diffs (87 lines):

diff -r e6bf5a15b610 -r dbe8bce6a8b7 sys/miscfs/specfs/spec_vnops.c
--- a/sys/miscfs/specfs/spec_vnops.c    Mon Mar 28 12:36:51 2022 +0000
+++ b/sys/miscfs/specfs/spec_vnops.c    Mon Mar 28 12:37:01 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: spec_vnops.c,v 1.202 2022/03/28 12:36:51 riastradh Exp $       */
+/*     $NetBSD: spec_vnops.c,v 1.203 2022/03/28 12:37:01 riastradh Exp $       */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.202 2022/03/28 12:36:51 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.203 2022/03/28 12:37:01 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -498,6 +498,11 @@
 
 /*
  * Get the file system mounted on this block device.
+ *
+ * XXX Caller should hold the vnode lock -- shared or exclusive -- so
+ * that this can't changed, and the vnode can't be revoked while we
+ * examine it.  But not all callers do, and they're scattered through a
+ * lot of file systems, so we can't assert this yet.
  */
 struct mount *
 spec_node_getmountedfs(vnode_t *devvp)
@@ -512,23 +517,51 @@
 
 /*
  * Set the file system mounted on this block device.
+ *
+ * XXX Caller should hold the vnode lock exclusively so this can't be
+ * changed or assumed by spec_node_getmountedfs while we change it, and
+ * the vnode can't be revoked while we handle it.  But not all callers
+ * do, and they're scattered through a lot of file systems, so we can't
+ * assert this yet.  Instead, for now, we'll take an I/O reference so
+ * at least the ioctl doesn't race with revoke/detach.
+ *
+ * If you do change this to assert an exclusive vnode lock, you must
+ * also do vdead_check before trying bdev_ioctl, because the vnode may
+ * have been revoked by the time the caller locked it, and this is
+ * _not_ a vop -- calls to spec_node_setmountedfs don't go through
+ * v_op, so revoking the vnode doesn't prevent further calls.
+ *
+ * XXX Caller should additionally have the vnode open, at least if mp
+ * is nonnull, but I'm not sure all callers do that -- need to audit.
+ * Currently udf closes the vnode before clearing the mount.
  */
 void
 spec_node_setmountedfs(vnode_t *devvp, struct mount *mp)
 {
        struct dkwedge_info dkw;
+       struct specnode *sn;
+       dev_t dev;
+       int error;
 
        KASSERT(devvp->v_type == VBLK);
-       KASSERT(devvp->v_specnode->sn_dev->sd_mountpoint == NULL || mp == NULL);
-       devvp->v_specnode->sn_dev->sd_mountpoint = mp;
-       if (mp == NULL)
+
+       error = spec_io_enter(devvp, &sn, &dev);
+       if (error)
                return;
 
-       if (bdev_ioctl(devvp->v_rdev, DIOCGWEDGEINFO, &dkw, FREAD, curlwp) != 0)
-               return;
+       KASSERT(sn->sn_dev->sd_mountpoint == NULL || mp == NULL);
+       sn->sn_dev->sd_mountpoint = mp;
+       if (mp == NULL)
+               goto out;
+
+       error = bdev_ioctl(dev, DIOCGWEDGEINFO, &dkw, FREAD, curlwp);
+       if (error)
+               goto out;
 
        strlcpy(mp->mnt_stat.f_mntfromlabel, dkw.dkw_wname,
            sizeof(mp->mnt_stat.f_mntfromlabel));
+
+out:   spec_io_exit(devvp, sn);
 }
 
 /*



Home | Main Index | Thread Index | Old Index