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
38dd84a43cSPoul-Henning Kamp #include <sys/param.h>
39dd84a43cSPoul-Henning Kamp #include <sys/systm.h>
40dd84a43cSPoul-Henning Kamp #include <sys/kernel.h>
41b5cba416SPoul-Henning Kamp #include <sys/eventhandler.h>
42dd84a43cSPoul-Henning Kamp #include <sys/malloc.h>
43dd84a43cSPoul-Henning Kamp #include <sys/bio.h>
44dd84a43cSPoul-Henning Kamp #include <sys/sysctl.h>
45dd84a43cSPoul-Henning Kamp #include <sys/proc.h>
46b2901e99SAndrew Thompson #include <sys/unistd.h>
47dd84a43cSPoul-Henning Kamp #include <sys/kthread.h>
48dd84a43cSPoul-Henning Kamp #include <sys/lock.h>
49dd84a43cSPoul-Henning Kamp #include <sys/mutex.h>
50dd84a43cSPoul-Henning Kamp #include <sys/sbuf.h>
5163710c4dSJohn Baldwin #include <sys/sched.h>
5263710c4dSJohn Baldwin #include <sys/sx.h>
53dd84a43cSPoul-Henning Kamp #include <geom/geom.h>
54b1876192SPoul-Henning Kamp #include <geom/geom_int.h>
55dd84a43cSPoul-Henning Kamp
56dd84a43cSPoul-Henning Kamp MALLOC_DEFINE(M_GEOM, "GEOM", "Geom data structures");
57dd84a43cSPoul-Henning Kamp
58dd84a43cSPoul-Henning Kamp struct sx topology_lock;
59dd84a43cSPoul-Henning Kamp
60b2901e99SAndrew Thompson static struct proc *g_proc;
61*ffc1cc95SAlexander Motin struct thread __read_mostly *g_up_td;
62*ffc1cc95SAlexander Motin struct thread __read_mostly *g_down_td;
6361322a0aSAlexander Motin static struct thread __read_mostly *g_event_td;
64dd84a43cSPoul-Henning Kamp
6561322a0aSAlexander Motin int __read_mostly g_debugflags;
6661322a0aSAlexander Motin int __read_mostly g_collectstats = G_STATS_PROVIDERS;
67b5cba416SPoul-Henning Kamp int g_shutdown;
681b2cb2b3SDag-Erling Smørgrav int g_notaste;
69dd84a43cSPoul-Henning Kamp
70b1937dd1SPoul-Henning Kamp /*
71b1937dd1SPoul-Henning Kamp * G_UP and G_DOWN are the two threads which push I/O through the
72b1937dd1SPoul-Henning Kamp * stack.
73b1937dd1SPoul-Henning Kamp *
74b1937dd1SPoul-Henning Kamp * Things are procesed in a FIFO order, but these threads could be
75b1937dd1SPoul-Henning Kamp * part of I/O prioritization by deciding which bios/bioqs to service
76b1937dd1SPoul-Henning Kamp * in what order.
77b1937dd1SPoul-Henning Kamp *
78e8d57122SPedro F. Giffuni * We have only one thread in each direction, it is believed that until
79b1937dd1SPoul-Henning Kamp * a very non-trivial workload in the UP/DOWN path this will be enough,
80b1937dd1SPoul-Henning Kamp * but more than one can actually be run without problems.
81b1937dd1SPoul-Henning Kamp *
82b1937dd1SPoul-Henning Kamp * Holding the "mymutex" is a debugging feature: It prevents people
83b1937dd1SPoul-Henning Kamp * from sleeping in the UP/DOWN I/O path by mistake or design (doing
84b1937dd1SPoul-Henning Kamp * so almost invariably result in deadlocks since it stalls all I/O
85b1937dd1SPoul-Henning Kamp * processing in the given direction.
86b1937dd1SPoul-Henning Kamp */
87b1937dd1SPoul-Henning Kamp
88dd84a43cSPoul-Henning Kamp static void
g_up_procbody(void * arg)89b2901e99SAndrew Thompson g_up_procbody(void *arg)
90dd84a43cSPoul-Henning Kamp {
91dd84a43cSPoul-Henning Kamp
92b2901e99SAndrew Thompson thread_lock(g_up_td);
93b2901e99SAndrew Thompson sched_prio(g_up_td, PRIBIO);
94b2901e99SAndrew Thompson thread_unlock(g_up_td);
95dd84a43cSPoul-Henning Kamp for(;;) {
96b2901e99SAndrew Thompson g_io_schedule_up(g_up_td);
97dd84a43cSPoul-Henning Kamp }
98dd84a43cSPoul-Henning Kamp }
99dd84a43cSPoul-Henning Kamp
100dd84a43cSPoul-Henning Kamp static void
g_down_procbody(void * arg)101b2901e99SAndrew Thompson g_down_procbody(void *arg)
102dd84a43cSPoul-Henning Kamp {
103dd84a43cSPoul-Henning Kamp
104b2901e99SAndrew Thompson thread_lock(g_down_td);
105b2901e99SAndrew Thompson sched_prio(g_down_td, PRIBIO);
106b2901e99SAndrew Thompson thread_unlock(g_down_td);
107dd84a43cSPoul-Henning Kamp for(;;) {
108b2901e99SAndrew Thompson g_io_schedule_down(g_down_td);
109dd84a43cSPoul-Henning Kamp }
110dd84a43cSPoul-Henning Kamp }
111dd84a43cSPoul-Henning Kamp
112dd84a43cSPoul-Henning Kamp static void
g_event_procbody(void * arg)113b2901e99SAndrew Thompson g_event_procbody(void *arg)
114dd84a43cSPoul-Henning Kamp {
115dd84a43cSPoul-Henning Kamp
116b2901e99SAndrew Thompson thread_lock(g_event_td);
117b2901e99SAndrew Thompson sched_prio(g_event_td, PRIBIO);
118b2901e99SAndrew Thompson thread_unlock(g_event_td);
119b1876192SPoul-Henning Kamp g_run_events();
120f7842e00SJaakko Heinonen /* NOTREACHED */
121dd84a43cSPoul-Henning Kamp }
122dd84a43cSPoul-Henning Kamp
12340ea77a0SAlexander Motin int
g_is_geom_thread(struct thread * td)12440ea77a0SAlexander Motin g_is_geom_thread(struct thread *td)
12540ea77a0SAlexander Motin {
12640ea77a0SAlexander Motin
12740ea77a0SAlexander Motin return (td == g_up_td || td == g_down_td || td == g_event_td);
12840ea77a0SAlexander Motin }
12940ea77a0SAlexander Motin
130b5cba416SPoul-Henning Kamp static void
geom_shutdown(void * foo __unused)131b5cba416SPoul-Henning Kamp geom_shutdown(void *foo __unused)
132b5cba416SPoul-Henning Kamp {
133b5cba416SPoul-Henning Kamp
134b5cba416SPoul-Henning Kamp g_shutdown = 1;
135b5cba416SPoul-Henning Kamp }
136b5cba416SPoul-Henning Kamp
137dd84a43cSPoul-Henning Kamp void
g_init(void)138dd84a43cSPoul-Henning Kamp g_init(void)
139dd84a43cSPoul-Henning Kamp {
14044be139bSPoul-Henning Kamp
14144be139bSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_ignition");
142dd84a43cSPoul-Henning Kamp sx_init(&topology_lock, "GEOM topology");
143dd84a43cSPoul-Henning Kamp g_io_init();
144dd84a43cSPoul-Henning Kamp g_event_init();
145d49d7ca5SPoul-Henning Kamp g_ctl_init();
146b2901e99SAndrew Thompson kproc_kthread_add(g_event_procbody, NULL, &g_proc, &g_event_td,
147b2901e99SAndrew Thompson RFHIGHPID, 0, "geom", "g_event");
148b2901e99SAndrew Thompson kproc_kthread_add(g_up_procbody, NULL, &g_proc, &g_up_td,
149b2901e99SAndrew Thompson RFHIGHPID, 0, "geom", "g_up");
150b2901e99SAndrew Thompson kproc_kthread_add(g_down_procbody, NULL, &g_proc, &g_down_td,
151b2901e99SAndrew Thompson RFHIGHPID, 0, "geom", "g_down");
152b5cba416SPoul-Henning Kamp EVENTHANDLER_REGISTER(shutdown_pre_sync, geom_shutdown, NULL,
153b5cba416SPoul-Henning Kamp SHUTDOWN_PRI_FIRST);
154dd84a43cSPoul-Henning Kamp }
155dd84a43cSPoul-Henning Kamp
156dd84a43cSPoul-Henning Kamp static int
sysctl_kern_geom_confany(struct sysctl_req * req,g_event_t * func,size_t * hint)1575c32e9fcSAlexander Motin sysctl_kern_geom_confany(struct sysctl_req *req, g_event_t *func, size_t *hint)
158d518e539SPoul-Henning Kamp {
1595c32e9fcSAlexander Motin size_t len = 0;
1605c32e9fcSAlexander Motin int error = 0;
161d518e539SPoul-Henning Kamp struct sbuf *sb;
162d518e539SPoul-Henning Kamp
1635c32e9fcSAlexander Motin if (req->oldptr == NULL) {
1645c32e9fcSAlexander Motin sb = sbuf_new(NULL, NULL, PAGE_SIZE, SBUF_FIXEDLEN |
1655c32e9fcSAlexander Motin SBUF_INCLUDENUL);
1665c32e9fcSAlexander Motin sbuf_set_drain(sb, sbuf_count_drain, &len);
1675c32e9fcSAlexander Motin g_waitfor_event(func, sb, M_WAITOK, NULL);
1685c32e9fcSAlexander Motin req->oldidx = *hint = len;
1695c32e9fcSAlexander Motin } else {
1705c32e9fcSAlexander Motin sb = sbuf_new(NULL, NULL, *hint, SBUF_AUTOEXTEND |
1715c32e9fcSAlexander Motin SBUF_INCLUDENUL);
1725c32e9fcSAlexander Motin g_waitfor_event(func, sb, M_WAITOK, NULL);
1735c32e9fcSAlexander Motin *hint = sbuf_len(sb);
1745c32e9fcSAlexander Motin error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
1755c32e9fcSAlexander Motin }
176d518e539SPoul-Henning Kamp sbuf_delete(sb);
177d518e539SPoul-Henning Kamp return error;
178d518e539SPoul-Henning Kamp }
179d518e539SPoul-Henning Kamp
180d518e539SPoul-Henning Kamp static int
sysctl_kern_geom_conftxt(SYSCTL_HANDLER_ARGS)1815c32e9fcSAlexander Motin sysctl_kern_geom_conftxt(SYSCTL_HANDLER_ARGS)
1825c32e9fcSAlexander Motin {
1835c32e9fcSAlexander Motin static size_t hint = PAGE_SIZE;
1845c32e9fcSAlexander Motin
1855c32e9fcSAlexander Motin return (sysctl_kern_geom_confany(req, g_conftxt, &hint));
1865c32e9fcSAlexander Motin }
1875c32e9fcSAlexander Motin
1885c32e9fcSAlexander Motin static int
sysctl_kern_geom_confdot(SYSCTL_HANDLER_ARGS)1892874f1cfSPoul-Henning Kamp sysctl_kern_geom_confdot(SYSCTL_HANDLER_ARGS)
190dd84a43cSPoul-Henning Kamp {
1915c32e9fcSAlexander Motin static size_t hint = PAGE_SIZE;
192dd84a43cSPoul-Henning Kamp
1935c32e9fcSAlexander Motin return (sysctl_kern_geom_confany(req, g_confdot, &hint));
194dd84a43cSPoul-Henning Kamp }
195dd84a43cSPoul-Henning Kamp
196dd84a43cSPoul-Henning Kamp static int
sysctl_kern_geom_confxml(SYSCTL_HANDLER_ARGS)1972874f1cfSPoul-Henning Kamp sysctl_kern_geom_confxml(SYSCTL_HANDLER_ARGS)
198dd84a43cSPoul-Henning Kamp {
1995c32e9fcSAlexander Motin static size_t hint = PAGE_SIZE;
200dd84a43cSPoul-Henning Kamp
2015c32e9fcSAlexander Motin return (sysctl_kern_geom_confany(req, g_confxml, &hint));
202dd84a43cSPoul-Henning Kamp }
203dd84a43cSPoul-Henning Kamp
2047029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, geom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
2057029da5cSPawel Biernacki "GEOMetry management");
20629c21195SPoul-Henning Kamp
2077029da5cSPawel Biernacki SYSCTL_PROC(_kern_geom, OID_AUTO, confxml,
208c2da9542SAlexander Motin CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,
2097029da5cSPawel Biernacki sysctl_kern_geom_confxml, "",
210d518e539SPoul-Henning Kamp "Dump the GEOM config in XML");
211dd84a43cSPoul-Henning Kamp
2127029da5cSPawel Biernacki SYSCTL_PROC(_kern_geom, OID_AUTO, confdot,
213c2da9542SAlexander Motin CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,
2147029da5cSPawel Biernacki sysctl_kern_geom_confdot, "",
215d518e539SPoul-Henning Kamp "Dump the GEOM config in dot");
216d518e539SPoul-Henning Kamp
2177029da5cSPawel Biernacki SYSCTL_PROC(_kern_geom, OID_AUTO, conftxt,
218c2da9542SAlexander Motin CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,
2197029da5cSPawel Biernacki sysctl_kern_geom_conftxt, "",
220d518e539SPoul-Henning Kamp "Dump the GEOM config in txt");
22129c21195SPoul-Henning Kamp
222af3b2549SHans Petter Selasky SYSCTL_INT(_kern_geom, OID_AUTO, debugflags, CTLFLAG_RWTUN,
2238c957640SLukas Ertl &g_debugflags, 0, "Set various trace levels for GEOM debugging");
224dd84a43cSPoul-Henning Kamp
2251b2cb2b3SDag-Erling Smørgrav SYSCTL_INT(_kern_geom, OID_AUTO, notaste, CTLFLAG_RW,
2261b2cb2b3SDag-Erling Smørgrav &g_notaste, 0, "Prevent GEOM tasting");
2271b2cb2b3SDag-Erling Smørgrav
228801bb689SPoul-Henning Kamp SYSCTL_INT(_kern_geom, OID_AUTO, collectstats, CTLFLAG_RW,
2298c957640SLukas Ertl &g_collectstats, 0,
2308c957640SLukas Ertl "Control statistics collection on GEOM providers and consumers");
231801bb689SPoul-Henning Kamp
2326adb7488SPoul-Henning Kamp SYSCTL_INT(_debug_sizeof, OID_AUTO, g_class, CTLFLAG_RD,
233f0188618SHans Petter Selasky SYSCTL_NULL_INT_PTR, sizeof(struct g_class), "sizeof(struct g_class)");
2346adb7488SPoul-Henning Kamp SYSCTL_INT(_debug_sizeof, OID_AUTO, g_geom, CTLFLAG_RD,
235f0188618SHans Petter Selasky SYSCTL_NULL_INT_PTR, sizeof(struct g_geom), "sizeof(struct g_geom)");
2366adb7488SPoul-Henning Kamp SYSCTL_INT(_debug_sizeof, OID_AUTO, g_provider, CTLFLAG_RD,
237f0188618SHans Petter Selasky SYSCTL_NULL_INT_PTR, sizeof(struct g_provider), "sizeof(struct g_provider)");
2386adb7488SPoul-Henning Kamp SYSCTL_INT(_debug_sizeof, OID_AUTO, g_consumer, CTLFLAG_RD,
239f0188618SHans Petter Selasky SYSCTL_NULL_INT_PTR, sizeof(struct g_consumer), "sizeof(struct g_consumer)");
2406adb7488SPoul-Henning Kamp SYSCTL_INT(_debug_sizeof, OID_AUTO, g_bioq, CTLFLAG_RD,
241f0188618SHans Petter Selasky SYSCTL_NULL_INT_PTR, sizeof(struct g_bioq), "sizeof(struct g_bioq)");
242