Module Name:    src
Committed By:   pgoyette
Date:           Fri Jul 22 03:39:43 UTC 2016

Modified Files:
        src/sys/dev [pgoyette-localcount]: cgd.c

Log Message:
Make sure that whenever we're using the cgd device's softc, we maintain
a reference to the device so things won't get deleted out from under us!


To generate a diff of this commit:
cvs rdiff -u -r1.108.2.4 -r1.108.2.5 src/sys/dev/cgd.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/cgd.c
diff -u src/sys/dev/cgd.c:1.108.2.4 src/sys/dev/cgd.c:1.108.2.5
--- src/sys/dev/cgd.c:1.108.2.4	Wed Jul 20 06:51:13 2016
+++ src/sys/dev/cgd.c	Fri Jul 22 03:39:43 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: cgd.c,v 1.108.2.4 2016/07/20 06:51:13 pgoyette Exp $ */
+/* $NetBSD: cgd.c,v 1.108.2.5 2016/07/22 03:39:43 pgoyette Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.108.2.4 2016/07/20 06:51:13 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.108.2.5 2016/07/22 03:39:43 pgoyette Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -102,7 +102,7 @@ const struct cdevsw cgd_cdevsw = {
 static int cgd_match(device_t, cfdata_t, void *);
 static void cgd_attach(device_t, device_t, void *);
 static int cgd_detach(device_t, int);
-static struct cgd_softc	*cgd_spawn(int);
+static struct cgd_softc	*cgd_spawn(int, *device_t);
 static int cgd_destroy(device_t);
 
 /* Internal Functions */
@@ -172,7 +172,8 @@ static void	hexprint(const char *, void 
 /* Utility Functions */
 
 #define CGDUNIT(x)		DISKUNIT(x)
-#define GETCGD_SOFTC(_cs, x)	if (!((_cs) = getcgd_softc(x))) return ENXIO
+#define GETCGD_SOFTC(_cs, x, _dv)				\
+	if (!((_cs) = getcgd_softc(x, &_dv))) return ENXIO;
 
 /* The code */
 
@@ -188,16 +189,20 @@ cgd_release(dev_t dev)
 }
 
 static struct cgd_softc *
-getcgd_softc(dev_t dev)
+getcgd_softc(dev_t dev, device_t *self)
 {
 	int	unit = CGDUNIT(dev);
 	struct cgd_softc *sc;
 
 	DPRINTF_FOLLOW(("getcgd_softc(0x%"PRIx64"): unit = %d\n", dev, unit));
 
-	sc = device_lookup_private(&cgd_cd, unit);
+	*self = device_lookup_acquire(&cgd_cd, unit);
+	if (*self == NULL)
+		return NULL;
+	
+	sc = device_private(*self);
 	if (sc == NULL)
-		sc = cgd_spawn(unit);
+		sc = cgd_spawn(unit, *self);
 	return sc;
 }
 
@@ -256,9 +261,8 @@ cgdattach(int num)
 }
 
 static struct cgd_softc *
-cgd_spawn(int unit)
+cgd_spawn(int unit, device_t *self)
 {
-	device_t self;
 	cfdata_t cf;
 
 	cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
@@ -270,14 +274,15 @@ cgd_spawn(int unit)
 	if (config_attach_pseudo(cf) == NULL)
 		return NULL;
 
-	self = device_lookup_acquire(&cgd_cd, unit);
+	*self = device_lookup_acquire(&cgd_cd, unit);
 	if (self == NULL)
 		return NULL;
 	else
 		/*
-		 * Note that we return with a reference to the device!
+		 * Note that we return while still holding a reference
+		 * to the device!
 		 */
-		return device_private(self);
+		return device_private(*self);
 }
 
 static int
@@ -297,40 +302,50 @@ cgd_destroy(device_t dev)
 static int
 cgdopen(dev_t dev, int flags, int fmt, struct lwp *l)
 {
+	device_t self;
+	int	error;
 	struct	cgd_softc *cs;
 
 	DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
-	GETCGD_SOFTC(cs, dev);
-	return dk_open(&cs->sc_dksc, dev, flags, fmt, l);
+	GETCGD_SOFTC(cs, dev, self);
+	error = dk_open(&cs->sc_dksc, dev, flags, fmt, l);
+	device_release(self);
+	return error;
 }
 
 static int
 cgdclose(dev_t dev, int flags, int fmt, struct lwp *l)
 {
 	int error;
+	device_t self;
 	struct	cgd_softc *cs;
 	struct	dk_softc *dksc;
 
 	DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
-	GETCGD_SOFTC(cs, dev);
+	GETCGD_SOFTC(cs, dev, self);
 	dksc = &cs->sc_dksc;
-	if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0)
+	if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0) {
+		device_release(self);
 		return error;
+	}
 
 	if (!DK_ATTACHED(dksc)) {
 		if ((error = cgd_destroy(cs->sc_dksc.sc_dev)) != 0) {
 			aprint_error_dev(dksc->sc_dev,
 			    "unable to detach instance\n");
+			device_release(self);
 			return error;
 		}
 	}
-	return 0;
+	device_release(self);
+	return error;
 }
 
 static void
 cgdstrategy(struct buf *bp)
 {
-	struct	cgd_softc *cs = getcgd_softc(bp->b_dev);
+	device_t self;
+	struct	cgd_softc *cs = getcgd_softc(bp->b_dev, &self);
 	struct	dk_softc *dksc = &cs->sc_dksc;
 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
 
@@ -349,12 +364,14 @@ cgdstrategy(struct buf *bp)
 		bp->b_resid = bp->b_bcount;
 		biodone(bp);
 		cgd_release(bp->b_dev);
+		device_release(self);
 		return;
 	}
 
 	/* XXXrcd: Should we test for (cs != NULL)? */
 	dk_strategy(&cs->sc_dksc, bp);
 	cgd_release(bp->b_dev);
+	device_release(self);
 	return;
 }
 
@@ -362,7 +379,8 @@ static int
 cgdsize(dev_t dev)
 {
 	int retval;
-	struct cgd_softc *cs = getcgd_softc(dev);
+	device_t self;
+	struct cgd_softc *cs = getcgd_softc(dev, &self);
 
 	DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
 	if (!cs)
@@ -371,6 +389,7 @@ cgdsize(dev_t dev)
 		retval = dk_size(&cs->sc_dksc, dev);
 
 	cgd_release(dev);
+	device_release(self);
 	return retval;
 }
 
@@ -481,8 +500,9 @@ static void
 cgdiodone(struct buf *nbp)
 {
 	dev_t dev;
+	device_t self;
 	struct	buf *obp = nbp->b_private;
-	struct	cgd_softc *cs = getcgd_softc(obp->b_dev);
+	struct	cgd_softc *cs = getcgd_softc(obp->b_dev, &self);
 	struct	dk_softc *dksc = &cs->sc_dksc;
 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
 	daddr_t	bn;
@@ -531,6 +551,7 @@ cgdiodone(struct buf *nbp)
 	dev = obp->b_dev;
 	dk_done(dksc, obp);
 	cgd_release(dev);
+	device_release(self);
 
 	dk_start(dksc, NULL);
 }
@@ -585,40 +606,52 @@ cgd_dumpblocks(device_t dev, void *va, d
 static int
 cgdread(dev_t dev, struct uio *uio, int flags)
 {
+	device_t self;
+	int	error;
 	struct	cgd_softc *cs;
 	struct	dk_softc *dksc;
 
 	DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n",
 	    (unsigned long long)dev, uio, flags));
-	GETCGD_SOFTC(cs, dev);
+	GETCGD_SOFTC(cs, dev, self);
 	dksc = &cs->sc_dksc;
 	if (!DK_ATTACHED(dksc))
 		return ENXIO;
-	return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
+	error = physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
+	device_release(self);
+	return error;
 }
 
 /* XXX: we should probably put these into dksubr.c, mostly */
 static int
 cgdwrite(dev_t dev, struct uio *uio, int flags)
 {
+	device_t self;
+	int	error;
 	struct	cgd_softc *cs;
 	struct	dk_softc *dksc;
 
 	DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
-	GETCGD_SOFTC(cs, dev);
+	GETCGD_SOFTC(cs, dev, self);
 	dksc = &cs->sc_dksc;
-	if (!DK_ATTACHED(dksc))
+	if (!DK_ATTACHED(dksc)) {
+		device_release(self);
 		return ENXIO;
-	return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
+	}
+	error = physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
+	device_release(self);
+	return error;
 }
 
 static int
 cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
 {
+	device_t self;
 	struct	cgd_softc *cs;
 	struct	dk_softc *dksc;
 	int	part = DISKPART(dev);
 	int	pmask = 1 << part;
+	int	error = 0;
 
 	DPRINTF_FOLLOW(("cgdioctl(0x%"PRIx64", %ld, %p, %d, %p)\n",
 	    dev, cmd, data, flag, l));
@@ -632,7 +665,7 @@ cgdioctl(dev_t dev, u_long cmd, void *da
 			return EBADF;
 		/* FALLTHROUGH */
 	default:
-		GETCGD_SOFTC(cs, dev);
+		GETCGD_SOFTC(cs, dev, self);
 		dksc = &cs->sc_dksc;
 		break;
 	}
@@ -640,46 +673,61 @@ cgdioctl(dev_t dev, u_long cmd, void *da
 	switch (cmd) {
 	case CGDIOCSET:
 		if (DK_ATTACHED(dksc))
-			return EBUSY;
-		return cgd_ioctl_set(cs, data, l);
+			error = EBUSY;
+		else
+			cgd_ioctl_set(cs, data, l);
+		break;
 	case CGDIOCCLR:
 		if (DK_BUSY(&cs->sc_dksc, pmask))
-			return EBUSY;
-		return cgd_ioctl_clr(cs, l);
+			error = EBUSY;
+		else
+			cgd_ioctl_clr(cs, l);
+		break;
 	case DIOCCACHESYNC:
 		/*
 		 * XXX Do we really need to care about having a writable
 		 * file descriptor here?
 		 */
 		if ((flag & FWRITE) == 0)
-			return (EBADF);
+			error = (EBADF);
 
 		/*
 		 * We pass this call down to the underlying disk.
 		 */
-		return VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred);
+		else
+			error = VOP_IOCTL(cs->sc_tvn, cmd, data, flag,
+			    l->l_cred);
+		break;
 	case DIOCGSTRATEGY:
 	case DIOCSSTRATEGY:
 		if (!DK_ATTACHED(dksc))
-			return ENOENT;
+			error = ENOENT;
 		/*FALLTHROUGH*/
 	default:
-		return dk_ioctl(dksc, dev, cmd, data, flag, l);
+		 if (error == 0)
+			error = dk_ioctl(dksc, dev, cmd, data, flag, l);
+		break;
 	case CGDIOCGET:
 		KASSERT(0);
-		return EINVAL;
+		error = EINVAL;
 	}
+	device_release(self);
+	return error;
 }
 
 static int
 cgddump(dev_t dev, daddr_t blkno, void *va, size_t size)
 {
+	device_t self;
+	int	error;
 	struct	cgd_softc *cs;
 
 	DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
 	    dev, blkno, va, (unsigned long)size));
-	GETCGD_SOFTC(cs, dev);
-	return dk_dump(&cs->sc_dksc, dev, blkno, va, size);
+	GETCGD_SOFTC(cs, dev, self);
+	error = dk_dump(&cs->sc_dksc, dev, blkno, va, size);
+	device_release(self);
+	return error;
 }
 
 /*
@@ -840,7 +888,8 @@ cgd_ioctl_clr(struct cgd_softc *cs, stru
 static int
 cgd_ioctl_get(dev_t dev, void *data, struct lwp *l)
 {
-	struct cgd_softc *cs = getcgd_softc(dev);
+	device_t self;
+	struct cgd_softc *cs = getcgd_softc(dev, &self);
 	struct cgd_user *cgu;
 	int unit;
 	struct	dk_softc *dksc = &cs->sc_dksc;
@@ -856,6 +905,7 @@ cgd_ioctl_get(dev_t dev, void *data, str
 
 	if (cgu->cgu_unit < 0) {
 		cgd_release(dev);
+		device_release(self);
 		return EINVAL;	/* XXX: should this be ENXIO? */
 	}
 
@@ -876,6 +926,7 @@ cgd_ioctl_get(dev_t dev, void *data, str
 		cgu->cgu_keylen = cs->sc_cdata.cf_keylen;
 	}
 	cgd_release(dev);
+	device_release(self);
 	return 0;
 }
 
@@ -1082,6 +1133,7 @@ cgd_modcmd(modcmd_t cmd, void *arg)
 	devmajor_t bmajor = -1, cmajor = -1;
 #endif
 
+printf("%s: cmd %d\n", __func__, cmd);
 	switch (cmd) {
 	case MODULE_CMD_INIT:
 #ifdef _MODULE
@@ -1140,11 +1192,13 @@ cgd_modcmd(modcmd_t cmd, void *arg)
 		break;
 
 	case MODULE_CMD_STAT:
-		return ENOTTY;
-
+		error = ENOTTY;
+		break;
 	default:
-		return ENOTTY;
+		error = ENOTTY;
+		break;
 	}
+printf("%s: return %d\n", __func__, error);
 
 	return error;
 }

Reply via email to