summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/geom/geom.h1
-rw-r--r--sys/geom/geom_disk.c6
-rw-r--r--sys/geom/geom_dump.c3
-rw-r--r--sys/geom/geom_event.c73
-rw-r--r--sys/geom/geom_kern.c15
-rw-r--r--sys/geom/geom_sunlabel.c6
6 files changed, 69 insertions, 35 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h
index b05fb1d..80d2949 100644
--- a/sys/geom/geom.h
+++ b/sys/geom/geom.h
@@ -211,6 +211,7 @@ void g_trace(int level, const char *, ...);
typedef void g_event_t(void *, int flag);
#define EV_CANCEL 1
int g_post_event(g_event_t *func, void *arg, int flag, ...);
+int g_waitfor_event(g_event_t *func, void *arg, int flag, ...);
void g_cancel_event(void *ref);
void g_orphan_provider(struct g_provider *pp, int error);
void g_waitidle(void);
diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c
index 91887b8..ec2e9b8 100644
--- a/sys/geom/geom_disk.c
+++ b/sys/geom/geom_disk.c
@@ -375,7 +375,6 @@ g_kern_disks(void *p, int flag __unused)
sp = " ";
}
sbuf_finish(sb);
- wakeup(sb);
}
static int
@@ -386,10 +385,7 @@ sysctl_disks(SYSCTL_HANDLER_ARGS)
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
sbuf_clear(sb);
- g_post_event(g_kern_disks, sb, M_WAITOK, NULL);
- while (!sbuf_done(sb)) {
- tsleep(sb, PZERO, "kern.disks", hz);
- }
+ g_waitfor_event(g_kern_disks, sb, M_WAITOK, NULL);
error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
sbuf_delete(sb);
return error;
diff --git a/sys/geom/geom_dump.c b/sys/geom/geom_dump.c
index 3f064b3..c56a25d 100644
--- a/sys/geom/geom_dump.c
+++ b/sys/geom/geom_dump.c
@@ -106,7 +106,6 @@ g_confdot(void *p, int flag )
g_confdot_class(sb, mp);
sbuf_printf(sb, "};\n");
sbuf_finish(sb);
- wakeup(p);
}
static void
@@ -150,7 +149,6 @@ g_conftxt(void *p, int flag)
if (mp != NULL)
g_conftxt_class(sb, mp);
sbuf_finish(sb);
- wakeup(p);
}
@@ -260,7 +258,6 @@ g_confxml(void *p, int flag)
KASSERT(flag != EV_CANCEL, ("g_confxml was cancelled"));
g_topology_assert();
g_conf_specific(p, NULL, NULL, NULL, NULL);
- wakeup(p);
}
void
diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c
index babff65..0add6cf 100644
--- a/sys/geom/geom_event.c
+++ b/sys/geom/geom_event.c
@@ -64,11 +64,15 @@ static struct sx g_eventstall;
struct g_event {
TAILQ_ENTRY(g_event) events;
- void *arg;
g_event_t *func;
+ void *arg;
+ int flag;
void *ref[G_N_EVENTREFS];
};
+#define EV_DONE 0x80000
+#define EV_WAKEUP 0x40000
+
void
g_waitidle(void)
{
@@ -180,7 +184,12 @@ one_event(void)
g_topology_assert();
ep->func(ep->arg, 0);
g_topology_assert();
- g_destroy_event(ep);
+ if (ep->flag & EV_WAKEUP) {
+ ep->flag |= EV_DONE;
+ wakeup(ep);
+ } else {
+ g_destroy_event(ep);
+ }
g_pending_events--;
if (g_pending_events == 0)
wakeup(&g_pending_events);
@@ -212,7 +221,12 @@ g_cancel_event(void *ref)
if (ep->ref[n] == ref) {
TAILQ_REMOVE(&g_events, ep, events);
ep->func(ep->arg, EV_CANCEL);
- g_free(ep);
+ if (ep->flag & EV_WAKEUP) {
+ ep->flag |= EV_DONE;
+ wakeup(ep);
+ } else {
+ g_destroy_event(ep);
+ }
break;
}
}
@@ -220,21 +234,18 @@ g_cancel_event(void *ref)
mtx_unlock(&g_eventlock);
}
-int
-g_post_event(g_event_t *func, void *arg, int flag, ...)
+static int
+g_post_event_x(g_event_t *func, void *arg, int flag, struct g_event **epp, va_list ap)
{
struct g_event *ep;
- va_list ap;
void *p;
u_int n;
- g_trace(G_T_TOPOLOGY, "g_post_event(%p, %p, %d", func, arg, flag);
- KASSERT(flag == M_NOWAIT || flag == M_WAITOK,
- ("Wrong flag to g_post_event"));
+ g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d", func, arg, flag);
ep = g_malloc(sizeof *ep, flag | M_ZERO);
if (ep == NULL)
return (ENOMEM);
- va_start(ap, flag);
+ ep->flag = flag;
for (n = 0; n < G_N_EVENTREFS; n++) {
p = va_arg(ap, void *);
if (p == NULL)
@@ -251,6 +262,48 @@ g_post_event(g_event_t *func, void *arg, int flag, ...)
TAILQ_INSERT_TAIL(&g_events, ep, events);
mtx_unlock(&g_eventlock);
wakeup(&g_wait_event);
+ if (epp != NULL)
+ *epp = ep;
+ return (0);
+}
+
+int
+g_post_event(g_event_t *func, void *arg, int flag, ...)
+{
+ va_list ap;
+
+ va_start(ap, flag);
+ KASSERT(flag == M_WAITOK || flag == M_NOWAIT,
+ ("Wrong flag to g_post_event"));
+ return (g_post_event_x(func, arg, flag, NULL, ap));
+}
+
+
+/*
+ * XXX: It might actually be useful to call this function with topology held.
+ * XXX: This would ensure that the event gets created before anything else
+ * XXX: changes. At present all users have a handle on things in some other
+ * XXX: way, so this remains an XXX for now.
+ */
+
+int
+g_waitfor_event(g_event_t *func, void *arg, int flag, ...)
+{
+ va_list ap;
+ struct g_event *ep;
+ int error;
+
+ /* g_topology_assert_not(); */
+ va_start(ap, flag);
+ KASSERT(flag == M_WAITOK || flag == M_NOWAIT,
+ ("Wrong flag to g_post_event"));
+ error = g_post_event_x(func, arg, flag | EV_WAKEUP, &ep, ap);
+ if (error)
+ return (error);
+ do
+ tsleep(ep, PRIBIO, "g_waitfor_event", hz);
+ while (!(ep->flag & EV_DONE));
+ g_destroy_event(ep);
return (0);
}
diff --git a/sys/geom/geom_kern.c b/sys/geom/geom_kern.c
index 38531b7..aa44b9f 100644
--- a/sys/geom/geom_kern.c
+++ b/sys/geom/geom_kern.c
@@ -172,10 +172,7 @@ sysctl_kern_geom_conftxt(SYSCTL_HANDLER_ARGS)
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
sbuf_clear(sb);
- g_post_event(g_conftxt, sb, M_WAITOK, NULL);
- do {
- tsleep(sb, PZERO, "g_conftxt", hz);
- } while(!sbuf_done(sb));
+ g_waitfor_event(g_conftxt, sb, M_WAITOK, NULL);
error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
sbuf_delete(sb);
return error;
@@ -189,10 +186,7 @@ sysctl_kern_geom_confdot(SYSCTL_HANDLER_ARGS)
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
sbuf_clear(sb);
- g_post_event(g_confdot, sb, M_WAITOK, NULL);
- do {
- tsleep(sb, PZERO, "g_confdot", hz);
- } while(!sbuf_done(sb));
+ g_waitfor_event(g_confdot, sb, M_WAITOK, NULL);
error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
sbuf_delete(sb);
return error;
@@ -206,10 +200,7 @@ sysctl_kern_geom_confxml(SYSCTL_HANDLER_ARGS)
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
sbuf_clear(sb);
- g_post_event(g_confxml, sb, M_WAITOK, NULL);
- do {
- tsleep(sb, PZERO, "g_confxml", hz);
- } while(!sbuf_done(sb));
+ g_waitfor_event(g_confxml, sb, M_WAITOK, NULL);
error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
sbuf_delete(sb);
return error;
diff --git a/sys/geom/geom_sunlabel.c b/sys/geom/geom_sunlabel.c
index edd3e6f..a8891af 100644
--- a/sys/geom/geom_sunlabel.c
+++ b/sys/geom/geom_sunlabel.c
@@ -164,7 +164,6 @@ g_sunlabel_callconfig(void *arg, int flag)
if (!hp->error)
hp->error = g_write_data(LIST_FIRST(&hp->gp->consumer),
0, hp->label, SUN_SIZE);
- wakeup(hp);
}
/*
@@ -194,11 +193,8 @@ g_sunlabel_config(struct gctl_req *req, struct g_geom *gp, const char *verb)
error = g_access_rel(cp, 1, 1, 1);
if (error)
return (error);
- g_post_event(g_sunlabel_callconfig, &h0h0, M_WAITOK, gp, NULL);
g_topology_unlock();
- do
- tsleep(&h0h0, PRIBIO, "g_sunlabel_config", hz);
- while (h0h0.error == -1);
+ g_waitfor_event(g_sunlabel_callconfig, &h0h0, M_WAITOK, gp, NULL);
g_topology_lock();
error = h0h0.error;
g_access_rel(cp, -1, -1, -1);
OpenPOWER on IntegriCloud