minix/servers/ds/store.c
Cristiano Giuffrida d1fd04e72a Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.

SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic 
registration / deregistration of system services.

VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.

RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 01:20:42 +00:00

456 lines
12 KiB
C

/* Implementation of the Data Store. */
#include "inc.h"
/* Allocate space for the data store. */
PRIVATE struct data_store ds_store[NR_DS_KEYS];
PRIVATE struct subscription ds_subs[NR_DS_SUBS];
PRIVATE int nr_in_use;
PRIVATE _PROTOTYPE(int find_key, (char *key, struct data_store **dsp, int t));
PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, int auth));
PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, int auth));
PRIVATE _PROTOTYPE(void check_subscribers, (struct data_store *dsp));
/*===========================================================================*
* sef_cb_init_fresh *
*===========================================================================*/
PUBLIC int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the data store server. */
int i, r;
struct rprocpub rprocpub[NR_BOOT_PROCS];
/* Reset data store: data and subscriptions. */
for(i = 0; i < NR_DS_KEYS; i++) {
int b;
ds_store[i].ds_flags = 0;
for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++) {
ds_store[i].ds_old_subs[b] = 0;
}
}
for(i = 0; i < NR_DS_SUBS; i++)
ds_subs[i].sub_flags = 0;
/* Map all the services in the boot image. */
if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
(vir_bytes) rprocpub, sizeof(rprocpub), S)) != OK) {
panic("DS", "sys_safecopyfrom failed", r);
}
for(i=0;i < NR_BOOT_PROCS;i++) {
if(rprocpub[i].in_use) {
if((r = map_service(&rprocpub[i])) != OK) {
panic("DS", "unable to map service", r);
}
}
}
return(OK);
}
/*===========================================================================*
* map_service *
*===========================================================================*/
PUBLIC int map_service(rpub)
struct rprocpub *rpub;
{
/* Map a new service by registering its label. */
struct data_store *dsp;
dsp = &ds_store[nr_in_use]; /* new slot found */
strcpy(dsp->ds_key, rpub->label);
dsp->ds_flags = DS_IN_USE | DS_TYPE_U32; /* initialize slot */
nr_in_use++;
dsp->ds_val.ds_val_u32 = (u32_t) rpub->endpoint; /* store data */
/* If anyone has a matching subscription, update them. */
check_subscribers(dsp);
return(OK);
}
PRIVATE int set_owner(dsp, auth)
struct data_store *dsp; /* data store structure */
int auth;
{
return(TRUE);
}
PRIVATE int is_authorized(dsp, ap)
struct data_store *dsp; /* data store structure */
int ap; /* authorization value */
{
/* Authorize the caller. */
return(TRUE);
}
PRIVATE int find_key(key_name, dsp, type)
char *key_name; /* key to look up */
struct data_store **dsp; /* store pointer here */
int type; /* type info */
{
register int i;
*dsp = NULL;
for (i=0; i<NR_DS_KEYS; i++) {
if ((ds_store[i].ds_flags & DS_IN_USE) /* valid slot? */
&& ((ds_store[i].ds_flags & type) == type) /* right type? */
&& !strcmp(ds_store[i].ds_key, key_name)) { /* matching name? */
*dsp = &ds_store[i];
return(TRUE); /* report success */
}
}
return(FALSE); /* report not found */
}
PUBLIC int do_publish(m_ptr)
message *m_ptr; /* request message */
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
int r, type;
/* Store (key,value)-pair. First see if key already exists. If so,
* check if the caller is allowed to overwrite the value. Otherwise
* find a new slot and store the new value.
*/
if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
m_ptr->m_source);
return EINVAL;
}
/* Check type info. */
type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
if(type != DS_TYPE_U32 && type != DS_TYPE_STR) {
printf("DS: bogus type code %lx from %d\n", type, m_ptr->m_source);
return EINVAL;
}
/* Copy name from caller. */
if ((r=sys_safecopyfrom(m_ptr->m_source,
(cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
(vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
return r;
}
/* Make sure name is 0-terminated. */
key_name[DS_MAX_KEYLEN-1] = '\0';
/* See if it already exists. */
if (!find_key(key_name, &dsp, type)) { /* look up key */
if (nr_in_use >= NR_DS_KEYS) {
return(EAGAIN); /* store is full */
} else {
dsp = &ds_store[nr_in_use]; /* new slot found */
strcpy(dsp->ds_key, key_name);
dsp->ds_flags = DS_IN_USE | m_ptr->DS_FLAGS; /* initialize slot */
nr_in_use ++;
}
}
/* At this point we have a data store pointer and know the caller is
* authorize to write to it. Set all fields as requested.
*/
switch(type) {
case DS_TYPE_U32:
dsp->ds_val.ds_val_u32 = (u32_t) m_ptr->DS_VAL; /* store data */
break;
case DS_TYPE_STR:
/* store string data: check size, then do copy */
if(m_ptr->DS_VAL_LEN < 1 || m_ptr->DS_VAL_LEN > DS_MAX_VALLEN) {
printf("DS: publish: bogus len from %d: %d\n",
m_ptr->m_source, m_ptr->DS_VAL_LEN);
return EINVAL;
}
if((r=sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
(vir_bytes) dsp->ds_val.ds_val_str,
m_ptr->DS_VAL_LEN, D)) != OK) {
printf("DS: publish: str copy failed from %d: %d\n",
m_ptr->m_source, r);
return r;
}
break;
default:
panic(__FILE__, "Impossible type.", type);
break;
}
/* If anyone has a matching subscription, update them. */
check_subscribers(dsp);
return(OK);
}
/*===========================================================================*
* do_retrieve *
*===========================================================================*/
PUBLIC int do_retrieve(m_ptr)
message *m_ptr; /* request message */
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
int r, type;
size_t len;
if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 1) {
printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
m_ptr->m_source);
return EINVAL;
}
/* Copy name from caller. */
if ((r=sys_safecopyfrom(m_ptr->m_source,
(cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
(vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, r);
return r;
}
/* Make sure name is 0-terminated. */
key_name[DS_MAX_KEYLEN-1] = '\0';
/* Retrieve data. Look up the key in the data store. Return an error if it
* is not found. If this data is private, only the owner may retrieve it.
*/
type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
if (find_key(key_name, &dsp, type)) { /* look up key */
/* Data is public or the caller is authorized to retrieve it. */
switch(type) {
case DS_TYPE_U32:
m_ptr->DS_VAL = dsp->ds_val.ds_val_u32; /* return value */
break;
case DS_TYPE_STR:
len = strlen(dsp->ds_val.ds_val_str) + 1;
if(len > m_ptr->DS_VAL_LEN)
len = m_ptr->DS_VAL_LEN;
if ((r=sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL,
0, (vir_bytes) dsp->ds_val.ds_val_str,len, D)) != OK) {
printf("DS: retrieve: copy failed to %d: %d\n",
m_ptr->m_source, r);
return r;
}
break;
default:
panic(__FILE__, "retrieve: impossible type.", type);
/* not reached. */
break;
}
return(OK); /* report success */
}
return(ESRCH); /* key not found */
}
/*===========================================================================*
* do_check *
*===========================================================================*/
PUBLIC int do_check(m_ptr)
message *m_ptr; /* request message */
{
/* This routine goes through all subscriptions for a client,
* and checks all data items if it has been flagged (i.e.,
* created or updated) matching that subscription. Return
* a message and copy the key and value for every one.
*/
struct data_store *dsp;
int r, s, d, type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
if(!type) return EINVAL;
for(s = 0; s < NR_DS_SUBS; s++) {
int len;
if(!(ds_subs[s].sub_flags & DS_IN_USE))
continue;
if(m_ptr->m_source != ds_subs[s].sub_owner)
continue;
for(d = 0; d < NR_DS_KEYS; d++) {
/* No match if this is no value, it's
* not flagged, or the type is wrong.
*/
if(!(ds_store[d].ds_flags & DS_IN_USE))
continue;
if(!GET_BIT(ds_store[d].ds_old_subs, s))
continue;
if(type != (ds_store[d].ds_flags & DS_TYPE_MASK))
continue;
/* We have a match. Unflag it for this
* subscription.
*/
UNSET_BIT(ds_store[d].ds_old_subs, s);
len = strlen(ds_store[d].ds_key)+1;
if(len > m_ptr->DS_KEY_LEN)
len = m_ptr->DS_KEY_LEN;
/* Copy the key into client. */
if ((r=sys_safecopyto(m_ptr->m_source,
(cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
(vir_bytes) ds_store[d].ds_key,
len, D)) != OK)
return r;
/* Now copy the value. */
switch(type) {
case DS_TYPE_STR:
len = strlen(ds_store[d].
ds_val.ds_val_str)+1;
if(len > m_ptr->DS_VAL_LEN)
len = m_ptr->DS_VAL_LEN;
if ((r=sys_safecopyto(m_ptr->m_source,
m_ptr->DS_VAL, 0,
(vir_bytes) ds_store[d].
ds_val.ds_val_str,
len, D)) != OK)
return r;
break;
case DS_TYPE_U32:
m_ptr->DS_VAL =
ds_store[d].ds_val.ds_val_u32;
break;
default:
panic(__FILE__,
"Check impossible type.",
type);
}
return OK;
}
}
return(ESRCH); /* key not found */
}
PUBLIC int do_subscribe(m_ptr)
message *m_ptr; /* request message */
{
char regex[DS_MAX_KEYLEN+3];
int s, type, e, d, n = 0;
char errbuf[80];
/* Subscribe to a key of interest.
* All updates to the key will cause a notification message
* to be sent to the subscribed. On success, directly return a copy of the
* data for the given key.
*/
if(m_ptr->DS_KEY_LEN < 2 || m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN)
return EINVAL;
/* Copy name from caller. Anchor the subscription with "^regexp$" so
* substrings don't match. The caller probably will not expect this,
* and the usual case is for a complete match.
*/
regex[0] = '^';
if ((s=sys_safecopyfrom(m_ptr->m_source,
(cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
(vir_bytes) regex + 1, m_ptr->DS_KEY_LEN, D)) != OK) {
printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, s);
return s;
}
regex[DS_MAX_KEYLEN-1] = '\0';
strcat(regex, "$");
/* Find subscription slot. */
for(s = 0; s < NR_DS_SUBS; s++)
if(!(ds_subs[s].sub_flags & DS_IN_USE))
break;
if(s >= NR_DS_SUBS) {
printf("DS: no space for subscription by %d.\n", m_ptr->m_source);
return ENOSPC;
}
/* Compile regular expression. */
if((e=regcomp(&ds_subs[s].sub_regex, regex, REG_EXTENDED)) != 0) {
regerror(e, &ds_subs[s].sub_regex, errbuf, sizeof(errbuf));
printf("DS: subscribe: regerror: %s\n", errbuf);
return EINVAL;
}
type = (m_ptr->DS_FLAGS & DS_TYPE_MASK);
ds_subs[s].sub_flags = DS_IN_USE | type;
ds_subs[s].sub_owner = m_ptr->m_source;
/* Caller requested an instant initial list? */
if(m_ptr->DS_FLAGS & DS_INITIAL) {
for(d = 0; d < NR_DS_KEYS; d++) {
if(!(ds_store[d].ds_flags & DS_IN_USE))
continue;
if(regexec(&ds_subs[s].sub_regex, ds_store[d].ds_key,
0, NULL, 0) == 0) {
SET_BIT(ds_store[d].ds_old_subs, s);
n = 1;
}
}
/* Any matches? */
if(n) notify(ds_subs[s].sub_owner);
}
return OK;
}
/*===========================================================================*
* do_getsysinfo *
*===========================================================================*/
PUBLIC int do_getsysinfo(m_ptr)
message *m_ptr;
{
vir_bytes src_addr, dst_addr;
int dst_proc;
size_t len;
int s;
switch(m_ptr->m1_i1) {
case SI_DATA_STORE:
src_addr = (vir_bytes) ds_store;
len = sizeof(struct data_store) * NR_DS_KEYS;
break;
default:
return(EINVAL);
}
dst_proc = m_ptr->m_source;
dst_addr = (vir_bytes) m_ptr->m1_p1;
if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len))) {
printf("DS: copy failed: %d\n", s);
return(s);
}
return(OK);
}
/*===========================================================================*
* check_subscribers *
*===========================================================================*/
PRIVATE void
check_subscribers(struct data_store *dsp)
{
/* Send subscribers whose subscriptions match this (new
* or updated) data item a notify(), and flag the subscriptions
* as updated.
*/
int i;
for(i = 0; i < NR_DS_SUBS; i++) {
if(ds_subs[i].sub_flags & DS_IN_USE) {
if(regexec(&ds_subs[i].sub_regex, dsp->ds_key,
0, NULL, 0) == 0) {
SET_BIT(dsp->ds_old_subs, i);
notify(ds_subs[i].sub_owner);
} else {
UNSET_BIT(dsp->ds_old_subs, i);
}
}
}
}