1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: head/sys/geom/geom_event.c 93818 2002-04-04 21:03:38Z jhb $
36 */
37
38/*
39 * XXX: How do we in general know that objects referenced in events
40 * have not been destroyed before we get around to handle the event ?
41 */
42
43#include <sys/param.h>
44#ifndef _KERNEL
45#include <stdio.h>
46#include <unistd.h>
47#include <string.h>
48#include <stdlib.h>
49#include <signal.h>
50#include <err.h>
51#else
52#include <sys/malloc.h>
53#include <sys/systm.h>
54#include <sys/kernel.h>
55#include <sys/lock.h>
56#include <sys/mutex.h>
57#endif
58#include <sys/errno.h>
59#include <sys/time.h>
60#include <geom/geom.h>
61#include <geom/geom_int.h>
62
63static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events);
64static u_int g_pending_events, g_silence_events;
65static void g_do_event(struct g_event *ep);
66static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep);
67static struct mtx g_doorlock;
68
69void
70g_silence(void)
71{
72
73 g_silence_events = 1;
74}
75
76void
77g_rattle(void)
78{
79
80 g_silence_events = 0;
81 mtx_lock(&Giant);
82 wakeup(&g_silence_events);
83 while (g_pending_events)
84 tsleep(&g_pending_events, PPAUSE, "g_rattle", hz/5);
85 mtx_unlock(&Giant);
86}
87
88void
89g_orphan_provider(struct g_provider *pp, int error)
90{
91
92 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
93 pp, pp->name, error);
94 KASSERT(error != 0,
95 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
96 pp, pp->name));
97 pp->error = error;
98 mtx_lock(&g_doorlock);
99 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
100 mtx_unlock(&g_doorlock);
101 mtx_lock(&Giant);
102 wakeup(&g_wait_event);
103 mtx_unlock(&Giant);
104}
105
106/*
107 * This function is called once on each provider which the event handler
108 * finds on its g_doorstep.
109 */
110
111static void
112g_orphan_register(struct g_provider *pp)
113{
114 struct g_consumer *cp, *cp2;
115
116 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name);
117 g_topology_assert();
118
119 /*
120 * Tell all consumers the bad news.
121 * Don't get surprised if they self-destruct.
122 */
123 cp = LIST_FIRST(&pp->consumers);
124 while (cp != NULL) {
125 cp2 = LIST_NEXT(cp, consumers);
126 KASSERT(cp->geom->orphan != NULL,
127 ("geom %s has no orphan, class %s",
128 cp->geom->name, cp->geom->class->name));
129 cp->geom->orphan(cp);
130 cp = cp2;
131 }
132}
133
134static void
135g_destroy_event(struct g_event *ep)
136{
137
138 g_free(ep);
139}
140
141static void
142g_do_event(struct g_event *ep)
143{
144 struct g_class *mp, *mp2;
145 struct g_geom *gp;
146 struct g_consumer *cp, *cp2;
147 struct g_provider *pp;
148 int i;
149
150 g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ",
151 ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer);
152 g_topology_assert();
153 switch (ep->event) {
154 case EV_NEW_CLASS:
155 mp2 = ep->class;
156 if (mp2->taste == NULL)
157 break;
158 LIST_FOREACH(mp, &g_classes, class) {
159 if (mp2 == mp)
160 continue;
161 LIST_FOREACH(gp, &mp->geom, geom) {
162 LIST_FOREACH(pp, &gp->provider, provider) {
163 mp2->taste(ep->class, pp, 0);
164 g_topology_assert();
165 }
166 }
167 }
168 break;
169 case EV_NEW_PROVIDER:
170 g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
171 ep->provider->name);
172 LIST_FOREACH(mp, &g_classes, class) {
173 if (mp->taste == NULL)
174 continue;
175 i = 1;
176 LIST_FOREACH(cp, &ep->provider->consumers, consumers)
177 if(cp->geom->class == mp)
178 i = 0;
179 if (i) {
180 mp->taste(mp, ep->provider, 0);
181 g_topology_assert();
182 }
183 }
184 break;
185 case EV_SPOILED:
186 g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
187 ep->provider, ep->provider->name, ep->consumer);
188 cp = LIST_FIRST(&ep->provider->consumers);
189 while (cp != NULL) {
190 cp2 = LIST_NEXT(cp, consumers);
191 if (cp->spoiled) {
192 g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)",
193 cp, cp->geom->name, cp->geom->spoiled);
194 if (cp->geom->spoiled != NULL)
195 cp->geom->spoiled(cp);
196 cp->spoiled = 0;
197 }
198 cp = cp2;
199 }
200 break;
201 case EV_LAST:
202 default:
203 KASSERT(1 == 0, ("Unknown event %d", ep->event));
204 }
205}
206
207static int
208one_event(void)
209{
210 struct g_event *ep;
211 struct g_provider *pp;
212
213 g_topology_lock();
214 for (;;) {
215 mtx_lock(&g_doorlock);
216 pp = TAILQ_FIRST(&g_doorstep);
217 if (pp != NULL)
218 TAILQ_REMOVE(&g_doorstep, pp, orphan);
219 mtx_unlock(&g_doorlock);
220 if (pp == NULL)
221 break;
222 g_orphan_register(pp);
223 }
224 ep = TAILQ_FIRST(&g_events);
225 if (ep == NULL) {
226 g_topology_unlock();
227 return (0);
228 }
229 TAILQ_REMOVE(&g_events, ep, events);
230 if (ep->class != NULL)
231 ep->class->event = NULL;
232 if (ep->geom != NULL)
233 ep->geom->event = NULL;
234 if (ep->provider != NULL)
235 ep->provider->event = NULL;
236 if (ep->consumer != NULL)
237 ep->consumer->event = NULL;
238 g_do_event(ep);
239 g_pending_events--;
240 if (g_pending_events == 0) {
241 mtx_lock(&Giant);
242 wakeup(&g_pending_events);
243 mtx_unlock(&Giant);
244 }
245 g_topology_unlock();
246 g_destroy_event(ep);
247 return (1);
248}
249
250void
251g_run_events()
252{
253
254 while (one_event())
255 ;
256}
257
258void
259g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
260{
261 struct g_event *ep;
262
263 g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
264 ev, mp, gp, pp, cp);
265 g_topology_assert();
266 ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
267 ep->event = ev;
268 if (mp != NULL) {
269 ep->class = mp;
270 KASSERT(mp->event == NULL, ("Double event on class"));
271 mp->event = ep;
272 }
273 if (gp != NULL) {
274 ep->geom = gp;
275 KASSERT(gp->event == NULL, ("Double event on geom"));
276 gp->event = ep;
277 }
278 if (pp != NULL) {
279 ep->provider = pp;
280 KASSERT(pp->event == NULL, ("Double event on provider"));
281 pp->event = ep;
282 }
283 if (cp != NULL) {
284 ep->consumer = cp;
285 KASSERT(cp->event == NULL, ("Double event on consumer"));
286 cp->event = ep;
287 }
288 g_pending_events++;
289 TAILQ_INSERT_TAIL(&g_events, ep, events);
290 mtx_lock(&Giant);
291 wakeup(&g_wait_event);
292 mtx_unlock(&Giant);
293}
294
295void
296g_event_init()
297{
298
299 mtx_init(&g_doorlock, "GEOM orphanage", NULL, MTX_DEF);
300}
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: head/sys/geom/geom_event.c 93818 2002-04-04 21:03:38Z jhb $
36 */
37
38/*
39 * XXX: How do we in general know that objects referenced in events
40 * have not been destroyed before we get around to handle the event ?
41 */
42
43#include <sys/param.h>
44#ifndef _KERNEL
45#include <stdio.h>
46#include <unistd.h>
47#include <string.h>
48#include <stdlib.h>
49#include <signal.h>
50#include <err.h>
51#else
52#include <sys/malloc.h>
53#include <sys/systm.h>
54#include <sys/kernel.h>
55#include <sys/lock.h>
56#include <sys/mutex.h>
57#endif
58#include <sys/errno.h>
59#include <sys/time.h>
60#include <geom/geom.h>
61#include <geom/geom_int.h>
62
63static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events);
64static u_int g_pending_events, g_silence_events;
65static void g_do_event(struct g_event *ep);
66static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep);
67static struct mtx g_doorlock;
68
69void
70g_silence(void)
71{
72
73 g_silence_events = 1;
74}
75
76void
77g_rattle(void)
78{
79
80 g_silence_events = 0;
81 mtx_lock(&Giant);
82 wakeup(&g_silence_events);
83 while (g_pending_events)
84 tsleep(&g_pending_events, PPAUSE, "g_rattle", hz/5);
85 mtx_unlock(&Giant);
86}
87
88void
89g_orphan_provider(struct g_provider *pp, int error)
90{
91
92 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
93 pp, pp->name, error);
94 KASSERT(error != 0,
95 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
96 pp, pp->name));
97 pp->error = error;
98 mtx_lock(&g_doorlock);
99 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
100 mtx_unlock(&g_doorlock);
101 mtx_lock(&Giant);
102 wakeup(&g_wait_event);
103 mtx_unlock(&Giant);
104}
105
106/*
107 * This function is called once on each provider which the event handler
108 * finds on its g_doorstep.
109 */
110
111static void
112g_orphan_register(struct g_provider *pp)
113{
114 struct g_consumer *cp, *cp2;
115
116 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name);
117 g_topology_assert();
118
119 /*
120 * Tell all consumers the bad news.
121 * Don't get surprised if they self-destruct.
122 */
123 cp = LIST_FIRST(&pp->consumers);
124 while (cp != NULL) {
125 cp2 = LIST_NEXT(cp, consumers);
126 KASSERT(cp->geom->orphan != NULL,
127 ("geom %s has no orphan, class %s",
128 cp->geom->name, cp->geom->class->name));
129 cp->geom->orphan(cp);
130 cp = cp2;
131 }
132}
133
134static void
135g_destroy_event(struct g_event *ep)
136{
137
138 g_free(ep);
139}
140
141static void
142g_do_event(struct g_event *ep)
143{
144 struct g_class *mp, *mp2;
145 struct g_geom *gp;
146 struct g_consumer *cp, *cp2;
147 struct g_provider *pp;
148 int i;
149
150 g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ",
151 ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer);
152 g_topology_assert();
153 switch (ep->event) {
154 case EV_NEW_CLASS:
155 mp2 = ep->class;
156 if (mp2->taste == NULL)
157 break;
158 LIST_FOREACH(mp, &g_classes, class) {
159 if (mp2 == mp)
160 continue;
161 LIST_FOREACH(gp, &mp->geom, geom) {
162 LIST_FOREACH(pp, &gp->provider, provider) {
163 mp2->taste(ep->class, pp, 0);
164 g_topology_assert();
165 }
166 }
167 }
168 break;
169 case EV_NEW_PROVIDER:
170 g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
171 ep->provider->name);
172 LIST_FOREACH(mp, &g_classes, class) {
173 if (mp->taste == NULL)
174 continue;
175 i = 1;
176 LIST_FOREACH(cp, &ep->provider->consumers, consumers)
177 if(cp->geom->class == mp)
178 i = 0;
179 if (i) {
180 mp->taste(mp, ep->provider, 0);
181 g_topology_assert();
182 }
183 }
184 break;
185 case EV_SPOILED:
186 g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
187 ep->provider, ep->provider->name, ep->consumer);
188 cp = LIST_FIRST(&ep->provider->consumers);
189 while (cp != NULL) {
190 cp2 = LIST_NEXT(cp, consumers);
191 if (cp->spoiled) {
192 g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)",
193 cp, cp->geom->name, cp->geom->spoiled);
194 if (cp->geom->spoiled != NULL)
195 cp->geom->spoiled(cp);
196 cp->spoiled = 0;
197 }
198 cp = cp2;
199 }
200 break;
201 case EV_LAST:
202 default:
203 KASSERT(1 == 0, ("Unknown event %d", ep->event));
204 }
205}
206
207static int
208one_event(void)
209{
210 struct g_event *ep;
211 struct g_provider *pp;
212
213 g_topology_lock();
214 for (;;) {
215 mtx_lock(&g_doorlock);
216 pp = TAILQ_FIRST(&g_doorstep);
217 if (pp != NULL)
218 TAILQ_REMOVE(&g_doorstep, pp, orphan);
219 mtx_unlock(&g_doorlock);
220 if (pp == NULL)
221 break;
222 g_orphan_register(pp);
223 }
224 ep = TAILQ_FIRST(&g_events);
225 if (ep == NULL) {
226 g_topology_unlock();
227 return (0);
228 }
229 TAILQ_REMOVE(&g_events, ep, events);
230 if (ep->class != NULL)
231 ep->class->event = NULL;
232 if (ep->geom != NULL)
233 ep->geom->event = NULL;
234 if (ep->provider != NULL)
235 ep->provider->event = NULL;
236 if (ep->consumer != NULL)
237 ep->consumer->event = NULL;
238 g_do_event(ep);
239 g_pending_events--;
240 if (g_pending_events == 0) {
241 mtx_lock(&Giant);
242 wakeup(&g_pending_events);
243 mtx_unlock(&Giant);
244 }
245 g_topology_unlock();
246 g_destroy_event(ep);
247 return (1);
248}
249
250void
251g_run_events()
252{
253
254 while (one_event())
255 ;
256}
257
258void
259g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
260{
261 struct g_event *ep;
262
263 g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
264 ev, mp, gp, pp, cp);
265 g_topology_assert();
266 ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
267 ep->event = ev;
268 if (mp != NULL) {
269 ep->class = mp;
270 KASSERT(mp->event == NULL, ("Double event on class"));
271 mp->event = ep;
272 }
273 if (gp != NULL) {
274 ep->geom = gp;
275 KASSERT(gp->event == NULL, ("Double event on geom"));
276 gp->event = ep;
277 }
278 if (pp != NULL) {
279 ep->provider = pp;
280 KASSERT(pp->event == NULL, ("Double event on provider"));
281 pp->event = ep;
282 }
283 if (cp != NULL) {
284 ep->consumer = cp;
285 KASSERT(cp->event == NULL, ("Double event on consumer"));
286 cp->event = ep;
287 }
288 g_pending_events++;
289 TAILQ_INSERT_TAIL(&g_events, ep, events);
290 mtx_lock(&Giant);
291 wakeup(&g_wait_event);
292 mtx_unlock(&Giant);
293}
294
295void
296g_event_init()
297{
298
299 mtx_init(&g_doorlock, "GEOM orphanage", NULL, MTX_DEF);
300}