2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 1995-2003 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * Just in case we're not in a build environment, make sure that
2N/A * TEXT_DOMAIN gets set to something.
2N/A */
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * libmeta wrappers for event notification
2N/A */
2N/A
2N/A#include <meta.h>
2N/A#include <sys/lvm/md_notify.h>
2N/A
2N/A#if defined(DEBUG)
2N/A#include <assert.h>
2N/A#endif /* DEBUG */
2N/A
2N/Astruct tag2obj_type {
2N/A md_tags_t tag;
2N/A ev_obj_t obj;
2N/A} tag2obj_typetab[] =
2N/A{
2N/A { TAG_EMPTY, EVO_EMPTY },
2N/A { TAG_METADEVICE, EVO_METADEV },
2N/A { TAG_REPLICA, EVO_REPLICA },
2N/A { TAG_HSP, EVO_HSP },
2N/A { TAG_HS, EVO_HS },
2N/A { TAG_SET, EVO_SET },
2N/A { TAG_DRIVE, EVO_DRIVE },
2N/A { TAG_HOST, EVO_HOST },
2N/A { TAG_MEDIATOR, EVO_MEDIATOR },
2N/A { TAG_UNK, EVO_UNSPECIFIED },
2N/A
2N/A { TAG_LAST, EVO_LAST }
2N/A};
2N/A
2N/Astruct evdrv2evlib_type {
2N/A md_event_type_t drv;
2N/A evid_t lib;
2N/A} evdrv2evlib_typetab[] =
2N/A{
2N/A { EQ_EMPTY, EV_EMPTY },
2N/A { EQ_CREATE, EV_CREATE },
2N/A { EQ_DELETE, EV_DELETE },
2N/A { EQ_ADD, EV_ADD },
2N/A { EQ_REMOVE, EV_REMOVE },
2N/A { EQ_REPLACE, EV_REPLACE },
2N/A { EQ_MEDIATOR_ADD, EV_MEDIATOR_ADD },
2N/A { EQ_MEDIATOR_DELETE, EV_MEDIATOR_DELETE },
2N/A { EQ_HOST_ADD, EV_HOST_ADD },
2N/A { EQ_HOST_DELETE, EV_HOST_DELETE },
2N/A { EQ_DRIVE_ADD, EV_DRIVE_ADD },
2N/A { EQ_DRIVE_DELETE, EV_DRIVE_DELETE },
2N/A { EQ_RENAME_SRC, EV_RENAME_SRC },
2N/A { EQ_RENAME_DST, EV_RENAME_DST },
2N/A { EQ_INIT_START, EV_INIT_START },
2N/A { EQ_INIT_FAILED, EV_INIT_FAILED },
2N/A { EQ_INIT_FATAL, EV_INIT_FATAL },
2N/A { EQ_INIT_SUCCESS, EV_INIT_SUCCESS },
2N/A { EQ_IOERR, EV_IOERR },
2N/A { EQ_ERRED, EV_ERRED },
2N/A { EQ_LASTERRED, EV_LASTERRED },
2N/A { EQ_OK, EV_OK },
2N/A { EQ_ENABLE, EV_ENABLE },
2N/A { EQ_RESYNC_START, EV_RESYNC_START },
2N/A { EQ_RESYNC_FAILED, EV_RESYNC_FAILED },
2N/A { EQ_RESYNC_SUCCESS, EV_RESYNC_SUCCESS },
2N/A { EQ_RESYNC_DONE, EV_RESYNC_DONE },
2N/A { EQ_HOTSPARED, EV_HOTSPARED },
2N/A { EQ_HS_FREED, EV_HS_FREED },
2N/A { EQ_TAKEOVER, EV_TAKEOVER },
2N/A { EQ_RELEASE, EV_RELEASE },
2N/A { EQ_OPEN_FAIL, EV_OPEN_FAIL },
2N/A { EQ_OFFLINE, EV_OFFLINE },
2N/A { EQ_ONLINE, EV_ONLINE },
2N/A { EQ_GROW, EV_GROW },
2N/A { EQ_DETACH, EV_DETACH },
2N/A { EQ_DETACHING, EV_DETACHING },
2N/A { EQ_ATTACH, EV_ATTACH },
2N/A { EQ_ATTACHING, EV_ATTACHING },
2N/A { EQ_CHANGE, EV_CHANGE },
2N/A { EQ_EXCHANGE, EV_EXCHANGE },
2N/A { EQ_REGEN_START, EV_REGEN_START },
2N/A { EQ_REGEN_DONE, EV_REGEN_DONE },
2N/A { EQ_REGEN_FAILED, EV_REGEN_FAILED },
2N/A { EQ_USER, EV_USER },
2N/A { EQ_NOTIFY_LOST, EV_NOTIFY_LOST },
2N/A
2N/A { EQ_LAST, EV_LAST }
2N/A};
2N/A
2N/Astatic ev_obj_t
2N/Adev2tag(md_dev64_t dev, set_t setno, md_error_t *ep)
2N/A{
2N/A mdname_t *np = NULL;
2N/A mdsetname_t *sp = NULL;
2N/A ev_obj_t obj = EVO_METADEV;
2N/A char *miscname;
2N/A
2N/A if ((sp = metasetnosetname(setno, ep)) == NULL) {
2N/A goto out;
2N/A }
2N/A if (!(np = metamnumname(&sp, meta_getminor(dev), 0, ep))) {
2N/A goto out;
2N/A }
2N/A
2N/A /* need to invalidate name in case rename or delete/create done */
2N/A meta_invalidate_name(np);
2N/A
2N/A if (!(miscname = metagetmiscname(np, ep))) {
2N/A goto out;
2N/A }
2N/A if (strcmp(miscname, MD_STRIPE) == 0) {
2N/A obj = EVO_STRIPE;
2N/A } else if (strcmp(miscname, MD_MIRROR) == 0) {
2N/A obj = EVO_MIRROR;
2N/A } else if (strcmp(miscname, MD_RAID) == 0) {
2N/A obj = EVO_RAID5;
2N/A } else if (strcmp(miscname, MD_TRANS) == 0) {
2N/A obj = EVO_TRANS;
2N/A }
2N/Aout:
2N/A return (obj);
2N/A}
2N/A
2N/Astatic ev_obj_t
2N/Atagdrv_2_objlib(md_tags_t tag)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
2N/A if (tag2obj_typetab[i].tag == tag)
2N/A return (tag2obj_typetab[i].obj);
2N/A }
2N/A return (EVO_UNSPECIFIED);
2N/A}
2N/A
2N/Astatic md_tags_t
2N/Aobjlib_2_tagdrv(ev_obj_t obj)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
2N/A if (tag2obj_typetab[i].obj == obj)
2N/A return (tag2obj_typetab[i].tag);
2N/A }
2N/A return (TAG_UNK);
2N/A}
2N/A
2N/A
2N/Astatic evid_t
2N/Aevdrv_2_evlib(md_event_type_t drv_ev)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
2N/A if (evdrv2evlib_typetab[i].drv == drv_ev)
2N/A return (evdrv2evlib_typetab[i].lib);
2N/A }
2N/A return (EV_UNK);
2N/A}
2N/A
2N/Astatic md_event_type_t
2N/Aevlib_2_evdrv(evid_t lib_ev)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
2N/A if (evdrv2evlib_typetab[i].lib == lib_ev)
2N/A return (evdrv2evlib_typetab[i].drv);
2N/A }
2N/A return (EQ_EMPTY);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * meta_event
2N/A * returns 0 on succcess or < 0 to indicate error.
2N/A * abs(return code) = errno
2N/A */
2N/Astatic int
2N/Ameta_event(md_event_ioctl_t *evctl, md_error_t *ep)
2N/A{
2N/A int l;
2N/A
2N/A if (!evctl || !ep)
2N/A return (-EINVAL);
2N/A
2N/A l = strlen(evctl->mdn_name);
2N/A if ((l == 0 && evctl->mdn_cmd != EQ_PUT) || l >= MD_NOTIFY_NAME_SIZE) {
2N/A return (-EINVAL);
2N/A }
2N/A
2N/A MD_SETDRIVERNAME(evctl, MD_NOTIFY, 0);
2N/A mdclrerror(ep);
2N/A errno = 0;
2N/A
2N/A if (metaioctl(MD_IOCNOTIFY, evctl, ep, evctl->mdn_name) != 0) {
2N/A if (errno == 0) {
2N/A errno = EINVAL;
2N/A }
2N/A if (mdisok(ep)) {
2N/A (void) mdsyserror(ep, errno, evctl->mdn_name);
2N/A }
2N/A return (-errno);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic void
2N/Ainit_evctl(char *qname,
2N/A md_tags_t tag,
2N/A md_event_type_t ev,
2N/A uint_t flags,
2N/A set_t set,
2N/A md_dev64_t dev,
2N/A md_event_cmds_t cmd,
2N/A u_longlong_t udata,
2N/A md_event_ioctl_t *evctlp)
2N/A{
2N/A
2N/A assert(evctlp);
2N/A
2N/A (void) memset(evctlp, 0, sizeof (md_event_ioctl_t));
2N/A
2N/A evctlp->mdn_magic = MD_EVENT_ID;
2N/A evctlp->mdn_rev = MD_NOTIFY_REVISION;
2N/A
2N/A if (qname)
2N/A (void) strncpy(evctlp->mdn_name, qname, MD_NOTIFY_NAME_SIZE-1);
2N/A else
2N/A (void) memset(evctlp->mdn_name, 0, MD_NOTIFY_NAME_SIZE);
2N/A
2N/A evctlp->mdn_tag = tag;
2N/A evctlp->mdn_event = ev;
2N/A evctlp->mdn_flags = flags;
2N/A evctlp->mdn_set = set;
2N/A evctlp->mdn_dev = dev;
2N/A evctlp->mdn_cmd = cmd;
2N/A evctlp->mdn_user = udata;
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_createq
2N/A * - creates an eventq
2N/A * - returns 0 on success or errno and sets ep
2N/A */
2N/Aint
2N/Ameta_notify_createq(char *qname, ulong_t flags, md_error_t *ep)
2N/A{
2N/A md_event_ioctl_t evctl;
2N/A int err = 0;
2N/A
2N/A mdclrerror(ep);
2N/A if (!qname || strlen(qname) == 0) {
2N/A (void) mdsyserror(ep, EINVAL,
2N/A dgettext(TEXT_DOMAIN,
2N/A "null or zero-length queue name"));
2N/A return (EINVAL);
2N/A }
2N/A
2N/A init_evctl(qname,
2N/A TAG_EMPTY,
2N/A EQ_EMPTY,
2N/A (flags & EVFLG_PERMANENT) != 0? EQ_Q_PERM: 0,
2N/A /* set */ 0,
2N/A /* dev */ 0,
2N/A EQ_ON,
2N/A /* user-defined event data */ 0,
2N/A &evctl);
2N/A
2N/A err = meta_event(&evctl, ep);
2N/A
2N/A if (err == -EEXIST && !(flags & EVFLG_EXISTERR)) {
2N/A err = 0;
2N/A mdclrerror(ep);
2N/A }
2N/A if (!mdisok(ep) && mdanysyserror(ep)) {
2N/A err = (ep)->info.md_error_info_t_u.ds_error.errnum;
2N/A }
2N/A return (-err);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_deleteq
2N/A * - deletes an eventq
2N/A * - free's any underlying resources
2N/A * - returns 0 on success or errno and sets ep
2N/A */
2N/Aint
2N/Ameta_notify_deleteq(char *qname, md_error_t *ep)
2N/A{
2N/A md_event_ioctl_t evctl;
2N/A int err;
2N/A
2N/A init_evctl(qname,
2N/A TAG_EMPTY,
2N/A EQ_EMPTY,
2N/A /* flags */ 0,
2N/A /* set */ 0,
2N/A /* dev */ 0,
2N/A EQ_OFF,
2N/A /* user-defined event data */ 0,
2N/A &evctl);
2N/A
2N/A err = meta_event(&evctl, ep);
2N/A return (-err);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_validq
2N/A * - verifies that the queue exists
2N/A * - returns true or false, ep may be changed as a side-effect
2N/A */
2N/Abool_t
2N/Ameta_notify_validq(char *qname, md_error_t *ep)
2N/A{
2N/A md_event_ioctl_t evctl;
2N/A
2N/A init_evctl(qname,
2N/A TAG_EMPTY,
2N/A EQ_EMPTY,
2N/A /* flags */ 0,
2N/A /* set */ 0,
2N/A /* dev */ 0,
2N/A EQ_ON,
2N/A /* user-defined event data */ 0,
2N/A &evctl);
2N/A
2N/A return (meta_event(&evctl, ep) == -EEXIST);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_listq
2N/A * - returns number of (currently) active queus or -errno
2N/A * - allocates qnames array and sets user's pointer to it,
2N/A * fills in array with vector of qnames
2N/A */
2N/Aint
2N/Ameta_notify_listq(char ***qnames, md_error_t *ep)
2N/A{
2N/A
2N/A#ifdef lint
2N/A qnames = qnames;
2N/A#endif /* lint */
2N/A
2N/A mdclrerror(ep);
2N/A (void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
2N/A return (-EOPNOTSUPP);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_flushq
2N/A * - calls the underlying notify driver to flush all events
2N/A * from the named queue
2N/A * - returns 0 on success or errno and sets ep as necessary
2N/A */
2N/Aint
2N/Ameta_notify_flushq(char *qname, md_error_t *ep)
2N/A{
2N/A
2N/A#ifdef lint
2N/A qname = qname;
2N/A#endif /* lint */
2N/A
2N/A mdclrerror(ep);
2N/A (void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
2N/A return (EOPNOTSUPP);
2N/A}
2N/A
2N/Astatic void
2N/Acook_ev(md_event_ioctl_t *evctlp, md_ev_t *evp, md_error_t *ep)
2N/A{
2N/A assert(evctlp);
2N/A assert(evp);
2N/A
2N/A evp->obj_type = tagdrv_2_objlib(evctlp->mdn_tag);
2N/A
2N/A if (evp->obj_type == EVO_METADEV) {
2N/A evp->obj_type = dev2tag(evctlp->mdn_dev, evctlp->mdn_set, ep);
2N/A }
2N/A
2N/A evp->setno = evctlp->mdn_set;
2N/A evp->ev = evdrv_2_evlib(evctlp->mdn_event);
2N/A evp->obj = evctlp->mdn_dev;
2N/A evp->uev = evctlp->mdn_user;
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_getev
2N/A * - collects up to 1 event and stores it into md_ev_t
2N/A * - returns number of events found (0 or 1) on success or -errno
2N/A * - flags governs whether an empty queue is waited upon (EVFLG_WAIT)
2N/A */
2N/Aint
2N/Ameta_notify_getev(char *qname, ulong_t flags, md_ev_t *evp, md_error_t *ep)
2N/A{
2N/A md_event_ioctl_t evctl;
2N/A int n_ev;
2N/A int err = -EINVAL;
2N/A
2N/A if (!evp) {
2N/A goto out;
2N/A }
2N/A
2N/A init_evctl(qname,
2N/A TAG_EMPTY,
2N/A EQ_EMPTY,
2N/A /* flags (unused in get) */ 0,
2N/A (evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
2N/A (evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
2N/A (flags & EVFLG_WAIT) != 0? EQ_GET_WAIT: EQ_GET_NOWAIT,
2N/A /* user-defined event data */ 0,
2N/A &evctl);
2N/A
2N/A err = meta_event(&evctl, ep);
2N/A
2N/A /*
2N/A * trap EAGAIN so that EV_EMPTY events get returned, but
2N/A * be sure n_ev = 0 so that users who just watch the count
2N/A * will also work
2N/A */
2N/A switch (err) {
2N/A case -EAGAIN:
2N/A err = n_ev = 0;
2N/A cook_ev(&evctl, evp, ep);
2N/A break;
2N/A case 0:
2N/A n_ev = 1;
2N/A cook_ev(&evctl, evp, ep);
2N/A break;
2N/A }
2N/Aout:
2N/A return (err == 0? n_ev: err);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * meta_notify_getevlist
2N/A * - collects all pending events in the named queue and allocates
2N/A * an md_evlist_t * to return them
2N/A * - returns the number of events found (may be 0 if !WAIT) on success
2N/A * or -errno and sets ep as necessary
2N/A */
2N/Aint
2N/Ameta_notify_getevlist(char *qname,
2N/A ulong_t flags,
2N/A md_evlist_t **evpp_arg,
2N/A md_error_t *ep)
2N/A{
2N/A md_ev_t *evp = NULL;
2N/A md_evlist_t *evlp = NULL;
2N/A md_evlist_t *evlp_head = NULL;
2N/A md_evlist_t *new = NULL;
2N/A int n_ev = 0;
2N/A int err = -EINVAL;
2N/A
2N/A mdclrerror(ep);
2N/A if (!evpp_arg) {
2N/A (void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
2N/A "No event list pointer"));
2N/A goto out;
2N/A }
2N/A
2N/A if (!qname || strlen(qname) == 0) {
2N/A (void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
2N/A "Null or zero-length queue name"));
2N/A goto out;
2N/A }
2N/A
2N/A do {
2N/A if (!(evp = (md_ev_t *)Malloc(sizeof (md_ev_t)))) {
2N/A (void) mdsyserror(ep, ENOMEM, qname);
2N/A continue;
2N/A }
2N/A evp->obj_type = EVO_EMPTY;
2N/A evp->setno = EV_ALLSETS;
2N/A evp->ev = EV_EMPTY;
2N/A evp->obj = EV_ALLOBJS;
2N/A evp->uev = 0ULL;
2N/A
2N/A err = meta_notify_getev(qname, flags, evp, ep);
2N/A
2N/A if (evp->ev != EV_EMPTY) {
2N/A new = (md_evlist_t *)Zalloc(sizeof (md_evlist_t));
2N/A if (evlp_head == NULL) {
2N/A evlp = evlp_head = new;
2N/A } else {
2N/A evlp->next = new;
2N/A evlp = new;
2N/A }
2N/A evlp->evp = evp;
2N/A n_ev++;
2N/A }
2N/A
2N/A } while (err >= 0 && evp && evp->ev != EV_EMPTY);
2N/Aout:
2N/A if (err == -EAGAIN) {
2N/A err = 0;
2N/A }
2N/A
2N/A if (err < 0) {
2N/A meta_notify_freeevlist(evlp_head);
2N/A evlp_head = NULL;
2N/A return (err);
2N/A } else if ((err == 0) && (evp->ev == EV_EMPTY)) {
2N/A Free(evp);
2N/A evp = NULL;
2N/A }
2N/A
2N/A if (evpp_arg) {
2N/A *evpp_arg = evlp_head;
2N/A }
2N/A
2N/A return (n_ev);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * the guts of meta_notify_putev() and meta_notify_sendev()
2N/A * are within this function.
2N/A *
2N/A * meta_notify_putev() is intended for general use by user-level code,
2N/A * such as the GUI, to send user-defined events.
2N/A *
2N/A * meta_notify_sendev() is for "user-level driver" code, such as
2N/A * set manipulation and the multi-host daemon to generate events.
2N/A *
2N/A * Note- only convention enforces this usage.
2N/A */
2N/Aint
2N/Ameta_notify_doputev(md_ev_t *evp, md_error_t *ep)
2N/A{
2N/A md_event_ioctl_t evctl;
2N/A
2N/A if (!evp || !ep) {
2N/A return (EINVAL);
2N/A }
2N/A
2N/A /*
2N/A * users may only put events of type EQ_USER
2N/A */
2N/A init_evctl(/* qname (unused in put) */ NULL,
2N/A TAG_EMPTY,
2N/A EQ_EMPTY,
2N/A /* flags (unused in put) */ 0,
2N/A (evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
2N/A (evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
2N/A EQ_PUT,
2N/A evp->uev,
2N/A &evctl);
2N/A
2N/A evctl.mdn_tag = objlib_2_tagdrv(evp->obj_type);
2N/A evctl.mdn_event = evlib_2_evdrv(evp->ev);
2N/A
2N/A return (-meta_event(&evctl, ep));
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_putev
2N/A * - sends an event down to the notify driver (hence, all queues)
2N/A * - returns 0 on success or errno
2N/A */
2N/Aint
2N/Ameta_notify_putev(md_ev_t *evp, md_error_t *ep)
2N/A{
2N/A if (!evp || !ep) {
2N/A return (EINVAL);
2N/A }
2N/A
2N/A evp->ev = EV_USER; /* by definition */
2N/A
2N/A return (meta_notify_doputev(evp, ep));
2N/A}
2N/A
2N/A/*
2N/A * alternate put event entry point which allows
2N/A * more control of event innards (for use by md "user-level drivers")
2N/A *
2N/A * Since this routine isn't for use by clients, the user event data
2N/A * is always forced to be 0. That is only meaningful for events
2N/A * of type EQ_USER (and those go through meta_notify_putev()), so
2N/A * this is consistent.
2N/A */
2N/Aint
2N/Ameta_notify_sendev(
2N/A ev_obj_t tag,
2N/A set_t set,
2N/A md_dev64_t dev,
2N/A evid_t ev)
2N/A{
2N/A md_error_t status = mdnullerror;
2N/A md_error_t *ep = &status;
2N/A md_ev_t ev_packet;
2N/A int rc;
2N/A
2N/A ev_packet.obj_type = tag;
2N/A ev_packet.setno = set;
2N/A ev_packet.obj = dev;
2N/A ev_packet.ev = ev;
2N/A ev_packet.uev = 0ULL;
2N/A
2N/A rc = meta_notify_doputev(&ev_packet, ep);
2N/A
2N/A if (0 == rc && !mdisok(ep)) {
2N/A rc = EINVAL;
2N/A mdclrerror(ep);
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_putevlist
2N/A * - sends all of the events in the event list
2N/A * - returns number of events sent (>= 0) on success or -errno
2N/A */
2N/Aint
2N/Ameta_notify_putevlist(md_evlist_t *evlp, md_error_t *ep)
2N/A{
2N/A md_evlist_t *evlpi;
2N/A int n_ev = 0;
2N/A int err;
2N/A
2N/A if (!evlp) {
2N/A err = 0;
2N/A goto out; /* that was easy */
2N/A }
2N/A
2N/A for (n_ev = 0, evlpi = evlp; evlpi; evlpi = evlpi->next) {
2N/A if ((err = meta_notify_putev(evlpi->evp, ep)) < 0) {
2N/A goto out;
2N/A }
2N/A n_ev++;
2N/A }
2N/Aout:
2N/A return (err != 0? err: n_ev);
2N/A}
2N/A
2N/A/*
2N/A * meta_notify_freevlist
2N/A * - frees any memory allocated within the event list
2N/A * - returns 0 on success or errno and sets ep as necessary
2N/A */
2N/Avoid
2N/Ameta_notify_freeevlist(md_evlist_t *evlp)
2N/A{
2N/A md_evlist_t *i;
2N/A md_evlist_t *next;
2N/A
2N/A for (i = evlp; i; i = i->next) {
2N/A if (i && i->evp) {
2N/A Free(i->evp);
2N/A i->evp = NULL;
2N/A }
2N/A }
2N/A for (i = evlp; i; /* NULL */) {
2N/A next = i->next;
2N/A Free(i);
2N/A i = next;
2N/A }
2N/A}