[Midnightbsd-cvs] src [10005] trunk/sys/geom/geom_dev.c: sync with freebsd 10 stable
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sun May 27 17:18:26 EDT 2018
Revision: 10005
http://svnweb.midnightbsd.org/src/?rev=10005
Author: laffer1
Date: 2018-05-27 17:18:26 -0400 (Sun, 27 May 2018)
Log Message:
-----------
sync with freebsd 10 stable
Modified Paths:
--------------
trunk/sys/geom/geom_dev.c
Modified: trunk/sys/geom/geom_dev.c
===================================================================
--- trunk/sys/geom/geom_dev.c 2018-05-27 21:15:33 UTC (rev 10004)
+++ trunk/sys/geom/geom_dev.c 2018-05-27 21:18:26 UTC (rev 10005)
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/geom/geom_dev.c,v 1.94 2007/05/05 17:02:19 pjd Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/geom/geom_dev.c 315705 2017-03-22 07:54:29Z mav $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -83,6 +83,8 @@
.d_flags = D_DISK | D_TRACKCLOSE,
};
+static g_init_t g_dev_init;
+static g_fini_t g_dev_fini;
static g_taste_t g_dev_taste;
static g_orphan_t g_dev_orphan;
static g_attrchanged_t g_dev_attrchanged;
@@ -90,6 +92,8 @@
static struct g_class g_dev_class = {
.name = "DEV",
.version = G_VERSION,
+ .init = g_dev_init,
+ .fini = g_dev_fini,
.taste = g_dev_taste,
.orphan = g_dev_orphan,
.attrchanged = g_dev_attrchanged
@@ -108,12 +112,86 @@
"delete request sent to the provider. Larger requests are chunked "
"so they can be interrupted. (0 = disable chunking)");
+static char *dumpdev = NULL;
static void
+g_dev_init(struct g_class *mp)
+{
+
+ dumpdev = getenv("dumpdev");
+}
+
+static void
+g_dev_fini(struct g_class *mp)
+{
+
+ freeenv(dumpdev);
+ dumpdev = NULL;
+}
+
+static int
+g_dev_setdumpdev(struct cdev *dev, struct thread *td)
+{
+ struct g_kerneldump kd;
+ struct g_consumer *cp;
+ int error, len;
+
+ if (dev == NULL)
+ return (set_dumper(NULL, NULL, td));
+
+ cp = dev->si_drv2;
+ len = sizeof(kd);
+ kd.offset = 0;
+ kd.length = OFF_MAX;
+ error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
+ if (error == 0) {
+ error = set_dumper(&kd.di, devtoname(dev), td);
+ if (error == 0)
+ dev->si_flags |= SI_DUMPDEV;
+ }
+ return (error);
+}
+
+static int
+init_dumpdev(struct cdev *dev)
+{
+ struct g_consumer *cp;
+ const char *devprefix = "/dev/", *devname;
+ int error;
+ size_t len;
+
+ if (dumpdev == NULL)
+ return (0);
+
+ len = strlen(devprefix);
+ devname = devtoname(dev);
+ if (strcmp(devname, dumpdev) != 0 &&
+ (strncmp(dumpdev, devprefix, len) != 0 ||
+ strcmp(devname, dumpdev + len) != 0))
+ return (0);
+
+ cp = (struct g_consumer *)dev->si_drv2;
+ error = g_access(cp, 1, 0, 0);
+ if (error != 0)
+ return (error);
+
+ error = g_dev_setdumpdev(dev, curthread);
+ if (error == 0) {
+ freeenv(dumpdev);
+ dumpdev = NULL;
+ }
+
+ (void)g_access(cp, -1, 0, 0);
+
+ return (error);
+}
+
+static void
g_dev_destroy(void *arg, int flags __unused)
{
struct g_consumer *cp;
struct g_geom *gp;
struct g_dev_softc *sc;
+ char buf[SPECNAMELEN + 6];
g_topology_assert();
cp = arg;
@@ -120,6 +198,8 @@
gp = cp->geom;
sc = cp->private;
g_trace(G_T_TOPOLOGY, "g_dev_destroy(%p(%s))", cp, gp->name);
+ snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
+ devctl_notify_f("GEOM", "DEV", "DESTROY", buf, M_WAITOK);
if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
g_access(cp, -cp->acr, -cp->acw, -cp->ace);
g_detach(cp);
@@ -143,52 +223,68 @@
}
static void
-g_dev_attrchanged(struct g_consumer *cp, const char *attr)
+g_dev_set_physpath(struct g_consumer *cp)
{
struct g_dev_softc *sc;
+ char *physpath;
+ int error, physpath_len;
+
+ if (g_access(cp, 1, 0, 0) != 0)
+ return;
+
+ sc = cp->private;
+ physpath_len = MAXPATHLEN;
+ physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
+ error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
+ g_access(cp, -1, 0, 0);
+ if (error == 0 && strlen(physpath) != 0) {
+ struct cdev *dev, *old_alias_dev;
+ struct cdev **alias_devp;
+
+ dev = sc->sc_dev;
+ old_alias_dev = sc->sc_alias;
+ alias_devp = (struct cdev **)&sc->sc_alias;
+ make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp, dev,
+ old_alias_dev, physpath);
+ } else if (sc->sc_alias) {
+ destroy_dev((struct cdev *)sc->sc_alias);
+ sc->sc_alias = NULL;
+ }
+ g_free(physpath);
+}
+
+static void
+g_dev_set_media(struct g_consumer *cp)
+{
+ struct g_dev_softc *sc;
struct cdev *dev;
char buf[SPECNAMELEN + 6];
sc = cp->private;
- if (strcmp(attr, "GEOM::media") == 0) {
- dev = sc->sc_dev;
+ dev = sc->sc_dev;
+ snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
+ devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
+ devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
+ dev = sc->sc_alias;
+ if (dev != NULL) {
snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
- dev = sc->sc_alias;
- if (dev != NULL) {
- snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
- devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf,
- M_WAITOK);
- }
+ devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
+ }
+}
+
+static void
+g_dev_attrchanged(struct g_consumer *cp, const char *attr)
+{
+
+ if (strcmp(attr, "GEOM::media") == 0) {
+ g_dev_set_media(cp);
return;
}
- if (strcmp(attr, "GEOM::physpath") != 0)
+ if (strcmp(attr, "GEOM::physpath") == 0) {
+ g_dev_set_physpath(cp);
return;
-
- if (g_access(cp, 1, 0, 0) == 0) {
- char *physpath;
- int error, physpath_len;
-
- physpath_len = MAXPATHLEN;
- physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
- error =
- g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
- g_access(cp, -1, 0, 0);
- if (error == 0 && strlen(physpath) != 0) {
- struct cdev *old_alias_dev;
- struct cdev **alias_devp;
-
- dev = sc->sc_dev;
- old_alias_dev = sc->sc_alias;
- alias_devp = (struct cdev **)&sc->sc_alias;
- make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp,
- dev, old_alias_dev, physpath);
- } else if (sc->sc_alias) {
- destroy_dev((struct cdev *)sc->sc_alias);
- sc->sc_alias = NULL;
- }
- g_free(physpath);
}
}
@@ -214,7 +310,7 @@
struct g_dev_softc *sc;
int error, len;
struct cdev *dev, *adev;
- char buf[64], *val;
+ char buf[SPECNAMELEN + 6], *val;
g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
g_topology_assert();
@@ -223,6 +319,7 @@
mtx_init(&sc->sc_mtx, "g_dev", NULL, MTX_DEF);
cp = g_new_consumer(gp);
cp->private = sc;
+ cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
error = g_attach(cp, pp);
KASSERT(error == 0,
("g_dev_taste(%s) failed to g_attach, err=%d", pp->name, error));
@@ -238,6 +335,7 @@
g_free(sc);
return (NULL);
}
+ dev->si_flags |= SI_UNMAPPED;
sc->sc_dev = dev;
/* Search for device alias name and create it if found. */
@@ -252,22 +350,26 @@
freeenv(val);
make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
&adev, dev, "%s", buf);
+ adev->si_flags |= SI_UNMAPPED;
break;
}
}
- if (pp->flags & G_PF_CANDELETE)
- dev->si_flags |= SI_CANDELETE;
dev->si_iosize_max = MAXPHYS;
dev->si_drv2 = cp;
+ error = init_dumpdev(dev);
+ if (error != 0)
+ printf("%s: init_dumpdev() failed (gp->name=%s, error=%d)\n",
+ __func__, gp->name, error);
if (adev != NULL) {
- if (pp->flags & G_PF_CANDELETE)
- adev->si_flags |= SI_CANDELETE;
adev->si_iosize_max = MAXPHYS;
adev->si_drv2 = cp;
+ init_dumpdev(adev);
}
g_dev_attrchanged(cp, "GEOM::physpath");
+ snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
+ devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK);
return (gp);
}
@@ -292,6 +394,13 @@
#else
e = 0;
#endif
+
+ /*
+ * This happens on attempt to open a device node with O_EXEC.
+ */
+ if (r + w + e == 0)
+ return (EINVAL);
+
if (w) {
/*
* When running in very secure mode, do not allow
@@ -335,6 +444,20 @@
#else
e = 0;
#endif
+
+ /*
+ * The vgonel(9) - caused by eg. forced unmount of devfs - calls
+ * VOP_CLOSE(9) on devfs vnode without any FREAD or FWRITE flags,
+ * which would result in zero deltas, which in turn would cause
+ * panic in g_access(9).
+ *
+ * Note that we cannot zero the counters (ie. do "r = cp->acr"
+ * etc) instead, because the consumer might be opened in another
+ * devfs instance.
+ */
+ if (r + w + e == 0)
+ return (EINVAL);
+
sc = cp->private;
mtx_lock(&sc->sc_mtx);
sc->sc_open += r + w + e;
@@ -358,10 +481,8 @@
{
struct g_consumer *cp;
struct g_provider *pp;
- struct g_kerneldump kd;
- off_t offset, length, chunk;
+ off_t offset, length, chunk, odd;
int i, error;
- u_int u;
cp = dev->si_drv2;
pp = cp->provider;
@@ -396,21 +517,10 @@
error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
break;
case DIOCSKERNELDUMP:
- u = *((u_int *)data);
- if (!u) {
- set_dumper(NULL);
- error = 0;
- break;
- }
- kd.offset = 0;
- kd.length = OFF_MAX;
- i = sizeof kd;
- error = g_io_getattr("GEOM::kerneldump", cp, &i, &kd);
- if (!error) {
- error = set_dumper(&kd.di);
- if (!error)
- dev->si_flags |= SI_DUMPDEV;
- }
+ if (*(u_int *)data == 0)
+ error = g_dev_setdumpdev(NULL, td);
+ else
+ error = g_dev_setdumpdev(dev, td);
break;
case DIOCGFLUSH:
error = g_io_flush(cp);
@@ -431,6 +541,13 @@
g_dev_del_max_sectors * cp->provider->sectorsize) {
chunk = g_dev_del_max_sectors *
cp->provider->sectorsize;
+ if (cp->provider->stripesize > 0) {
+ odd = (offset + chunk +
+ cp->provider->stripeoffset) %
+ cp->provider->stripesize;
+ if (chunk > odd)
+ chunk -= odd;
+ }
}
error = g_delete_data(cp, offset, chunk);
length -= chunk;
@@ -465,6 +582,16 @@
if (error == 0 && *(char *)data == '\0')
error = ENOENT;
break;
+ case DIOCGATTR: {
+ struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
+
+ if (arg->len > sizeof(arg->value)) {
+ error = EINVAL;
+ break;
+ }
+ error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
+ break;
+ }
default:
if (cp->provider->geom->ioctl != NULL) {
error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);
@@ -488,16 +615,16 @@
sc = cp->private;
bp = bp2->bio_parent;
bp->bio_error = bp2->bio_error;
- if (bp->bio_error != 0) {
+ bp->bio_completed = bp2->bio_completed;
+ bp->bio_resid = bp->bio_length - bp2->bio_completed;
+ if (bp2->bio_error != 0) {
g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
- bp2, bp->bio_error);
+ bp2, bp2->bio_error);
bp->bio_flags |= BIO_ERROR;
} else {
g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
- bp2, bp, bp->bio_resid, (intmax_t)bp2->bio_completed);
+ bp2, bp, bp2->bio_resid, (intmax_t)bp2->bio_completed);
}
- bp->bio_resid = bp->bio_length - bp2->bio_completed;
- bp->bio_completed = bp2->bio_completed;
g_destroy_bio(bp2);
destroy = 0;
mtx_lock(&sc->sc_mtx);
@@ -509,7 +636,7 @@
}
mtx_unlock(&sc->sc_mtx);
if (destroy)
- g_post_event(g_dev_destroy, cp, M_WAITOK, NULL);
+ g_post_event(g_dev_destroy, cp, M_NOWAIT, NULL);
biodone(bp);
}
@@ -523,7 +650,8 @@
KASSERT(bp->bio_cmd == BIO_READ ||
bp->bio_cmd == BIO_WRITE ||
- bp->bio_cmd == BIO_DELETE,
+ bp->bio_cmd == BIO_DELETE ||
+ bp->bio_cmd == BIO_FLUSH,
("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
dev = bp->bio_dev;
cp = dev->si_drv2;
@@ -617,7 +745,7 @@
/* Reset any dump-area set on this device */
if (dev->si_flags & SI_DUMPDEV)
- set_dumper(NULL);
+ (void)set_dumper(NULL, NULL, curthread);
/* Destroy the struct cdev *so we get no more requests */
destroy_dev_sched_cb(dev, g_dev_callback, cp);
More information about the Midnightbsd-cvs
mailing list