Module Name:    src
Committed By:   thorpej
Date:           Sun May 16 21:03:38 UTC 2021

Modified Files:
        src/sys/dev/i2c [thorpej-i2c-spi-conf]: i2c.c

Log Message:
- Set D_MCLOSE in the iic_cdevsw so that we get a d_close call for
  each close so that the module ref counting works properly.
- Rearrange things a little to avoid holding the iic_mtx a long as
  previously done.


To generate a diff of this commit:
cvs rdiff -u -r1.78.2.3 -r1.78.2.4 src/sys/dev/i2c/i2c.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/i2c/i2c.c
diff -u src/sys/dev/i2c/i2c.c:1.78.2.3 src/sys/dev/i2c/i2c.c:1.78.2.4
--- src/sys/dev/i2c/i2c.c:1.78.2.3	Sun May 16 04:40:08 2021
+++ src/sys/dev/i2c/i2c.c	Sun May 16 21:03:38 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2c.c,v 1.78.2.3 2021/05/16 04:40:08 thorpej Exp $	*/
+/*	$NetBSD: i2c.c,v 1.78.2.4 2021/05/16 21:03:38 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -69,7 +69,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.78.2.3 2021/05/16 04:40:08 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.78.2.4 2021/05/16 21:03:38 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -115,13 +115,6 @@ static dev_type_open(iic_open);
 static dev_type_close(iic_close);
 static dev_type_ioctl(iic_ioctl);
 
-int iic_init(void);
-
-kmutex_t iic_mtx;
-int iic_refcnt;
-
-ONCE_DECL(iic_once);
-
 const struct cdevsw iic_cdevsw = {
 	.d_open = iic_open,
 	.d_close = iic_close,
@@ -134,11 +127,16 @@ const struct cdevsw iic_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MCLOSE,
 };
 
 static void	iic_smbus_intr_thread(void *);
 
+static kmutex_t iic_mtx;
+static int iic_refcnt;
+static bool iic_unloading;
+static ONCE_DECL(iic_once);
+
 static struct i2c_device_link *
 iic_devslot_lookup(struct iic_softc *sc, i2c_addr_t addr)
 {
@@ -928,22 +926,43 @@ iic_use_direct_match(const struct i2c_at
 static int
 iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
 {
-	struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
+	struct iic_softc *sc;
 
 	mutex_enter(&iic_mtx);
-	if (sc == NULL) {
+
+	if (iic_unloading) {
 		mutex_exit(&iic_mtx);
 		return ENXIO;
 	}
+
+	/* Hold a refrence while we look up the softc. */
+	if (iic_refcnt == INT_MAX) {
+		mutex_exit(&iic_mtx);
+		return EBUSY;
+	}
 	iic_refcnt++;
+
 	mutex_exit(&iic_mtx);
 
+	sc = device_lookup_private(&iic_cd, minor(dev));
+
+	if (sc == NULL) {
+		mutex_enter(&iic_mtx);
+		iic_refcnt--;
+		mutex_exit(&iic_mtx);
+		return ENXIO;
+	}
+
 	return 0;
 }
 
 static int
 iic_close(dev_t dev, int flag, int fmt, lwp_t *l)
 {
+	struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));;
+
+	KASSERT(iic_refcnt != 0);
+	KASSERT(sc != NULL);
 
 	mutex_enter(&iic_mtx);
 	iic_refcnt--;
@@ -1037,7 +1056,7 @@ MODULE(MODULE_CLASS_DRIVER, iic, "i2cexe
 #include "ioconf.c"
 #endif
 
-int
+static int
 iic_init(void)
 {
 
@@ -1084,19 +1103,26 @@ iic_modcmd(modcmd_t cmd, void *opaque)
 			mutex_exit(&iic_mtx);
 			return EBUSY;
 		}
+		iic_unloading = true;
+		mutex_exit(&iic_mtx);
 #ifdef _MODULE
 		error = config_fini_component(cfdriver_ioconf_iic,
 		    cfattach_ioconf_iic, cfdata_ioconf_iic);
 		if (error != 0) {
+			mutex_enter(&iic_mtx);
+			iic_unloading = false;
 			mutex_exit(&iic_mtx);
 			break;
 		}
 		error = devsw_detach(NULL, &iic_cdevsw);
-		if (error != 0)
+		if (error != 0) {
 			config_init_component(cfdriver_ioconf_iic,
 			    cfattach_ioconf_iic, cfdata_ioconf_iic);
+			mutex_enter(&iic_mtx);
+			iic_unloading = false;
+			mutex_exit(&iic_mtx);
+		}
 #endif
-		mutex_exit(&iic_mtx);
 		break;
 	default:
 		error = ENOTTY;

Reply via email to