diff options
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r-- | usr/src/uts/common/io/bofi.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/os/evchannels.c | 101 | ||||
-rw-r--r-- | usr/src/uts/common/os/fm.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/sys/door.h | 42 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sysevent.h | 123 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sysevent_impl.h | 6 |
6 files changed, 204 insertions, 74 deletions
diff --git a/usr/src/uts/common/io/bofi.c b/usr/src/uts/common/io/bofi.c index 275362dd51..80b69bd07b 100644 --- a/usr/src/uts/common/io/bofi.c +++ b/usr/src/uts/common/io/bofi.c @@ -784,7 +784,7 @@ bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) if (reset_bus_ops(nexus_name, &save_bus_ops) == 0) return (DDI_FAILURE); - sysevent_evc_unbind(bofi_error_chan); + (void) sysevent_evc_unbind(bofi_error_chan); mutex_destroy(&clone_tab_mutex); mutex_destroy(&bofi_mutex); diff --git a/usr/src/uts/common/os/evchannels.c b/usr/src/uts/common/os/evchannels.c index a25ef4fa65..9ae0565244 100644 --- a/usr/src/uts/common/os/evchannels.c +++ b/usr/src/uts/common/os/evchannels.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file contains the source of the general purpose event channel extension * to the sysevent framework. This implementation is made up mainly of four @@ -70,6 +68,9 @@ #define EVCH_EVQ_EVCOUNT(x) ((&(x)->eq_eventq)->sq_count) #define EVCH_EVQ_HIGHWM(x) ((&(x)->eq_eventq)->sq_highwm) +#define CH_HOLD_PEND 1 +#define CH_HOLD_PEND_INDEF 2 + struct evch_globals { evch_dlist_t evch_list; kmutex_t evch_list_lock; @@ -320,7 +321,8 @@ evch_zonefree(zoneid_t zoneid, void *arg) */ mutex_enter(&chp->ch_mutex); ASSERT(chp->ch_bindings == 0); - ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0); + ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0 || + chp->ch_holdpend == CH_HOLD_PEND_INDEF); /* Forcibly unsubscribe each remaining subscription */ while ((sdp = evch_dl_next(&chp->ch_subscr, NULL)) != NULL) { @@ -800,17 +802,50 @@ evch_namecmp(evch_dlelem_t *ep, char *s) } /* + * Simple wildcarded match test of event class string 'class' to + * wildcarded subscription string 'pat'. Recursive only if + * 'pat' includes a wildcard, otherwise essentially just strcmp. + */ +static int +evch_clsmatch(char *class, const char *pat) +{ + char c; + + do { + if ((c = *pat++) == '\0') + return (*class == '\0'); + + if (c == '*') { + while (*pat == '*') + pat++; /* consecutive *'s can be collapsed */ + + if (*pat == '\0') + return (1); + + while (*class != '\0') { + if (evch_clsmatch(class++, pat) != 0) + return (1); + } + + return (0); + } + } while (c == *class++); + + return (0); +} + +/* * Sysevent filter callback routine. Enables event delivery only if it matches - * the event class string given by parameter cookie. + * the event class pattern string given by parameter cookie. */ static int evch_class_filter(void *ev, void *cookie) { - char *class = (char *)cookie; + const char *pat = (const char *)cookie; - if (class == NULL || strcmp(SE_CLASS_NAME(ev), class) == 0) { + if (pat == NULL || evch_clsmatch(SE_CLASS_NAME(ev), pat)) return (EVQ_DELIVER); - } + return (EVQ_IGNORE); } @@ -1061,8 +1096,13 @@ evch_chbind(const char *chnam, evch_bind_t **scpp, uint32_t flags) p->ch_maxsubscr = EVCH_MAX_SUBSCRIPTIONS; p->ch_maxbinds = evch_bindings_max; p->ch_ctime = gethrestime_sec(); - if (flags & EVCH_HOLD_PEND) { - p->ch_holdpend = 1; + + if (flags & (EVCH_HOLD_PEND | EVCH_HOLD_PEND_INDEF)) { + if (flags & EVCH_HOLD_PEND_INDEF) + p->ch_holdpend = CH_HOLD_PEND_INDEF; + else + p->ch_holdpend = CH_HOLD_PEND; + evch_evq_stop(p->ch_queue); } @@ -1114,9 +1154,13 @@ evch_chunbind(evch_bind_t *bp) ASSERT(chp->ch_bindings > 0); chp->ch_bindings--; kmem_free(bp, sizeof (evch_bind_t)); - if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0) { + if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0 && + (chp->ch_nevents == 0 || chp->ch_holdpend != CH_HOLD_PEND_INDEF)) { /* - * No more bindings or persistent subscriber, destroy channel. + * No more bindings and no persistent subscriber(s). If there + * are no events in the channel then destroy the channel; + * otherwise destroy the channel only if we're not holding + * pending events indefinitely. */ mutex_exit(&chp->ch_mutex); evch_dl_del(&eg->evch_list, &chp->ch_link); @@ -1131,6 +1175,23 @@ evch_chunbind(evch_bind_t *bp) mutex_exit(&eg->evch_list_lock); } +static int +wildcard_count(const char *class) +{ + int count = 0; + char c; + + if (class == NULL) + return (0); + + while ((c = *class++) != '\0') { + if (c == '*') + count++; + } + + return (count); +} + /* * Subscribe to a channel. dtype is either EVCH_DELKERN for kernel callbacks * or EVCH_DELDOOR for door upcall delivery to user land. Depending on dtype @@ -1155,6 +1216,14 @@ evch_chsubscribe(evch_bind_t *bp, int dtype, const char *sid, const char *class, */ if (flags & ~(EVCH_SUB_KEEP | EVCH_SUB_DUMP)) return (EINVAL); + + /* + * Enforce a limit on the number of wildcards allowed in the class + * subscription string (limits recursion in pattern matching). + */ + if (wildcard_count(class) > EVCH_WILDCARD_MAX) + return (EINVAL); + /* * Check if we have already a subscription with that name and if we * have to reconnect the subscriber to a persistent subscription. @@ -1757,7 +1826,7 @@ sysevent_evc_bind(const char *ch_name, evchan_t **scpp, uint32_t flags) return (evch_chbind(ch_name, (evch_bind_t **)scpp, flags)); } -void +int sysevent_evc_unbind(evchan_t *scp) { evch_bind_t *bp = (evch_bind_t *)scp; @@ -1765,6 +1834,8 @@ sysevent_evc_unbind(evchan_t *scp) ASSERT(scp != NULL); evch_chunsubscribe(bp, NULL, 0); evch_chunbind(bp); + + return (0); } int @@ -1784,7 +1855,7 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class, (void *)callb, cookie, 0, 0)); } -void +int sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) { ASSERT(scp != NULL && sid != NULL); @@ -1792,6 +1863,8 @@ sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) sid = NULL; } evch_chunsubscribe((evch_bind_t *)scp, sid, 0); + + return (0); } /* diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c index c5ad2c3991..7dec9d8b91 100644 --- a/usr/src/uts/common/os/fm.c +++ b/usr/src/uts/common/os/fm.c @@ -517,10 +517,10 @@ fm_ereport_post(nvlist_t *ereport, int evc_flag) if (sysevent_evc_publish(error_chan, EC_FM, ESC_FM_ERROR, SUNW_VENDOR, FM_PUB, ereport, evc_flag) != 0) { atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1); - sysevent_evc_unbind(error_chan); + (void) sysevent_evc_unbind(error_chan); return; } - sysevent_evc_unbind(error_chan); + (void) sysevent_evc_unbind(error_chan); } /* diff --git a/usr/src/uts/common/sys/door.h b/usr/src/uts/common/sys/door.h index e45386270d..7d04847864 100644 --- a/usr/src/uts/common/sys/door.h +++ b/usr/src/uts/common/sys/door.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,12 +30,29 @@ #ifndef _SYS_DOOR_H #define _SYS_DOOR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif +/* + * Attributes associated with doors. + */ + +/* Attributes originally obtained from door_create operation */ +#define DOOR_UNREF 0x01 /* Deliver an unref notification with door */ +#define DOOR_PRIVATE 0x02 /* Use a private pool of server threads */ +#define DOOR_UNREF_MULTI 0x10 /* Deliver unref notification more than once */ +#define DOOR_REFUSE_DESC 0x40 /* Do not accept descriptors from callers */ +#define DOOR_NO_CANCEL 0x80 /* No server thread cancel on client abort */ +#define DOOR_NO_DEPLETION_CB 0x100 /* No thread create callbacks on depletion */ + +/* Attributes (additional) returned with door_info and door_desc_t data */ +#define DOOR_LOCAL 0x04 /* Descriptor is local to current process */ +#define DOOR_REVOKED 0x08 /* Door has been revoked */ +#define DOOR_IS_UNREF 0x20 /* Door is currently unreferenced */ +#define DOOR_PRIVCREATE 0x200 /* Door has a private thread creation func */ +#define DOOR_DEPLETION_CB 0x400 /* Set only during depletion callbacks */ + #if !defined(_ASM) #include <sys/types.h> @@ -62,25 +79,10 @@ typedef struct __door_handle *door_handle_t; /* opaque kernel door handle */ /* Door descriptor passed to door_info to get current thread's binding */ #define DOOR_QUERY -2 -/* - * Attributes associated with doors. - */ - -/* Attributes originally obtained from door_create operation */ -#define DOOR_UNREF 0x01 /* Deliver an unref notification with door */ -#define DOOR_PRIVATE 0x02 /* Use a private pool of server threads */ -#define DOOR_UNREF_MULTI 0x10 /* Deliver unref notification more than once */ -#define DOOR_REFUSE_DESC 0x40 /* Do not accept descriptors from callers */ -#define DOOR_NO_CANCEL 0x80 /* No server thread cancel on client abort */ - -/* Attributes (additional) returned with door_info and door_desc_t data */ -#define DOOR_LOCAL 0x04 /* Descriptor is local to current process */ -#define DOOR_REVOKED 0x08 /* Door has been revoked */ -#define DOOR_IS_UNREF 0x20 /* Door is currently unreferenced */ - /* Masks of applicable flags */ #define DOOR_CREATE_MASK (DOOR_UNREF | DOOR_PRIVATE | \ - DOOR_UNREF_MULTI | DOOR_REFUSE_DESC | DOOR_NO_CANCEL) + DOOR_UNREF_MULTI | DOOR_REFUSE_DESC | DOOR_NO_CANCEL | \ + DOOR_NO_DEPLETION_CB | DOOR_PRIVCREATE) #define DOOR_KI_CREATE_MASK (DOOR_UNREF | DOOR_UNREF_MULTI) /* Mask of above attributes */ diff --git a/usr/src/uts/common/sys/sysevent.h b/usr/src/uts/common/sys/sysevent.h index 0a61e41de8..44b5d069fb 100644 --- a/usr/src/uts/common/sys/sysevent.h +++ b/usr/src/uts/common/sys/sysevent.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,16 +18,15 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SYSEVENT_H #define _SYS_SYSEVENT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/nvpair.h> #ifdef __cplusplus @@ -164,18 +162,50 @@ typedef struct sysevent_value { #define EVCH_QWAIT 0x0008 /* Wait for slot in event queue */ /* - * Meaning of flags for subscribe/unsubscribe. Bits 0 to 7 are dedicated to - * the consolidation private interface. + * Meaning of flags for subscribe. Bits 8 to 15 are dedicated to + * the consolidation private interface, so flags defined here are restricted + * to the LSB. + * + * EVCH_SUB_KEEP indicates that this subscription should persist even if + * this subscriber id should die unexpectedly; matching events will be + * queued (up to a limit) and will be delivered if/when we restart again + * with the same subscriber id. + */ +#define EVCH_SUB_KEEP 0x01 + +/* + * Subscriptions may be wildcarded, but we limit the number of + * wildcards permitted. + */ +#define EVCH_WILDCARD_MAX 10 + +/* + * Used in unsubscribe to indicate all subscriber ids for a channel. */ -#define EVCH_SUB_KEEP 0x0001 #define EVCH_ALLSUB "all_subs" /* * Meaning of flags parameter of channel bind function + * + * EVCH_CREAT indicates to create a channel if not already present. + * + * EVCH_HOLD_PEND indicates that events should be published to this + * channel even if there are no matching subscribers present; when + * a subscriber belatedly binds to the channel and registers their + * subscriptions they will receive events that predate their bind. + * If the channel is closed, however, with no remaining bindings then + * the channel is destroyed. + * + * EVCH_HOLD_PEND_INDEF is a stronger version of EVCH_HOLD_PEND - + * even if the channel has no remaining bindings it will not be + * destroyed so long as events remain unconsumed. This is suitable for + * use with short-lived event producers that may bind to (create) the + * channel and exit before the intended consumer has started. */ -#define EVCH_CREAT 0x0001 /* Create a channel if not present */ +#define EVCH_CREAT 0x0001 #define EVCH_HOLD_PEND 0x0002 -#define EVCH_B_FLAGS 0x0003 /* All valid bits */ +#define EVCH_HOLD_PEND_INDEF 0x0004 +#define EVCH_B_FLAGS 0x0007 /* All valid bits */ /* * Meaning of commands of evc_control function @@ -186,37 +216,62 @@ typedef struct sysevent_value { #define EVCH_CMD_LAST EVCH_SET_CHAN_LEN /* Last command */ /* - * Event channel interface definitions + * Shared user/kernel event channel interface definitions */ -int sysevent_evc_bind(const char *, evchan_t **, uint32_t); -void sysevent_evc_unbind(evchan_t *); -int sysevent_evc_subscribe(evchan_t *, const char *, const char *, +extern int sysevent_evc_bind(const char *, evchan_t **, uint32_t); +extern int sysevent_evc_unbind(evchan_t *); +extern int sysevent_evc_subscribe(evchan_t *, const char *, const char *, int (*)(sysevent_t *, void *), void *, uint32_t); -void sysevent_evc_unsubscribe(evchan_t *, const char *); -int sysevent_evc_publish(evchan_t *, const char *, const char *, +extern int sysevent_evc_unsubscribe(evchan_t *, const char *); +extern int sysevent_evc_publish(evchan_t *, const char *, const char *, const char *, const char *, nvlist_t *, uint32_t); -int sysevent_evc_control(evchan_t *, int, ...); +extern int sysevent_evc_control(evchan_t *, int, ...); -#ifdef _KERNEL +#ifndef _KERNEL + +/* + * Userland-only event channel interfaces + */ + +#include <door.h> + +typedef struct sysevent_subattr sysevent_subattr_t; + +extern sysevent_subattr_t *sysevent_subattr_alloc(void); +extern void sysevent_subattr_free(sysevent_subattr_t *); + +extern void sysevent_subattr_thrattr(sysevent_subattr_t *, pthread_attr_t *); +extern void sysevent_subattr_sigmask(sysevent_subattr_t *, sigset_t *); + +extern void sysevent_subattr_thrcreate(sysevent_subattr_t *, + door_xcreate_server_func_t *, void *); +extern void sysevent_subattr_thrsetup(sysevent_subattr_t *, + door_xcreate_thrsetup_func_t *, void *); + +extern int sysevent_evc_xsubscribe(evchan_t *, const char *, const char *, + int (*)(sysevent_t *, void *), void *, uint32_t, sysevent_subattr_t *); + +#else /* * Kernel log_event interfaces. */ -int log_sysevent(sysevent_t *, int, sysevent_id_t *); - -sysevent_t *sysevent_alloc(char *, char *, char *, int); -void sysevent_free(sysevent_t *); -int sysevent_add_attr(sysevent_attr_list_t **, char *, sysevent_value_t *, int); -void sysevent_free_attr(sysevent_attr_list_t *); -int sysevent_attach_attributes(sysevent_t *, sysevent_attr_list_t *); -void sysevent_detach_attributes(sysevent_t *); -char *sysevent_get_class_name(sysevent_t *); -char *sysevent_get_subclass_name(sysevent_t *); -uint64_t sysevent_get_seq(sysevent_t *); -void sysevent_get_time(sysevent_t *, hrtime_t *); -size_t sysevent_get_size(sysevent_t *); -char *sysevent_get_pub(sysevent_t *); -int sysevent_get_attr_list(sysevent_t *, nvlist_t **); +extern int log_sysevent(sysevent_t *, int, sysevent_id_t *); + +extern sysevent_t *sysevent_alloc(char *, char *, char *, int); +extern void sysevent_free(sysevent_t *); +extern int sysevent_add_attr(sysevent_attr_list_t **, char *, + sysevent_value_t *, int); +extern void sysevent_free_attr(sysevent_attr_list_t *); +extern int sysevent_attach_attributes(sysevent_t *, sysevent_attr_list_t *); +extern void sysevent_detach_attributes(sysevent_t *); +extern char *sysevent_get_class_name(sysevent_t *); +extern char *sysevent_get_subclass_name(sysevent_t *); +extern uint64_t sysevent_get_seq(sysevent_t *); +extern void sysevent_get_time(sysevent_t *, hrtime_t *); +extern size_t sysevent_get_size(sysevent_t *); +extern char *sysevent_get_pub(sysevent_t *); +extern int sysevent_get_attr_list(sysevent_t *, nvlist_t **); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/sysevent_impl.h b/usr/src/uts/common/sys/sysevent_impl.h index 11115c8f2d..215862fbdd 100644 --- a/usr/src/uts/common/sys/sysevent_impl.h +++ b/usr/src/uts/common/sys/sysevent_impl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -476,9 +476,9 @@ typedef struct { /* * Project private flags for sysevent_evc_subscribe. Bits 0 to 7 are reserved - * for the consolidation private interface. + * for the consolidation private interface, so we must use bits 8-15 here. */ -#define EVCH_SUB_DUMP 0x0100 +#define EVCH_SUB_DUMP (0x01 << 8) /* * Permission flags |