mdeg.c revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* 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
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* MD Event Generator (MDEG) Module
*/
#include <sys/machsystm.h>
#include <sys/mach_descrip.h>
/*
* A single client registration
*/
typedef struct mdeg_clnt {
} mdeg_clnt_t;
/*
* Global MDEG data
*
* Locking Strategy:
*
* mdeg.lock - lock used to sychronize system wide MD updates. An
* MD update must be treated as an atomic event. The lock is
* taken when notification that a new MD is available and held
* until all clients have been notified.
*
* mdeg.rwlock - lock used to sychronize access to the table of
* registered clients. The reader lock must be held when looking
* up client information in the table. The writer lock must be
* held when modifying any client information.
*/
static struct mdeg {
} mdeg;
/*
* Debugging routines
*/
#ifdef DEBUG
static void mdeg_dump_table(void);
#define MDEG_DUMP_CLNT mdeg_dump_clnt
#define MDEG_DUMP_TABLE mdeg_dump_table
#else /* DEBUG */
#define MDEG_DUMP_CLNT
#define MDEG_DUMP_TABLE()
#endif /* DEBUG */
/*
* Global constants
*/
/*
* A client handle is a 64 bit value with two pieces of
* information encoded in it. The upper 32 bits are the
* index into the table of a particular client structure.
* The lower 32 bits are a counter that is incremented
* each time a client structure is reused.
*/
#define MDEG_IDX_SHIFT 32
#define MDEG_COUNT_MASK 0xfffffffful
static const char trunc_str[] = " ... }";
/*
* Utility routines
*/
static mdeg_clnt_t *mdeg_alloc_clnt(void);
static void mdeg_notify_client(void *);
int
mdeg_init(void)
{
int tblsz;
/*
* Grab the current MD
*/
return (-1);
}
/*
* Initialize table of registered clients
*/
/*
* Initialize global lock
*/
/*
* Initialize the task queue
*/
/* ready to begin handling clients */
return (0);
}
void
mdeg_fini(void)
{
/*
* Flip the enabled switch off to make sure that
* no events get dispatched while things are being
* torn down.
*/
/* destroy the task queue */
/*
* Deallocate the table of registered clients
*/
/*
* Free up the cached MDs.
*/
}
static mdeg_clnt_t *
mdeg_alloc_clnt(void)
{
int idx;
/* search for an unused slot in the table */
break;
}
}
/* found any empty slot */
goto found;
}
/*
* There was no free space in the table. Grow
* the table to double its current size.
*/
MDEG_DBG("client table full:\n");
/* copy old table data to the new table */
/*
* Since the old table was full, the first free entry
* will be just past the end of the old table.
*/
/* clean up the old table */
return (clnt);
}
static mdeg_clnt_t *
{
int idx;
/* check if index is out of bounds */
MDEG_DBG("mdeg_get_client: index out of bounds\n");
return (NULL);
}
/* check for a valid client */
MDEG_DBG("mdeg_get_client: client is not valid\n");
return (NULL);
}
/* make sure the handle is an exact match */
MDEG_DBG("mdeg_get_client: bad handle\n");
return (NULL);
}
MDEG_DBG("mdeg_get_client: bad magic\n");
return (NULL);
}
return (clnt);
}
/*
* Send a notification to a client immediately after it registers.
* The result_t is a list of all the nodes that match their specified
* nodes of interest, all returned on the added list. This serves
* as a base of reference to the client. All future MD updates are
* relative to this list.
*/
static int
{
int nnodes;
int nodechk;
int rv = MDEG_SUCCESS;
/*
* Handle the special case where the node specification
* is NULL. In this case, call the client callback without
* any results. All processing is left to the client.
*/
/* call the client callback */
goto done;
}
rv = MDEG_FAILURE;
goto done;
}
if (startnode == MDE_INVAL_ELEM_COOKIE) {
/* not much we can do */
rv = MDEG_FAILURE;
goto done;
}
/*
* Use zalloc to provide correct default values for the
* unused removed, match_prev, and match_curr lists.
*/
if (nnodes == 0) {
MDEG_DBG("mdeg_notify_client_reg: no nodes of interest\n");
rv = MDEG_SUCCESS;
goto done;
} else if (nnodes == -1) {
MDEG_DBG("error scanning DAG\n");
rv = MDEG_FAILURE;
goto done;
}
MDEG_DBG("mdeg_notify_client_reg: %d node%s of interest\n",
/* get the list of nodes of interest */
/* call the client callback */
done:
if (mdp)
(void) md_fini_handle(mdp);
if (listp)
if (mdeg_res)
return (rv);
}
/*
* Register to receive an event notification when the system
* machine description is updated.
*
* Passing NULL for the node specification parameter is valid
* as long as the match specification is also NULL. In this
* case, the client will receive a notification when the MD
* has been updated, but the callback will not include any
* information. The client is then responsible for obtaining
* its own copy of the system MD and performing any processing
* manually.
*/
int
{
/*
* If the RW lock is held, a client is calling
* register from its own callback.
*/
MDEG_DBG("mdeg_register: rwlock already held\n");
return (MDEG_FAILURE);
}
/* node spec and node match must both be valid, or both NULL */
MDEG_DBG("mdeg_register: invalid parameters\n");
return (MDEG_FAILURE);
}
clnt = mdeg_alloc_clnt();
/*
* Fill in the rest of the data
*/
/* do this last */
return (MDEG_FAILURE);
}
return (MDEG_SUCCESS);
}
int
{
/*
* If the RW lock is held, a client is calling
* unregister from its own callback.
*/
MDEG_DBG("mdeg_unregister: rwlock already held\n");
return (MDEG_FAILURE);
}
/* lookup the client */
return (MDEG_FAILURE);
}
/* save the handle to prevent reuse */
return (MDEG_SUCCESS);
}
/*
* Simple algorithm for now, grab the global lock and let all
* the clients update themselves in parallel. There is a lot of
* room for improvement here. We could eliminate some scans of
* the DAG by imcrementally scanning at lower levels of the DAG
* rather than having each client start its own scan from the root.
*/
void
mdeg_notify_clients(void)
{
int idx;
int nclnt;
/*
* Rotate the MDs
*/
goto done;
}
}
MDEG_DBG("mdeg_notify_clients: no clients registered\n");
goto done;
}
/* dispatch the update notification to all clients */
continue;
}
done:
}
static void
mdeg_notify_client(void *arg)
{
/* trying to shutdown */
MDEG_DBG("mdeg_notify_client: mdeg disabled, aborting\n");
goto cleanup;
}
/*
* Handle the special case where the node specification
* is NULL. In this case, call the client callback without
* any results. All processing is left to the client.
*/
/* call the client callback */
MDEG_DBG("MDEG client callback done\n");
goto cleanup;
}
/* find our start nodes */
if (md_prev_start == MDE_INVAL_ELEM_COOKIE) {
goto cleanup;
}
if (md_curr_start == MDE_INVAL_ELEM_COOKIE) {
goto cleanup;
}
/* diff the MDs */
if (mdd == MD_INVAL_DIFF_COOKIE) {
MDEG_DBG("unable to diff MDs\n");
goto cleanup;
}
/*
* Cache the results of the diff
*/
/* call the client callback */
MDEG_DBG("MDEG client callback done\n");
if (mdd != MD_INVAL_DIFF_COOKIE)
(void) md_diff_fini(mdd);
}
static mde_cookie_t
{
int nnodes;
int idx;
return (MDE_INVAL_ELEM_COOKIE);
if (nnodes == 0)
return (MDE_INVAL_ELEM_COOKIE);
return (res);
}
}
return (MDE_INVAL_ELEM_COOKIE);
}
static boolean_t
{
case MDET_PROP_VAL: {
return (B_FALSE);
return (B_FALSE);
break;
}
case MDET_PROP_STR: {
char *str;
return (B_FALSE);
return (B_FALSE);
break;
}
default:
return (B_FALSE);
}
prop++;
}
return (B_TRUE);
}
static void
{
/*
* Cache added nodes.
*/
}
/*
* Cache removed nodes.
*/
}
/*
* Cache matching node pairs.
*/
}
}
#ifdef DEBUG
/*
* Generate a string that represents the node specifier
* structure. Clamp the string length if the specifier
* structure contains too much information.
*
* General form:
*
* <nodename>:{<propname>=<propval>,...}
* e.g.
* vdevice:{name=vsw,reg=0x0}
*/
static void
{
int offset;
if (len <= 0)
goto trunc;
case MDET_PROP_VAL:
if (len <= 0)
goto trunc;
break;
case MDET_PROP_STR:
if (len <= 0)
goto trunc;
break;
default:
return;
}
if (first)
prop++;
}
return;
/* string too long, truncate it */
}
/*
* Generate a string that represents the match structure.
* Clamp the string length if the match structure contains
* too much information.
*
* General form:
*
* <nodename>:{<propname>,...}
* e.g.
* nmatch=vport:{reg}
*/
static void
{
int offset;
if (len <= 0)
goto trunc;
if (len <= 0)
goto trunc;
if (first)
prop++;
}
return;
/* string too long, truncate it */
}
#define MAX_FIELD_STR 80
static void
{
char str[MAX_FIELD_STR];
MDEG_DBG(" valid=B_FALSE\n");
return;
}
}
static void
mdeg_dump_table(void)
{
int idx;
}
}
#endif /* DEBUG */