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; }