xref: /freebsd/sys/geom/geom_dev.c (revision 65c87a6c81f52a8328d81ba9ede5662d9df23a0c)
1dd84a43cSPoul-Henning Kamp /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
33728855aSPedro F. Giffuni  *
4dd84a43cSPoul-Henning Kamp  * Copyright (c) 2002 Poul-Henning Kamp
5dd84a43cSPoul-Henning Kamp  * Copyright (c) 2002 Networks Associates Technology, Inc.
6dd84a43cSPoul-Henning Kamp  * All rights reserved.
7dd84a43cSPoul-Henning Kamp  *
8dd84a43cSPoul-Henning Kamp  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
9dd84a43cSPoul-Henning Kamp  * and NAI Labs, the Security Research Division of Network Associates, Inc.
10dd84a43cSPoul-Henning Kamp  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
11dd84a43cSPoul-Henning Kamp  * DARPA CHATS research program.
12dd84a43cSPoul-Henning Kamp  *
13dd84a43cSPoul-Henning Kamp  * Redistribution and use in source and binary forms, with or without
14dd84a43cSPoul-Henning Kamp  * modification, are permitted provided that the following conditions
15dd84a43cSPoul-Henning Kamp  * are met:
16dd84a43cSPoul-Henning Kamp  * 1. Redistributions of source code must retain the above copyright
17dd84a43cSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer.
18dd84a43cSPoul-Henning Kamp  * 2. Redistributions in binary form must reproduce the above copyright
19dd84a43cSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer in the
20dd84a43cSPoul-Henning Kamp  *    documentation and/or other materials provided with the distribution.
21dd84a43cSPoul-Henning Kamp  * 3. The names of the authors may not be used to endorse or promote
22dd84a43cSPoul-Henning Kamp  *    products derived from this software without specific prior written
23dd84a43cSPoul-Henning Kamp  *    permission.
24dd84a43cSPoul-Henning Kamp  *
25dd84a43cSPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26dd84a43cSPoul-Henning Kamp  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27dd84a43cSPoul-Henning Kamp  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28dd84a43cSPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29dd84a43cSPoul-Henning Kamp  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30dd84a43cSPoul-Henning Kamp  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31dd84a43cSPoul-Henning Kamp  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32dd84a43cSPoul-Henning Kamp  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33dd84a43cSPoul-Henning Kamp  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34dd84a43cSPoul-Henning Kamp  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35dd84a43cSPoul-Henning Kamp  * SUCH DAMAGE.
36dd84a43cSPoul-Henning Kamp  */
37dd84a43cSPoul-Henning Kamp 
3850b1faefSDavid E. O'Brien #include <sys/cdefs.h>
3950b1faefSDavid E. O'Brien __FBSDID("$FreeBSD$");
4050b1faefSDavid E. O'Brien 
41dd84a43cSPoul-Henning Kamp #include <sys/param.h>
42dd84a43cSPoul-Henning Kamp #include <sys/systm.h>
43dd84a43cSPoul-Henning Kamp #include <sys/malloc.h>
44dd84a43cSPoul-Henning Kamp #include <sys/kernel.h>
45dd84a43cSPoul-Henning Kamp #include <sys/conf.h>
46416494d7SJustin T. Gibbs #include <sys/ctype.h>
47dd84a43cSPoul-Henning Kamp #include <sys/bio.h>
48773e541eSWarner Losh #include <sys/devctl.h>
49dd84a43cSPoul-Henning Kamp #include <sys/lock.h>
50dd84a43cSPoul-Henning Kamp #include <sys/mutex.h>
51fc6c63b4SPoul-Henning Kamp #include <sys/proc.h>
52dd84a43cSPoul-Henning Kamp #include <sys/errno.h>
53dd84a43cSPoul-Henning Kamp #include <sys/time.h>
54dd84a43cSPoul-Henning Kamp #include <sys/disk.h>
55dd84a43cSPoul-Henning Kamp #include <sys/fcntl.h>
56104a9b7eSAlexander Kabaev #include <sys/limits.h>
57a50e92ccSRobert Wing #include <sys/selinfo.h>
586f926c0bSSteven Hartland #include <sys/sysctl.h>
59dd84a43cSPoul-Henning Kamp #include <geom/geom.h>
6053705e35SPoul-Henning Kamp #include <geom/geom_int.h>
61416494d7SJustin T. Gibbs #include <machine/stdarg.h>
62416494d7SJustin T. Gibbs 
633c330affSAlexander Motin struct g_dev_softc {
643c330affSAlexander Motin 	struct mtx	 sc_mtx;
653c330affSAlexander Motin 	struct cdev	*sc_dev;
663c330affSAlexander Motin 	struct cdev	*sc_alias;
673c330affSAlexander Motin 	int		 sc_open;
6802a99230SAlexander Motin 	u_int		 sc_active;
69a50e92ccSRobert Wing 	struct selinfo	 sc_selinfo;
7002a99230SAlexander Motin #define	SC_A_DESTROY	(1 << 31)
7102a99230SAlexander Motin #define	SC_A_OPEN	(1 << 30)
7202a99230SAlexander Motin #define	SC_A_ACTIVE	(SC_A_OPEN - 1)
733c330affSAlexander Motin };
74dd84a43cSPoul-Henning Kamp 
75dd84a43cSPoul-Henning Kamp static d_open_t		g_dev_open;
76dd84a43cSPoul-Henning Kamp static d_close_t	g_dev_close;
77dd84a43cSPoul-Henning Kamp static d_strategy_t	g_dev_strategy;
78dd84a43cSPoul-Henning Kamp static d_ioctl_t	g_dev_ioctl;
79a50e92ccSRobert Wing static d_kqfilter_t	g_dev_kqfilter;
80a50e92ccSRobert Wing 
81a50e92ccSRobert Wing static void		gdev_filter_detach(struct knote *kn);
82a50e92ccSRobert Wing static int		gdev_filter_vnode(struct knote *kn, long hint);
83a50e92ccSRobert Wing 
84a50e92ccSRobert Wing static struct filterops gdev_filterops_vnode = {
85a50e92ccSRobert Wing 	.f_isfd = 1,
86a50e92ccSRobert Wing 	.f_detach = gdev_filter_detach,
87a50e92ccSRobert Wing 	.f_event = gdev_filter_vnode,
88a50e92ccSRobert Wing };
89dd84a43cSPoul-Henning Kamp 
90dd84a43cSPoul-Henning Kamp static struct cdevsw g_dev_cdevsw = {
91dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
927ac40f5fSPoul-Henning Kamp 	.d_open =	g_dev_open,
937ac40f5fSPoul-Henning Kamp 	.d_close =	g_dev_close,
947ac40f5fSPoul-Henning Kamp 	.d_read =	physread,
957ac40f5fSPoul-Henning Kamp 	.d_write =	physwrite,
967ac40f5fSPoul-Henning Kamp 	.d_ioctl =	g_dev_ioctl,
977ac40f5fSPoul-Henning Kamp 	.d_strategy =	g_dev_strategy,
987ac40f5fSPoul-Henning Kamp 	.d_name =	"g_dev",
99ce625ec7SKenneth D. Merry 	.d_flags =	D_DISK | D_TRACKCLOSE,
100a50e92ccSRobert Wing 	.d_kqfilter =	g_dev_kqfilter,
101dd84a43cSPoul-Henning Kamp };
102dd84a43cSPoul-Henning Kamp 
1030478dc0cSAndrey V. Elsukov static g_init_t g_dev_init;
1040478dc0cSAndrey V. Elsukov static g_fini_t g_dev_fini;
105dd84a43cSPoul-Henning Kamp static g_taste_t g_dev_taste;
106dd84a43cSPoul-Henning Kamp static g_orphan_t g_dev_orphan;
107416494d7SJustin T. Gibbs static g_attrchanged_t g_dev_attrchanged;
108e6b0d5ebSPawel Jakub Dawidek static g_resize_t g_dev_resize;
109dd84a43cSPoul-Henning Kamp 
110e805e8f0SPoul-Henning Kamp static struct g_class g_dev_class	= {
111c138fec0SPoul-Henning Kamp 	.name = "DEV",
1125721c9c7SPoul-Henning Kamp 	.version = G_VERSION,
1130478dc0cSAndrey V. Elsukov 	.init = g_dev_init,
1140478dc0cSAndrey V. Elsukov 	.fini = g_dev_fini,
115c138fec0SPoul-Henning Kamp 	.taste = g_dev_taste,
116650ee351SPoul-Henning Kamp 	.orphan = g_dev_orphan,
117e6b0d5ebSPawel Jakub Dawidek 	.attrchanged = g_dev_attrchanged,
118e6b0d5ebSPawel Jakub Dawidek 	.resize = g_dev_resize
119dd84a43cSPoul-Henning Kamp };
120dd84a43cSPoul-Henning Kamp 
1216f926c0bSSteven Hartland /*
1226f926c0bSSteven Hartland  * We target 262144 (8 x 32768) sectors by default as this significantly
1236f926c0bSSteven Hartland  * increases the throughput on commonly used SSD's with a marginal
1246f926c0bSSteven Hartland  * increase in non-interruptible request latency.
1256f926c0bSSteven Hartland  */
1266f926c0bSSteven Hartland static uint64_t g_dev_del_max_sectors = 262144;
1276f926c0bSSteven Hartland SYSCTL_DECL(_kern_geom);
1287029da5cSPawel Biernacki SYSCTL_NODE(_kern_geom, OID_AUTO, dev, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1297029da5cSPawel Biernacki     "GEOM_DEV stuff");
1306f926c0bSSteven Hartland SYSCTL_QUAD(_kern_geom_dev, OID_AUTO, delete_max_sectors, CTLFLAG_RW,
1316f926c0bSSteven Hartland     &g_dev_del_max_sectors, 0, "Maximum number of sectors in a single "
1326f926c0bSSteven Hartland     "delete request sent to the provider. Larger requests are chunked "
1336f926c0bSSteven Hartland     "so they can be interrupted. (0 = disable chunking)");
1346f926c0bSSteven Hartland 
1350478dc0cSAndrey V. Elsukov static char *dumpdev = NULL;
1360478dc0cSAndrey V. Elsukov static void
1370478dc0cSAndrey V. Elsukov g_dev_init(struct g_class *mp)
1380478dc0cSAndrey V. Elsukov {
1390478dc0cSAndrey V. Elsukov 
1402be111bfSDavide Italiano 	dumpdev = kern_getenv("dumpdev");
1410478dc0cSAndrey V. Elsukov }
1420478dc0cSAndrey V. Elsukov 
1430478dc0cSAndrey V. Elsukov static void
1440478dc0cSAndrey V. Elsukov g_dev_fini(struct g_class *mp)
1450478dc0cSAndrey V. Elsukov {
1460478dc0cSAndrey V. Elsukov 
1470478dc0cSAndrey V. Elsukov 	freeenv(dumpdev);
148b4d72907SConrad Meyer 	dumpdev = NULL;
1490478dc0cSAndrey V. Elsukov }
1500478dc0cSAndrey V. Elsukov 
1510478dc0cSAndrey V. Elsukov static int
1526b6e2954SConrad Meyer g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda)
1530478dc0cSAndrey V. Elsukov {
1540478dc0cSAndrey V. Elsukov 	struct g_kerneldump kd;
1550478dc0cSAndrey V. Elsukov 	struct g_consumer *cp;
1560478dc0cSAndrey V. Elsukov 	int error, len;
1570478dc0cSAndrey V. Elsukov 
1586b6e2954SConrad Meyer 	MPASS(dev != NULL && kda != NULL);
1596b6e2954SConrad Meyer 	MPASS(kda->kda_index != KDA_REMOVE);
1600478dc0cSAndrey V. Elsukov 
1610478dc0cSAndrey V. Elsukov 	cp = dev->si_drv2;
1620478dc0cSAndrey V. Elsukov 	len = sizeof(kd);
163bd92e6b6SMark Johnston 	memset(&kd, 0, len);
1640478dc0cSAndrey V. Elsukov 	kd.offset = 0;
1650478dc0cSAndrey V. Elsukov 	kd.length = OFF_MAX;
1660478dc0cSAndrey V. Elsukov 	error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
167480f31c2SKonrad Witaszczyk 	if (error != 0)
168480f31c2SKonrad Witaszczyk 		return (error);
169480f31c2SKonrad Witaszczyk 
1706b6e2954SConrad Meyer 	error = dumper_insert(&kd.di, devtoname(dev), kda);
1710478dc0cSAndrey V. Elsukov 	if (error == 0)
1720478dc0cSAndrey V. Elsukov 		dev->si_flags |= SI_DUMPDEV;
173480f31c2SKonrad Witaszczyk 
1740478dc0cSAndrey V. Elsukov 	return (error);
1750478dc0cSAndrey V. Elsukov }
1760478dc0cSAndrey V. Elsukov 
17786787e8dSSteven Hartland static int
1780478dc0cSAndrey V. Elsukov init_dumpdev(struct cdev *dev)
1790478dc0cSAndrey V. Elsukov {
180480f31c2SKonrad Witaszczyk 	struct diocskerneldump_arg kda;
18186787e8dSSteven Hartland 	struct g_consumer *cp;
1828510f61aSXin LI 	const char *devprefix = _PATH_DEV, *devname;
18386787e8dSSteven Hartland 	int error;
184b4d72907SConrad Meyer 	size_t len;
1850478dc0cSAndrey V. Elsukov 
186480f31c2SKonrad Witaszczyk 	bzero(&kda, sizeof(kda));
1876b6e2954SConrad Meyer 	kda.kda_index = KDA_APPEND;
188480f31c2SKonrad Witaszczyk 
1890478dc0cSAndrey V. Elsukov 	if (dumpdev == NULL)
19086787e8dSSteven Hartland 		return (0);
19186787e8dSSteven Hartland 
192b4d72907SConrad Meyer 	len = strlen(devprefix);
193b4d72907SConrad Meyer 	devname = devtoname(dev);
194b4d72907SConrad Meyer 	if (strcmp(devname, dumpdev) != 0 &&
195b4d72907SConrad Meyer 	   (strncmp(dumpdev, devprefix, len) != 0 ||
196b4d72907SConrad Meyer 	    strcmp(devname, dumpdev + len) != 0))
19786787e8dSSteven Hartland 		return (0);
19886787e8dSSteven Hartland 
19986787e8dSSteven Hartland 	cp = (struct g_consumer *)dev->si_drv2;
20086787e8dSSteven Hartland 	error = g_access(cp, 1, 0, 0);
20186787e8dSSteven Hartland 	if (error != 0)
20286787e8dSSteven Hartland 		return (error);
20386787e8dSSteven Hartland 
2046b6e2954SConrad Meyer 	error = g_dev_setdumpdev(dev, &kda);
20586787e8dSSteven Hartland 	if (error == 0) {
2060478dc0cSAndrey V. Elsukov 		freeenv(dumpdev);
2070478dc0cSAndrey V. Elsukov 		dumpdev = NULL;
2080478dc0cSAndrey V. Elsukov 	}
20986787e8dSSteven Hartland 
21086787e8dSSteven Hartland 	(void)g_access(cp, -1, 0, 0);
21186787e8dSSteven Hartland 
21286787e8dSSteven Hartland 	return (error);
2130478dc0cSAndrey V. Elsukov }
2140478dc0cSAndrey V. Elsukov 
2153c330affSAlexander Motin static void
2163c330affSAlexander Motin g_dev_destroy(void *arg, int flags __unused)
2173c330affSAlexander Motin {
2183c330affSAlexander Motin 	struct g_consumer *cp;
2193c330affSAlexander Motin 	struct g_geom *gp;
2203c330affSAlexander Motin 	struct g_dev_softc *sc;
22101de1a06SEdward Tomasz Napierala 	char buf[SPECNAMELEN + 6];
2223c330affSAlexander Motin 
2233c330affSAlexander Motin 	g_topology_assert();
2243c330affSAlexander Motin 	cp = arg;
2253c330affSAlexander Motin 	gp = cp->geom;
2263c330affSAlexander Motin 	sc = cp->private;
2273c330affSAlexander Motin 	g_trace(G_T_TOPOLOGY, "g_dev_destroy(%p(%s))", cp, gp->name);
22801de1a06SEdward Tomasz Napierala 	snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
229887611b1SWarner Losh 	devctl_notify("GEOM", "DEV", "DESTROY", buf);
230a50e92ccSRobert Wing 	knlist_clear(&sc->sc_selinfo.si_note, 0);
231a50e92ccSRobert Wing 	knlist_destroy(&sc->sc_selinfo.si_note);
2323c330affSAlexander Motin 	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
2333c330affSAlexander Motin 		g_access(cp, -cp->acr, -cp->acw, -cp->ace);
2343c330affSAlexander Motin 	g_detach(cp);
2353c330affSAlexander Motin 	g_destroy_consumer(cp);
2363c330affSAlexander Motin 	g_destroy_geom(gp);
2373c330affSAlexander Motin 	mtx_destroy(&sc->sc_mtx);
2383c330affSAlexander Motin 	g_free(sc);
2393c330affSAlexander Motin }
2403c330affSAlexander Motin 
24184c080a8SPoul-Henning Kamp void
242ce225127SPoul-Henning Kamp g_dev_print(void)
243ce225127SPoul-Henning Kamp {
244ce225127SPoul-Henning Kamp 	struct g_geom *gp;
24584c080a8SPoul-Henning Kamp 	char const *p = "";
246ce225127SPoul-Henning Kamp 
24784c080a8SPoul-Henning Kamp 	LIST_FOREACH(gp, &g_dev_class.geom, geom) {
24884c080a8SPoul-Henning Kamp 		printf("%s%s", p, gp->name);
24984c080a8SPoul-Henning Kamp 		p = " ";
25084c080a8SPoul-Henning Kamp 	}
251ce225127SPoul-Henning Kamp 	printf("\n");
252ce225127SPoul-Henning Kamp }
253ce225127SPoul-Henning Kamp 
254416494d7SJustin T. Gibbs static void
255151746b2SAlan Somers g_dev_set_physpath(struct g_consumer *cp)
256151746b2SAlan Somers {
257151746b2SAlan Somers 	struct g_dev_softc *sc;
258151746b2SAlan Somers 	char *physpath;
259151746b2SAlan Somers 	int error, physpath_len;
260151746b2SAlan Somers 
261151746b2SAlan Somers 	if (g_access(cp, 1, 0, 0) != 0)
262151746b2SAlan Somers 		return;
263151746b2SAlan Somers 
264151746b2SAlan Somers 	sc = cp->private;
265151746b2SAlan Somers 	physpath_len = MAXPATHLEN;
266151746b2SAlan Somers 	physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
267151746b2SAlan Somers 	error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
268151746b2SAlan Somers 	g_access(cp, -1, 0, 0);
269151746b2SAlan Somers 	if (error == 0 && strlen(physpath) != 0) {
270151746b2SAlan Somers 		struct cdev *dev, *old_alias_dev;
271151746b2SAlan Somers 		struct cdev **alias_devp;
272151746b2SAlan Somers 
273151746b2SAlan Somers 		dev = sc->sc_dev;
274151746b2SAlan Somers 		old_alias_dev = sc->sc_alias;
275151746b2SAlan Somers 		alias_devp = (struct cdev **)&sc->sc_alias;
276151746b2SAlan Somers 		make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp, dev,
277151746b2SAlan Somers 		    old_alias_dev, physpath);
278151746b2SAlan Somers 	} else if (sc->sc_alias) {
279151746b2SAlan Somers 		destroy_dev((struct cdev *)sc->sc_alias);
280151746b2SAlan Somers 		sc->sc_alias = NULL;
281151746b2SAlan Somers 	}
282151746b2SAlan Somers 	g_free(physpath);
283151746b2SAlan Somers }
284151746b2SAlan Somers 
285151746b2SAlan Somers static void
286151746b2SAlan Somers g_dev_set_media(struct g_consumer *cp)
287416494d7SJustin T. Gibbs {
2883c330affSAlexander Motin 	struct g_dev_softc *sc;
2893631c638SAlexander Motin 	struct cdev *dev;
2903631c638SAlexander Motin 	char buf[SPECNAMELEN + 6];
2913631c638SAlexander Motin 
2923c330affSAlexander Motin 	sc = cp->private;
2933c330affSAlexander Motin 	dev = sc->sc_dev;
2943631c638SAlexander Motin 	snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
295887611b1SWarner Losh 	devctl_notify("DEVFS", "CDEV", "MEDIACHANGE", buf);
296887611b1SWarner Losh 	devctl_notify("GEOM", "DEV", "MEDIACHANGE", buf);
2973c330affSAlexander Motin 	dev = sc->sc_alias;
2983631c638SAlexander Motin 	if (dev != NULL) {
2993631c638SAlexander Motin 		snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
300887611b1SWarner Losh 		devctl_notify("DEVFS", "CDEV", "MEDIACHANGE", buf);
301887611b1SWarner Losh 		devctl_notify("GEOM", "DEV", "MEDIACHANGE", buf);
3023631c638SAlexander Motin 	}
303151746b2SAlan Somers }
304151746b2SAlan Somers 
305151746b2SAlan Somers static void
306151746b2SAlan Somers g_dev_attrchanged(struct g_consumer *cp, const char *attr)
307151746b2SAlan Somers {
308151746b2SAlan Somers 
309151746b2SAlan Somers 	if (strcmp(attr, "GEOM::media") == 0) {
310151746b2SAlan Somers 		g_dev_set_media(cp);
3113631c638SAlexander Motin 		return;
3123631c638SAlexander Motin 	}
313416494d7SJustin T. Gibbs 
314151746b2SAlan Somers 	if (strcmp(attr, "GEOM::physpath") == 0) {
315151746b2SAlan Somers 		g_dev_set_physpath(cp);
316416494d7SJustin T. Gibbs 		return;
317416494d7SJustin T. Gibbs 	}
318416494d7SJustin T. Gibbs }
319416494d7SJustin T. Gibbs 
320e6b0d5ebSPawel Jakub Dawidek static void
321e6b0d5ebSPawel Jakub Dawidek g_dev_resize(struct g_consumer *cp)
322e6b0d5ebSPawel Jakub Dawidek {
323a50e92ccSRobert Wing 	struct g_dev_softc *sc;
324e6b0d5ebSPawel Jakub Dawidek 	char buf[SPECNAMELEN + 6];
325e6b0d5ebSPawel Jakub Dawidek 
326a50e92ccSRobert Wing 	sc = cp->private;
327a50e92ccSRobert Wing 	KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_ATTRIB);
328a50e92ccSRobert Wing 
329e6b0d5ebSPawel Jakub Dawidek 	snprintf(buf, sizeof(buf), "cdev=%s", cp->provider->name);
330887611b1SWarner Losh 	devctl_notify("GEOM", "DEV", "SIZECHANGE", buf);
331e6b0d5ebSPawel Jakub Dawidek }
332e6b0d5ebSPawel Jakub Dawidek 
333bff1e299SPoul-Henning Kamp struct g_provider *
33489c9c53dSPoul-Henning Kamp g_dev_getprovider(struct cdev *dev)
335bff1e299SPoul-Henning Kamp {
336bff1e299SPoul-Henning Kamp 	struct g_consumer *cp;
337bff1e299SPoul-Henning Kamp 
338a7830346SPoul-Henning Kamp 	g_topology_assert();
339bff1e299SPoul-Henning Kamp 	if (dev == NULL)
340bff1e299SPoul-Henning Kamp 		return (NULL);
341a7830346SPoul-Henning Kamp 	if (dev->si_devsw != &g_dev_cdevsw)
342b3b21113SPoul-Henning Kamp 		return (NULL);
343bff1e299SPoul-Henning Kamp 	cp = dev->si_drv2;
344bff1e299SPoul-Henning Kamp 	return (cp->provider);
345bff1e299SPoul-Henning Kamp }
346bff1e299SPoul-Henning Kamp 
347dd84a43cSPoul-Henning Kamp static struct g_geom *
348b1876192SPoul-Henning Kamp g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
349dd84a43cSPoul-Henning Kamp {
350dd84a43cSPoul-Henning Kamp 	struct g_geom *gp;
351c624eb25SWarner Losh 	struct g_geom_alias *gap;
352dd84a43cSPoul-Henning Kamp 	struct g_consumer *cp;
3533c330affSAlexander Motin 	struct g_dev_softc *sc;
3544a3760baSAlexander Motin 	int error;
355c624eb25SWarner Losh 	struct cdev *dev, *adev;
3564a3760baSAlexander Motin 	char buf[SPECNAMELEN + 6];
357e61ed798SAlexander Motin 	struct make_dev_args args;
358dd84a43cSPoul-Henning Kamp 
359dd84a43cSPoul-Henning Kamp 	g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
360dd84a43cSPoul-Henning Kamp 	g_topology_assert();
36102c62349SJaakko Heinonen 	gp = g_new_geomf(mp, "%s", pp->name);
3623c330affSAlexander Motin 	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
3633c330affSAlexander Motin 	mtx_init(&sc->sc_mtx, "g_dev", NULL, MTX_DEF);
364dd84a43cSPoul-Henning Kamp 	cp = g_new_consumer(gp);
3653c330affSAlexander Motin 	cp->private = sc;
36640ea77a0SAlexander Motin 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
3674b8374a7SPoul-Henning Kamp 	error = g_attach(cp, pp);
3683001e97dSEdward Tomasz Napierala 	if (error != 0) {
3693001e97dSEdward Tomasz Napierala 		printf("%s: g_dev_taste(%s) failed to g_attach, error=%d\n",
3703001e97dSEdward Tomasz Napierala 		    __func__, pp->name, error);
3713001e97dSEdward Tomasz Napierala 		g_destroy_consumer(cp);
3723001e97dSEdward Tomasz Napierala 		g_destroy_geom(gp);
3733001e97dSEdward Tomasz Napierala 		mtx_destroy(&sc->sc_mtx);
3743001e97dSEdward Tomasz Napierala 		g_free(sc);
3753001e97dSEdward Tomasz Napierala 		return (NULL);
3763001e97dSEdward Tomasz Napierala 	}
377e61ed798SAlexander Motin 	make_dev_args_init(&args);
378e61ed798SAlexander Motin 	args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
379e61ed798SAlexander Motin 	args.mda_devsw = &g_dev_cdevsw;
380e61ed798SAlexander Motin 	args.mda_cr = NULL;
381e61ed798SAlexander Motin 	args.mda_uid = UID_ROOT;
382e61ed798SAlexander Motin 	args.mda_gid = GID_OPERATOR;
383e61ed798SAlexander Motin 	args.mda_mode = 0640;
384e61ed798SAlexander Motin 	args.mda_si_drv1 = sc;
385e61ed798SAlexander Motin 	args.mda_si_drv2 = cp;
386e61ed798SAlexander Motin 	error = make_dev_s(&args, &sc->sc_dev, "%s", gp->name);
387bc2589f5SJaakko Heinonen 	if (error != 0) {
388bc2589f5SJaakko Heinonen 		printf("%s: make_dev_p() failed (gp->name=%s, error=%d)\n",
389bc2589f5SJaakko Heinonen 		    __func__, gp->name, error);
390bc2589f5SJaakko Heinonen 		g_detach(cp);
391bc2589f5SJaakko Heinonen 		g_destroy_consumer(cp);
392bc2589f5SJaakko Heinonen 		g_destroy_geom(gp);
3933c330affSAlexander Motin 		mtx_destroy(&sc->sc_mtx);
3943c330affSAlexander Motin 		g_free(sc);
395bc2589f5SJaakko Heinonen 		return (NULL);
396bc2589f5SJaakko Heinonen 	}
397e61ed798SAlexander Motin 	dev = sc->sc_dev;
398ce625ec7SKenneth D. Merry 	dev->si_flags |= SI_UNMAPPED;
399cd853791SKonstantin Belousov 	dev->si_iosize_max = maxphys;
400a50e92ccSRobert Wing 	knlist_init_mtx(&sc->sc_selinfo.si_note, &sc->sc_mtx);
40186787e8dSSteven Hartland 	error = init_dumpdev(dev);
40286787e8dSSteven Hartland 	if (error != 0)
40386787e8dSSteven Hartland 		printf("%s: init_dumpdev() failed (gp->name=%s, error=%d)\n",
40486787e8dSSteven Hartland 		    __func__, gp->name, error);
405416494d7SJustin T. Gibbs 
406416494d7SJustin T. Gibbs 	g_dev_attrchanged(cp, "GEOM::physpath");
40701de1a06SEdward Tomasz Napierala 	snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
408887611b1SWarner Losh 	devctl_notify("GEOM", "DEV", "CREATE", buf);
409c624eb25SWarner Losh 	/*
410c624eb25SWarner Losh 	 * Now add all the aliases for this drive
411c624eb25SWarner Losh 	 */
412ae1cce52SWarner Losh 	LIST_FOREACH(gap, &pp->aliases, ga_next) {
413c624eb25SWarner Losh 		error = make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &adev, dev,
414c624eb25SWarner Losh 		    "%s", gap->ga_alias);
415c624eb25SWarner Losh 		if (error) {
416a9ca503bSConrad Meyer 			printf("%s: make_dev_alias_p() failed (name=%s, error=%d)\n",
417a9ca503bSConrad Meyer 			    __func__, gap->ga_alias, error);
418c624eb25SWarner Losh 			continue;
419c624eb25SWarner Losh 		}
420c624eb25SWarner Losh 		snprintf(buf, sizeof(buf), "cdev=%s", gap->ga_alias);
421887611b1SWarner Losh 		devctl_notify("GEOM", "DEV", "CREATE", buf);
422c624eb25SWarner Losh 	}
423416494d7SJustin T. Gibbs 
424dd84a43cSPoul-Henning Kamp 	return (gp);
425dd84a43cSPoul-Henning Kamp }
426dd84a43cSPoul-Henning Kamp 
427dd84a43cSPoul-Henning Kamp static int
42889c9c53dSPoul-Henning Kamp g_dev_open(struct cdev *dev, int flags, int fmt, struct thread *td)
429dd84a43cSPoul-Henning Kamp {
430dd84a43cSPoul-Henning Kamp 	struct g_consumer *cp;
4313c330affSAlexander Motin 	struct g_dev_softc *sc;
432dd84a43cSPoul-Henning Kamp 	int error, r, w, e;
433dd84a43cSPoul-Henning Kamp 
434dd84a43cSPoul-Henning Kamp 	cp = dev->si_drv2;
435dd84a43cSPoul-Henning Kamp 	g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
4363c330affSAlexander Motin 	    cp->geom->name, flags, fmt, td);
437fc6c63b4SPoul-Henning Kamp 
438dd84a43cSPoul-Henning Kamp 	r = flags & FREAD ? 1 : 0;
439dd84a43cSPoul-Henning Kamp 	w = flags & FWRITE ? 1 : 0;
44002945fefSPoul-Henning Kamp #ifdef notyet
441dd84a43cSPoul-Henning Kamp 	e = flags & O_EXCL ? 1 : 0;
44202945fefSPoul-Henning Kamp #else
44302945fefSPoul-Henning Kamp 	e = 0;
44402945fefSPoul-Henning Kamp #endif
44572800098SEdward Tomasz Napierala 
44672800098SEdward Tomasz Napierala 	/*
44772800098SEdward Tomasz Napierala 	 * This happens on attempt to open a device node with O_EXEC.
44872800098SEdward Tomasz Napierala 	 */
44972800098SEdward Tomasz Napierala 	if (r + w + e == 0)
45072800098SEdward Tomasz Napierala 		return (EINVAL);
45172800098SEdward Tomasz Napierala 
452fc6c63b4SPoul-Henning Kamp 	if (w) {
453fc6c63b4SPoul-Henning Kamp 		/*
454fc6c63b4SPoul-Henning Kamp 		 * When running in very secure mode, do not allow
455fc6c63b4SPoul-Henning Kamp 		 * opens for writing of any disks.
456fc6c63b4SPoul-Henning Kamp 		 */
457fc6c63b4SPoul-Henning Kamp 		error = securelevel_ge(td->td_ucred, 2);
458fc6c63b4SPoul-Henning Kamp 		if (error)
459fc6c63b4SPoul-Henning Kamp 			return (error);
460fc6c63b4SPoul-Henning Kamp 	}
461c7e1925cSPoul-Henning Kamp 	g_topology_lock();
462d2bae332SPoul-Henning Kamp 	error = g_access(cp, r, w, e);
463dd84a43cSPoul-Henning Kamp 	g_topology_unlock();
4643c330affSAlexander Motin 	if (error == 0) {
465e61ed798SAlexander Motin 		sc = dev->si_drv1;
4663c330affSAlexander Motin 		mtx_lock(&sc->sc_mtx);
46702a99230SAlexander Motin 		if (sc->sc_open == 0 && (sc->sc_active & SC_A_ACTIVE) != 0)
4683c330affSAlexander Motin 			wakeup(&sc->sc_active);
4693c330affSAlexander Motin 		sc->sc_open += r + w + e;
47002a99230SAlexander Motin 		if (sc->sc_open == 0)
47102a99230SAlexander Motin 			atomic_clear_int(&sc->sc_active, SC_A_OPEN);
47202a99230SAlexander Motin 		else
47302a99230SAlexander Motin 			atomic_set_int(&sc->sc_active, SC_A_OPEN);
474*65c87a6cSRobert Wing 		KNOTE_LOCKED(&sc->sc_selinfo.si_note, NOTE_OPEN);
4753c330affSAlexander Motin 		mtx_unlock(&sc->sc_mtx);
4763c330affSAlexander Motin 	}
477dd84a43cSPoul-Henning Kamp 	return (error);
478dd84a43cSPoul-Henning Kamp }
479dd84a43cSPoul-Henning Kamp 
480dd84a43cSPoul-Henning Kamp static int
48189c9c53dSPoul-Henning Kamp g_dev_close(struct cdev *dev, int flags, int fmt, struct thread *td)
482dd84a43cSPoul-Henning Kamp {
483dd84a43cSPoul-Henning Kamp 	struct g_consumer *cp;
4843c330affSAlexander Motin 	struct g_dev_softc *sc;
4853c330affSAlexander Motin 	int error, r, w, e;
486dd84a43cSPoul-Henning Kamp 
487dd84a43cSPoul-Henning Kamp 	cp = dev->si_drv2;
488dd84a43cSPoul-Henning Kamp 	g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
4893c330affSAlexander Motin 	    cp->geom->name, flags, fmt, td);
4903c330affSAlexander Motin 
491dd84a43cSPoul-Henning Kamp 	r = flags & FREAD ? -1 : 0;
492dd84a43cSPoul-Henning Kamp 	w = flags & FWRITE ? -1 : 0;
49302945fefSPoul-Henning Kamp #ifdef notyet
494dd84a43cSPoul-Henning Kamp 	e = flags & O_EXCL ? -1 : 0;
49502945fefSPoul-Henning Kamp #else
49602945fefSPoul-Henning Kamp 	e = 0;
49702945fefSPoul-Henning Kamp #endif
498d6cc35b2SEdward Tomasz Napierala 
499d6cc35b2SEdward Tomasz Napierala 	/*
500d6cc35b2SEdward Tomasz Napierala 	 * The vgonel(9) - caused by eg. forced unmount of devfs - calls
501d6cc35b2SEdward Tomasz Napierala 	 * VOP_CLOSE(9) on devfs vnode without any FREAD or FWRITE flags,
502d6cc35b2SEdward Tomasz Napierala 	 * which would result in zero deltas, which in turn would cause
503d6cc35b2SEdward Tomasz Napierala 	 * panic in g_access(9).
504d6cc35b2SEdward Tomasz Napierala 	 *
505d6cc35b2SEdward Tomasz Napierala 	 * Note that we cannot zero the counters (ie. do "r = cp->acr"
506d6cc35b2SEdward Tomasz Napierala 	 * etc) instead, because the consumer might be opened in another
507d6cc35b2SEdward Tomasz Napierala 	 * devfs instance.
508d6cc35b2SEdward Tomasz Napierala 	 */
509d6cc35b2SEdward Tomasz Napierala 	if (r + w + e == 0)
510d6cc35b2SEdward Tomasz Napierala 		return (EINVAL);
511d6cc35b2SEdward Tomasz Napierala 
512e61ed798SAlexander Motin 	sc = dev->si_drv1;
5133c330affSAlexander Motin 	mtx_lock(&sc->sc_mtx);
5143c330affSAlexander Motin 	sc->sc_open += r + w + e;
51502a99230SAlexander Motin 	if (sc->sc_open == 0)
51602a99230SAlexander Motin 		atomic_clear_int(&sc->sc_active, SC_A_OPEN);
51702a99230SAlexander Motin 	else
51802a99230SAlexander Motin 		atomic_set_int(&sc->sc_active, SC_A_OPEN);
51902a99230SAlexander Motin 	while (sc->sc_open == 0 && (sc->sc_active & SC_A_ACTIVE) != 0)
52002a99230SAlexander Motin 		msleep(&sc->sc_active, &sc->sc_mtx, 0, "g_dev_close", hz / 10);
521*65c87a6cSRobert Wing 	KNOTE_LOCKED(&sc->sc_selinfo.si_note, NOTE_CLOSE | (w ? NOTE_CLOSE_WRITE : 0));
5223c330affSAlexander Motin 	mtx_unlock(&sc->sc_mtx);
523c7e1925cSPoul-Henning Kamp 	g_topology_lock();
524d2bae332SPoul-Henning Kamp 	error = g_access(cp, r, w, e);
525dd84a43cSPoul-Henning Kamp 	g_topology_unlock();
526dd84a43cSPoul-Henning Kamp 	return (error);
527dd84a43cSPoul-Henning Kamp }
528dd84a43cSPoul-Henning Kamp 
529dd84a43cSPoul-Henning Kamp static int
53089c9c53dSPoul-Henning Kamp g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
531dd84a43cSPoul-Henning Kamp {
532dd84a43cSPoul-Henning Kamp 	struct g_consumer *cp;
533f805f204SUlf Lilleengen 	struct g_provider *pp;
5344d5832bcSAlexander Motin 	off_t offset, length, chunk, odd;
535dd84a43cSPoul-Henning Kamp 	int i, error;
536dd84a43cSPoul-Henning Kamp 
537dd84a43cSPoul-Henning Kamp 	cp = dev->si_drv2;
538f805f204SUlf Lilleengen 	pp = cp->provider;
539dd84a43cSPoul-Henning Kamp 
54019cfcf25SAlexander Motin 	/* If consumer or provider is dying, don't disturb. */
54119cfcf25SAlexander Motin 	if (cp->flags & G_CF_ORPHAN)
54219cfcf25SAlexander Motin 		return (ENXIO);
54319cfcf25SAlexander Motin 	if (pp->error)
54419cfcf25SAlexander Motin 		return (pp->error);
54519cfcf25SAlexander Motin 
546dd84a43cSPoul-Henning Kamp 	error = 0;
547c7e1925cSPoul-Henning Kamp 	KASSERT(cp->acr || cp->acw,
548c7e1925cSPoul-Henning Kamp 	    ("Consumer with zero access count in g_dev_ioctl"));
549a5b2e75dSPoul-Henning Kamp 
55000dcdc8dSPoul-Henning Kamp 	i = IOCPARM_LEN(cmd);
55100dcdc8dSPoul-Henning Kamp 	switch (cmd) {
55200dcdc8dSPoul-Henning Kamp 	case DIOCGSECTORSIZE:
5536b3c68bfSAlexander Motin 		*(u_int *)data = pp->sectorsize;
5543f12caa1SPoul-Henning Kamp 		if (*(u_int *)data == 0)
55502fcfac0SNate Lawson 			error = ENOENT;
55600dcdc8dSPoul-Henning Kamp 		break;
55700dcdc8dSPoul-Henning Kamp 	case DIOCGMEDIASIZE:
5586b3c68bfSAlexander Motin 		*(off_t *)data = pp->mediasize;
5593f12caa1SPoul-Henning Kamp 		if (*(off_t *)data == 0)
56002fcfac0SNate Lawson 			error = ENOENT;
56100dcdc8dSPoul-Henning Kamp 		break;
56200dcdc8dSPoul-Henning Kamp 	case DIOCGFWSECTORS:
563b1876192SPoul-Henning Kamp 		error = g_io_getattr("GEOM::fwsectors", cp, &i, data);
56402fcfac0SNate Lawson 		if (error == 0 && *(u_int *)data == 0)
56502fcfac0SNate Lawson 			error = ENOENT;
56600dcdc8dSPoul-Henning Kamp 		break;
56700dcdc8dSPoul-Henning Kamp 	case DIOCGFWHEADS:
568b1876192SPoul-Henning Kamp 		error = g_io_getattr("GEOM::fwheads", cp, &i, data);
56902fcfac0SNate Lawson 		if (error == 0 && *(u_int *)data == 0)
57002fcfac0SNate Lawson 			error = ENOENT;
57100dcdc8dSPoul-Henning Kamp 		break;
572480f31c2SKonrad Witaszczyk 	case DIOCSKERNELDUMP:
573480f31c2SKonrad Witaszczyk 	    {
574480f31c2SKonrad Witaszczyk 		struct diocskerneldump_arg *kda;
575480f31c2SKonrad Witaszczyk 		uint8_t *encryptedkey;
576480f31c2SKonrad Witaszczyk 
577480f31c2SKonrad Witaszczyk 		kda = (struct diocskerneldump_arg *)data;
5786b6e2954SConrad Meyer 		if (kda->kda_index == KDA_REMOVE_ALL ||
5796b6e2954SConrad Meyer 		    kda->kda_index == KDA_REMOVE_DEV ||
5806b6e2954SConrad Meyer 		    kda->kda_index == KDA_REMOVE) {
5816b6e2954SConrad Meyer 			error = dumper_remove(devtoname(dev), kda);
5826b6e2954SConrad Meyer 			explicit_bzero(kda, sizeof(*kda));
583480f31c2SKonrad Witaszczyk 			break;
584480f31c2SKonrad Witaszczyk 		}
585480f31c2SKonrad Witaszczyk 
586480f31c2SKonrad Witaszczyk 		if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
5876b6e2954SConrad Meyer 			if (kda->kda_encryptedkeysize == 0 ||
588480f31c2SKonrad Witaszczyk 			    kda->kda_encryptedkeysize >
589480f31c2SKonrad Witaszczyk 			    KERNELDUMP_ENCKEY_MAX_SIZE) {
5906b6e2954SConrad Meyer 				explicit_bzero(kda, sizeof(*kda));
591480f31c2SKonrad Witaszczyk 				return (EINVAL);
592480f31c2SKonrad Witaszczyk 			}
593480f31c2SKonrad Witaszczyk 			encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
594480f31c2SKonrad Witaszczyk 			    M_WAITOK);
595480f31c2SKonrad Witaszczyk 			error = copyin(kda->kda_encryptedkey, encryptedkey,
596480f31c2SKonrad Witaszczyk 			    kda->kda_encryptedkeysize);
597480f31c2SKonrad Witaszczyk 		} else {
598480f31c2SKonrad Witaszczyk 			encryptedkey = NULL;
599480f31c2SKonrad Witaszczyk 		}
600480f31c2SKonrad Witaszczyk 		if (error == 0) {
601480f31c2SKonrad Witaszczyk 			kda->kda_encryptedkey = encryptedkey;
6026b6e2954SConrad Meyer 			error = g_dev_setdumpdev(dev, kda);
603480f31c2SKonrad Witaszczyk 		}
6044a711b8dSJohn Baldwin 		zfree(encryptedkey, M_TEMP);
605480f31c2SKonrad Witaszczyk 		explicit_bzero(kda, sizeof(*kda));
606480f31c2SKonrad Witaszczyk 		break;
607480f31c2SKonrad Witaszczyk 	    }
6080589353aSPawel Jakub Dawidek 	case DIOCGFLUSH:
6090589353aSPawel Jakub Dawidek 		error = g_io_flush(cp);
6100589353aSPawel Jakub Dawidek 		break;
6110589353aSPawel Jakub Dawidek 	case DIOCGDELETE:
6120589353aSPawel Jakub Dawidek 		offset = ((off_t *)data)[0];
6130589353aSPawel Jakub Dawidek 		length = ((off_t *)data)[1];
6146b3c68bfSAlexander Motin 		if ((offset % pp->sectorsize) != 0 ||
6156b3c68bfSAlexander Motin 		    (length % pp->sectorsize) != 0 || length <= 0) {
6160589353aSPawel Jakub Dawidek 			printf("%s: offset=%jd length=%jd\n", __func__, offset,
6170589353aSPawel Jakub Dawidek 			    length);
6180589353aSPawel Jakub Dawidek 			error = EINVAL;
6190589353aSPawel Jakub Dawidek 			break;
6200589353aSPawel Jakub Dawidek 		}
621015a11e6SPoul-Henning Kamp 		while (length > 0) {
622015a11e6SPoul-Henning Kamp 			chunk = length;
6236b3c68bfSAlexander Motin 			if (g_dev_del_max_sectors != 0 &&
6246b3c68bfSAlexander Motin 			    chunk > g_dev_del_max_sectors * pp->sectorsize) {
6256b3c68bfSAlexander Motin 				chunk = g_dev_del_max_sectors * pp->sectorsize;
6266b3c68bfSAlexander Motin 				if (pp->stripesize > 0) {
6274d5832bcSAlexander Motin 					odd = (offset + chunk +
6286b3c68bfSAlexander Motin 					    pp->stripeoffset) % pp->stripesize;
6294d5832bcSAlexander Motin 					if (chunk > odd)
6304d5832bcSAlexander Motin 						chunk -= odd;
6314d5832bcSAlexander Motin 				}
6326f926c0bSSteven Hartland 			}
633015a11e6SPoul-Henning Kamp 			error = g_delete_data(cp, offset, chunk);
634015a11e6SPoul-Henning Kamp 			length -= chunk;
635015a11e6SPoul-Henning Kamp 			offset += chunk;
636015a11e6SPoul-Henning Kamp 			if (error)
637015a11e6SPoul-Henning Kamp 				break;
638015a11e6SPoul-Henning Kamp 			/*
6396f926c0bSSteven Hartland 			 * Since the request size can be large, the service
6406f926c0bSSteven Hartland 			 * time can be is likewise.  We make this ioctl
6416f926c0bSSteven Hartland 			 * interruptible by checking for signals for each bio.
642015a11e6SPoul-Henning Kamp 			 */
643015a11e6SPoul-Henning Kamp 			if (SIGPENDING(td))
644015a11e6SPoul-Henning Kamp 				break;
645015a11e6SPoul-Henning Kamp 		}
6460589353aSPawel Jakub Dawidek 		break;
6470589353aSPawel Jakub Dawidek 	case DIOCGIDENT:
6480589353aSPawel Jakub Dawidek 		error = g_io_getattr("GEOM::ident", cp, &i, data);
6490589353aSPawel Jakub Dawidek 		break;
650f805f204SUlf Lilleengen 	case DIOCGPROVIDERNAME:
651f805f204SUlf Lilleengen 		strlcpy(data, pp->name, i);
652f805f204SUlf Lilleengen 		break;
6538b303238SAlexander Motin 	case DIOCGSTRIPESIZE:
6546b3c68bfSAlexander Motin 		*(off_t *)data = pp->stripesize;
6558b303238SAlexander Motin 		break;
6568b303238SAlexander Motin 	case DIOCGSTRIPEOFFSET:
6576b3c68bfSAlexander Motin 		*(off_t *)data = pp->stripeoffset;
6588b303238SAlexander Motin 		break;
659416494d7SJustin T. Gibbs 	case DIOCGPHYSPATH:
660416494d7SJustin T. Gibbs 		error = g_io_getattr("GEOM::physpath", cp, &i, data);
661416494d7SJustin T. Gibbs 		if (error == 0 && *(char *)data == '\0')
662416494d7SJustin T. Gibbs 			error = ENOENT;
663416494d7SJustin T. Gibbs 		break;
664c3e7ba3eSAlexander Motin 	case DIOCGATTR: {
665c3e7ba3eSAlexander Motin 		struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
666c3e7ba3eSAlexander Motin 
667c3e7ba3eSAlexander Motin 		if (arg->len > sizeof(arg->value)) {
668c3e7ba3eSAlexander Motin 			error = EINVAL;
669c3e7ba3eSAlexander Motin 			break;
670c3e7ba3eSAlexander Motin 		}
671c3e7ba3eSAlexander Motin 		error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
672c3e7ba3eSAlexander Motin 		break;
673c3e7ba3eSAlexander Motin 	}
6749a6844d5SKenneth D. Merry 	case DIOCZONECMD: {
6759a6844d5SKenneth D. Merry 		struct disk_zone_args *zone_args =(struct disk_zone_args *)data;
6769a6844d5SKenneth D. Merry 		struct disk_zone_rep_entry *new_entries, *old_entries;
6779a6844d5SKenneth D. Merry 		struct disk_zone_report *rep;
6789a6844d5SKenneth D. Merry 		size_t alloc_size;
6799a6844d5SKenneth D. Merry 
6809a6844d5SKenneth D. Merry 		old_entries = NULL;
6819a6844d5SKenneth D. Merry 		new_entries = NULL;
6829a6844d5SKenneth D. Merry 		rep = NULL;
6839a6844d5SKenneth D. Merry 		alloc_size = 0;
6849a6844d5SKenneth D. Merry 
6859a6844d5SKenneth D. Merry 		if (zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES) {
6869a6844d5SKenneth D. Merry 			rep = &zone_args->zone_params.report;
687cd853791SKonstantin Belousov #define	MAXENTRIES	(maxphys / sizeof(struct disk_zone_rep_entry))
688d4fbe32cSMark Johnston 			if (rep->entries_allocated > MAXENTRIES)
689d4fbe32cSMark Johnston 				rep->entries_allocated = MAXENTRIES;
6909a6844d5SKenneth D. Merry 			alloc_size = rep->entries_allocated *
6919a6844d5SKenneth D. Merry 			    sizeof(struct disk_zone_rep_entry);
6929a6844d5SKenneth D. Merry 			if (alloc_size != 0)
6939a6844d5SKenneth D. Merry 				new_entries = g_malloc(alloc_size,
6949a6844d5SKenneth D. Merry 				    M_WAITOK | M_ZERO);
6959a6844d5SKenneth D. Merry 			old_entries = rep->entries;
6969a6844d5SKenneth D. Merry 			rep->entries = new_entries;
6979a6844d5SKenneth D. Merry 		}
6989a6844d5SKenneth D. Merry 		error = g_io_zonecmd(zone_args, cp);
699d4fbe32cSMark Johnston 		if (zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES &&
700d4fbe32cSMark Johnston 		    alloc_size != 0 && error == 0)
7019a6844d5SKenneth D. Merry 			error = copyout(new_entries, old_entries, alloc_size);
702d4fbe32cSMark Johnston 		if (old_entries != NULL && rep != NULL)
7039a6844d5SKenneth D. Merry 			rep->entries = old_entries;
7049a6844d5SKenneth D. Merry 		if (new_entries != NULL)
7059a6844d5SKenneth D. Merry 			g_free(new_entries);
7069a6844d5SKenneth D. Merry 		break;
7079a6844d5SKenneth D. Merry 	}
70800dcdc8dSPoul-Henning Kamp 	default:
7096b3c68bfSAlexander Motin 		if (pp->geom->ioctl != NULL) {
7106b3c68bfSAlexander Motin 			error = pp->geom->ioctl(pp, cmd, data, fflag, td);
711f03bec94SPoul-Henning Kamp 		} else {
712f03bec94SPoul-Henning Kamp 			error = ENOIOCTL;
713497c3347SPoul-Henning Kamp 		}
71400dcdc8dSPoul-Henning Kamp 	}
715a5b2e75dSPoul-Henning Kamp 
716dd84a43cSPoul-Henning Kamp 	return (error);
717dd84a43cSPoul-Henning Kamp }
718dd84a43cSPoul-Henning Kamp 
719dd84a43cSPoul-Henning Kamp static void
720dd84a43cSPoul-Henning Kamp g_dev_done(struct bio *bp2)
721dd84a43cSPoul-Henning Kamp {
7223c330affSAlexander Motin 	struct g_consumer *cp;
7233c330affSAlexander Motin 	struct g_dev_softc *sc;
724dd84a43cSPoul-Henning Kamp 	struct bio *bp;
72502a99230SAlexander Motin 	int active;
726dd84a43cSPoul-Henning Kamp 
7273c330affSAlexander Motin 	cp = bp2->bio_from;
7283c330affSAlexander Motin 	sc = cp->private;
729936cc461SPoul-Henning Kamp 	bp = bp2->bio_parent;
730dd84a43cSPoul-Henning Kamp 	bp->bio_error = bp2->bio_error;
73121d0712cSAlexander Motin 	bp->bio_completed = bp2->bio_completed;
7322634da8cSAlexander Motin 	bp->bio_resid = bp->bio_length - bp2->bio_completed;
7339a6844d5SKenneth D. Merry 	if (bp2->bio_cmd == BIO_ZONE)
7349a6844d5SKenneth D. Merry 		bcopy(&bp2->bio_zone, &bp->bio_zone, sizeof(bp->bio_zone));
7359a6844d5SKenneth D. Merry 
73621d0712cSAlexander Motin 	if (bp2->bio_error != 0) {
737dd84a43cSPoul-Henning Kamp 		g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
73821d0712cSAlexander Motin 		    bp2, bp2->bio_error);
739dd84a43cSPoul-Henning Kamp 		bp->bio_flags |= BIO_ERROR;
740dd84a43cSPoul-Henning Kamp 	} else {
741*65c87a6cSRobert Wing 		if (bp->bio_cmd == BIO_READ)
742*65c87a6cSRobert Wing 			KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_READ);
743*65c87a6cSRobert Wing 		if (bp->bio_cmd == BIO_WRITE)
744*65c87a6cSRobert Wing 			KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_WRITE);
74514ac6812SPoul-Henning Kamp 		g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
74621d0712cSAlexander Motin 		    bp2, bp, bp2->bio_resid, (intmax_t)bp2->bio_completed);
747dd84a43cSPoul-Henning Kamp 	}
748dd84a43cSPoul-Henning Kamp 	g_destroy_bio(bp2);
74902a99230SAlexander Motin 	active = atomic_fetchadd_int(&sc->sc_active, -1) - 1;
75002a99230SAlexander Motin 	if ((active & SC_A_ACTIVE) == 0) {
75102a99230SAlexander Motin 		if ((active & SC_A_OPEN) == 0)
7523c330affSAlexander Motin 			wakeup(&sc->sc_active);
75302a99230SAlexander Motin 		if (active & SC_A_DESTROY)
7540ada3afcSAlexander Motin 			g_post_event(g_dev_destroy, cp, M_NOWAIT, NULL);
75502a99230SAlexander Motin 	}
756dd84a43cSPoul-Henning Kamp 	biodone(bp);
757dd84a43cSPoul-Henning Kamp }
758dd84a43cSPoul-Henning Kamp 
759dd84a43cSPoul-Henning Kamp static void
760dd84a43cSPoul-Henning Kamp g_dev_strategy(struct bio *bp)
761dd84a43cSPoul-Henning Kamp {
762dd84a43cSPoul-Henning Kamp 	struct g_consumer *cp;
763dd84a43cSPoul-Henning Kamp 	struct bio *bp2;
76489c9c53dSPoul-Henning Kamp 	struct cdev *dev;
7653c330affSAlexander Motin 	struct g_dev_softc *sc;
766dd84a43cSPoul-Henning Kamp 
767b630d83fSPoul-Henning Kamp 	KASSERT(bp->bio_cmd == BIO_READ ||
768b630d83fSPoul-Henning Kamp 	        bp->bio_cmd == BIO_WRITE ||
76916fac6c9SEdward Tomasz Napierala 	        bp->bio_cmd == BIO_DELETE ||
7709a6844d5SKenneth D. Merry 		bp->bio_cmd == BIO_FLUSH ||
7719a6844d5SKenneth D. Merry 		bp->bio_cmd == BIO_ZONE,
772b630d83fSPoul-Henning Kamp 		("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
773dd84a43cSPoul-Henning Kamp 	dev = bp->bio_dev;
774dd84a43cSPoul-Henning Kamp 	cp = dev->si_drv2;
775c7e1925cSPoul-Henning Kamp 	KASSERT(cp->acr || cp->acw,
776c7e1925cSPoul-Henning Kamp 	    ("Consumer with zero access count in g_dev_strategy"));
7778532d381SConrad Meyer 	biotrack(bp, __func__);
77818e42503SAlexander Motin #ifdef INVARIANTS
7796c252337SPawel Jakub Dawidek 	if ((bp->bio_offset % cp->provider->sectorsize) != 0 ||
7806c252337SPawel Jakub Dawidek 	    (bp->bio_bcount % cp->provider->sectorsize) != 0) {
781274ede62SSimon L. B. Nielsen 		bp->bio_resid = bp->bio_bcount;
7826c252337SPawel Jakub Dawidek 		biofinish(bp, NULL, EINVAL);
7836c252337SPawel Jakub Dawidek 		return;
7846c252337SPawel Jakub Dawidek 	}
78518e42503SAlexander Motin #endif
786e61ed798SAlexander Motin 	sc = dev->si_drv1;
7873c330affSAlexander Motin 	KASSERT(sc->sc_open > 0, ("Closed device in g_dev_strategy"));
78802a99230SAlexander Motin 	atomic_add_int(&sc->sc_active, 1);
7893c330affSAlexander Motin 
7904ba5a129SPoul-Henning Kamp 	for (;;) {
7914ba5a129SPoul-Henning Kamp 		/*
792e8d57122SPedro F. Giffuni 		 * XXX: This is not an ideal solution, but I believe it to
793e8d57122SPedro F. Giffuni 		 * XXX: deadlock safely, all things considered.
7944ba5a129SPoul-Henning Kamp 		 */
795dd84a43cSPoul-Henning Kamp 		bp2 = g_clone_bio(bp);
7964ba5a129SPoul-Henning Kamp 		if (bp2 != NULL)
7974ba5a129SPoul-Henning Kamp 			break;
7984d70511aSJohn Baldwin 		pause("gdstrat", hz / 10);
7994ba5a129SPoul-Henning Kamp 	}
800cc0163a3SPoul-Henning Kamp 	KASSERT(bp2 != NULL, ("XXX: ENOMEM in a bad place"));
801dd84a43cSPoul-Henning Kamp 	bp2->bio_done = g_dev_done;
802dd84a43cSPoul-Henning Kamp 	g_trace(G_T_BIO,
80314ac6812SPoul-Henning Kamp 	    "g_dev_strategy(%p/%p) offset %jd length %jd data %p cmd %d",
80414ac6812SPoul-Henning Kamp 	    bp, bp2, (intmax_t)bp->bio_offset, (intmax_t)bp2->bio_length,
80514ac6812SPoul-Henning Kamp 	    bp2->bio_data, bp2->bio_cmd);
806dd84a43cSPoul-Henning Kamp 	g_io_request(bp2, cp);
807c7e1925cSPoul-Henning Kamp 	KASSERT(cp->acr || cp->acw,
808c7e1925cSPoul-Henning Kamp 	    ("g_dev_strategy raced with g_dev_close and lost"));
809c7e1925cSPoul-Henning Kamp 
810dd84a43cSPoul-Henning Kamp }
811dd84a43cSPoul-Henning Kamp 
8124b8374a7SPoul-Henning Kamp /*
8133c330affSAlexander Motin  * g_dev_callback()
8143c330affSAlexander Motin  *
8153c330affSAlexander Motin  * Called by devfs when asynchronous device destruction is completed.
8163c330affSAlexander Motin  * - Mark that we have no attached device any more.
8173c330affSAlexander Motin  * - If there are no outstanding requests, schedule geom destruction.
8183c330affSAlexander Motin  *   Otherwise destruction will be scheduled later by g_dev_done().
8193c330affSAlexander Motin  */
8203c330affSAlexander Motin 
8213c330affSAlexander Motin static void
8223c330affSAlexander Motin g_dev_callback(void *arg)
8233c330affSAlexander Motin {
8243c330affSAlexander Motin 	struct g_consumer *cp;
8253c330affSAlexander Motin 	struct g_dev_softc *sc;
82602a99230SAlexander Motin 	int active;
8273c330affSAlexander Motin 
8283c330affSAlexander Motin 	cp = arg;
8293c330affSAlexander Motin 	sc = cp->private;
8303c330affSAlexander Motin 	g_trace(G_T_TOPOLOGY, "g_dev_callback(%p(%s))", cp, cp->geom->name);
8313c330affSAlexander Motin 
8323c330affSAlexander Motin 	sc->sc_dev = NULL;
8333c330affSAlexander Motin 	sc->sc_alias = NULL;
83402a99230SAlexander Motin 	active = atomic_fetchadd_int(&sc->sc_active, SC_A_DESTROY);
83502a99230SAlexander Motin 	if ((active & SC_A_ACTIVE) == 0)
8363c330affSAlexander Motin 		g_post_event(g_dev_destroy, cp, M_WAITOK, NULL);
8373c330affSAlexander Motin }
8383c330affSAlexander Motin 
8393c330affSAlexander Motin /*
8404b8374a7SPoul-Henning Kamp  * g_dev_orphan()
8414b8374a7SPoul-Henning Kamp  *
842df6c9fe9SPoul-Henning Kamp  * Called from below when the provider orphaned us.
843df6c9fe9SPoul-Henning Kamp  * - Clear any dump settings.
8443c330affSAlexander Motin  * - Request asynchronous device destruction to prevent any more requests
8453c330affSAlexander Motin  *   from coming in.  The provider is already marked with an error, so
846e8d57122SPedro F. Giffuni  *   anything which comes in the interim will be returned immediately.
8474b8374a7SPoul-Henning Kamp  */
848dd84a43cSPoul-Henning Kamp 
849dd84a43cSPoul-Henning Kamp static void
850b1876192SPoul-Henning Kamp g_dev_orphan(struct g_consumer *cp)
851dd84a43cSPoul-Henning Kamp {
85289c9c53dSPoul-Henning Kamp 	struct cdev *dev;
8533c330affSAlexander Motin 	struct g_dev_softc *sc;
854dd84a43cSPoul-Henning Kamp 
855dd84a43cSPoul-Henning Kamp 	g_topology_assert();
8563c330affSAlexander Motin 	sc = cp->private;
8573c330affSAlexander Motin 	dev = sc->sc_dev;
8583c330affSAlexander Motin 	g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, cp->geom->name);
859df6c9fe9SPoul-Henning Kamp 
860df6c9fe9SPoul-Henning Kamp 	/* Reset any dump-area set on this device */
8616b6e2954SConrad Meyer 	if (dev->si_flags & SI_DUMPDEV) {
8626b6e2954SConrad Meyer 		struct diocskerneldump_arg kda;
8636b6e2954SConrad Meyer 
8646b6e2954SConrad Meyer 		bzero(&kda, sizeof(kda));
8656b6e2954SConrad Meyer 		kda.kda_index = KDA_REMOVE_DEV;
8666b6e2954SConrad Meyer 		(void)dumper_remove(devtoname(dev), &kda);
8676b6e2954SConrad Meyer 	}
868df6c9fe9SPoul-Henning Kamp 
86989c9c53dSPoul-Henning Kamp 	/* Destroy the struct cdev *so we get no more requests */
8709c498bd5SAlexander Motin 	delist_dev(dev);
8713c330affSAlexander Motin 	destroy_dev_sched_cb(dev, g_dev_callback, cp);
872dd84a43cSPoul-Henning Kamp }
873dd84a43cSPoul-Henning Kamp 
874a50e92ccSRobert Wing static void
875a50e92ccSRobert Wing gdev_filter_detach(struct knote *kn)
876a50e92ccSRobert Wing {
877a50e92ccSRobert Wing 	struct g_dev_softc *sc;
878a50e92ccSRobert Wing 
879a50e92ccSRobert Wing 	sc = kn->kn_hook;
880a50e92ccSRobert Wing 
881a50e92ccSRobert Wing 	knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
882a50e92ccSRobert Wing }
883a50e92ccSRobert Wing 
884a50e92ccSRobert Wing static int
885a50e92ccSRobert Wing gdev_filter_vnode(struct knote *kn, long hint)
886a50e92ccSRobert Wing {
887a50e92ccSRobert Wing 	kn->kn_fflags |= kn->kn_sfflags & hint;
888a50e92ccSRobert Wing 
889a50e92ccSRobert Wing 	return (kn->kn_fflags != 0);
890a50e92ccSRobert Wing }
891a50e92ccSRobert Wing 
892a50e92ccSRobert Wing static int
893a50e92ccSRobert Wing g_dev_kqfilter(struct cdev *dev, struct knote *kn)
894a50e92ccSRobert Wing {
895a50e92ccSRobert Wing 	struct g_dev_softc *sc;
896a50e92ccSRobert Wing 
897a50e92ccSRobert Wing 	sc = dev->si_drv1;
898a50e92ccSRobert Wing 
899a50e92ccSRobert Wing 	if (kn->kn_filter != EVFILT_VNODE)
900a50e92ccSRobert Wing 		return (EINVAL);
901a50e92ccSRobert Wing 
902*65c87a6cSRobert Wing #define SUPPORTED_EVENTS (NOTE_ATTRIB | NOTE_OPEN | NOTE_CLOSE | \
903*65c87a6cSRobert Wing     NOTE_CLOSE_WRITE | NOTE_READ | NOTE_WRITE)
904*65c87a6cSRobert Wing 	if (kn->kn_sfflags & ~SUPPORTED_EVENTS)
905*65c87a6cSRobert Wing 		return (EOPNOTSUPP);
906a50e92ccSRobert Wing 
907a50e92ccSRobert Wing 	kn->kn_fop = &gdev_filterops_vnode;
908a50e92ccSRobert Wing 	kn->kn_hook = sc;
909a50e92ccSRobert Wing 	knlist_add(&sc->sc_selinfo.si_note, kn, 0);
910a50e92ccSRobert Wing 
911a50e92ccSRobert Wing 	return (0);
912a50e92ccSRobert Wing }
913a50e92ccSRobert Wing 
9144b8374a7SPoul-Henning Kamp DECLARE_GEOM_CLASS(g_dev_class, g_dev);
915