Module Name:    src
Committed By:   riastradh
Date:           Mon Oct  3 19:12:51 UTC 2022

Modified Files:
        src/sys/dev: cons.c

Log Message:
cons(9): Serialize open and close.

Kernel lock wasn't enough for this -- cdevvp, vn_lock, or VOP_OPEN
could block, allowing another thread to re-enter open.


To generate a diff of this commit:
cvs rdiff -u -r1.80 -r1.81 src/sys/dev/cons.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/dev/cons.c
diff -u src/sys/dev/cons.c:1.80 src/sys/dev/cons.c:1.81
--- src/sys/dev/cons.c:1.80	Mon Oct  3 19:12:29 2022
+++ src/sys/dev/cons.c	Mon Oct  3 19:12:51 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: cons.c,v 1.80 2022/10/03 19:12:29 riastradh Exp $	*/
+/*	$NetBSD: cons.c,v 1.81 2022/10/03 19:12:51 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.80 2022/10/03 19:12:29 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.81 2022/10/03 19:12:51 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.8
 #include <sys/vnode.h>
 #include <sys/kauth.h>
 #include <sys/mutex.h>
+#include <sys/module.h>
 
 #include <dev/cons.h>
 
@@ -83,6 +84,8 @@ const struct cdevsw cons_cdevsw = {
 	.d_flag = D_TTY
 };
 
+static struct kmutex cn_lock;
+
 struct	tty *constty = NULL;	/* virtual console output device */
 struct	consdev *cn_tab;	/* physical console device info */
 struct	vnode *cn_devvp[2];	/* vnode for underlying device. */
@@ -113,8 +116,12 @@ cnopen(dev_t dev, int flag, int mode, st
 	if (unit > 1)
 		return ENODEV;
 
-	if (cn_tab == NULL)
-		return (0);
+	mutex_enter(&cn_lock);
+
+	if (cn_tab == NULL) {
+		error = 0;
+		goto out;
+	}
 
 	/*
 	 * always open the 'real' console device, so we don't get nailed
@@ -145,15 +152,19 @@ cnopen(dev_t dev, int flag, int mode, st
 		 */
 		panic("cnopen: cn_tab->cn_dev == dev");
 	}
-	if (cn_devvp[unit] != NULLVP)
-		return 0;
+	if (cn_devvp[unit] != NULLVP) {
+		error = 0;
+		goto out;
+	}
 	if ((error = cdevvp(cndev, &cn_devvp[unit])) != 0) {
 		printf("cnopen: unable to get vnode reference\n");
-		return error;
+		goto out;
 	}
 	vn_lock(cn_devvp[unit], LK_EXCLUSIVE | LK_RETRY);
 	error = VOP_OPEN(cn_devvp[unit], flag, kauth_cred_get());
 	VOP_UNLOCK(cn_devvp[unit]);
+
+out:	mutex_exit(&cn_lock);
 	return error;
 }
 
@@ -165,8 +176,12 @@ cnclose(dev_t dev, int flag, int mode, s
 
 	unit = minor(dev);
 
-	if (cn_tab == NULL)
-		return (0);
+	mutex_enter(&cn_lock);
+
+	if (cn_tab == NULL) {
+		error = 0;
+		goto out;
+	}
 
 	vp = cn_devvp[unit];
 	cn_devvp[unit] = NULL;
@@ -174,6 +189,8 @@ cnclose(dev_t dev, int flag, int mode, s
 	error = VOP_CLOSE(vp, flag, kauth_cred_get());
 	VOP_UNLOCK(vp);
 	vrele(vp);
+
+out:	mutex_exit(&cn_lock);
 	return error;
 }
 
@@ -433,3 +450,21 @@ cn_redirect(dev_t *devp, int is_read, in
 	*devp = dev;
 	return true;
 }
+
+MODULE(MODULE_CLASS_DRIVER, cons, NULL);
+
+static int
+cons_modcmd(modcmd_t cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		mutex_init(&cn_lock, MUTEX_DEFAULT, IPL_NONE);
+		return 0;
+	case MODULE_CMD_FINI:
+		mutex_destroy(&cn_lock);
+		return 0;
+	default:
+		return ENOTTY;
+	}
+}

Reply via email to