minix/lib/libsys/ds.c
Cristiano Giuffrida 48c6bb79f4 Driver refactory for live update and crash recovery.
SYSLIB CHANGES:
- DS calls to publish / retrieve labels consider endpoints instead of u32_t.

VFS CHANGES:
- mapdriver() only adds an entry in the dmap table in VFS.
- dev_up() is only executed upon reception of a driver up event.

INET CHANGES:
- INET no longer searches for existing drivers instances at startup.
- A newtwork driver is (re)initialized upon reception of a driver up event.
- Networking startup is now race-free by design. No need to waste 5 seconds
at startup any more.

DRIVER CHANGES:
- Every driver publishes driver up events when starting for the first time or
in case of restart when recovery actions must be taken in the upper layers.
- Driver up events are published by drivers through DS. 
- For regular drivers, VFS is normally the only subscriber, but not necessarily.
For instance, when the filter driver is in use, it must subscribe to driver
up events to initiate recovery.
- For network drivers, inet is the only subscriber for now.
- Every VFS driver is statically linked with libdriver, every network driver
is statically linked with libnetdriver.

DRIVER LIBRARIES CHANGES:
- Libdriver is extended to provide generic receive() and ds_publish() interfaces
for VFS drivers.
- driver_receive() is a wrapper for sef_receive() also used in driver_task()
to discard spurious messages that were meant to be delivered to a previous
version of the driver.
- driver_receive_mq() is the same as driver_receive() but integrates support
for queued messages.
- driver_announce() publishes a driver up event for VFS drivers and marks
the driver as initialized and expecting a DEV_OPEN message.
- Libnetdriver is introduced to provide similar receive() and ds_publish()
interfaces for network drivers (netdriver_announce() and netdriver_receive()).
- Network drivers all support live update with no state transfer now.

KERNEL CHANGES:
- Added kernel call statectl for state management. Used by driver_announce() to
unblock eventual callers sendrecing to the driver.
2010-04-08 13:41:35 +00:00

270 lines
5.7 KiB
C

#include <minix/ds.h>
#include <string.h>
#include "syslib.h"
static message m;
PRIVATE int do_invoke_ds(int type, const char *ds_name)
{
cp_grant_id_t g_key;
size_t len_key;
int access, r;
if(type == DS_CHECK || type == DS_RETRIEVE_LABEL) {
len_key = DS_MAX_KEYLEN;
access = CPF_WRITE;
} else {
len_key = strlen(ds_name)+1;
access = CPF_READ;
}
/* Grant for key. */
g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name,
len_key, access);
if(!GRANT_VALID(g_key))
return errno;
m.DS_KEY_GRANT = g_key;
m.DS_KEY_LEN = len_key;
r = _taskcall(DS_PROC_NR, type, &m);
cpf_revoke(g_key);
return r;
}
int ds_publish_label(const char *ds_name, endpoint_t endpoint, int flags)
{
m.DS_VAL = (u32_t) endpoint;
m.DS_FLAGS = DSF_TYPE_LABEL | flags;
return do_invoke_ds(DS_PUBLISH, ds_name);
}
int ds_publish_u32(const char *ds_name, u32_t value, int flags)
{
m.DS_VAL = value;
m.DS_FLAGS = DSF_TYPE_U32 | flags;
return do_invoke_ds(DS_PUBLISH, ds_name);
}
static int ds_publish_raw(const char *ds_name, void *vaddr, size_t length,
int flags)
{
cp_grant_id_t gid;
int r;
/* Grant for memory range. */
gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length, CPF_READ);
if(!GRANT_VALID(gid))
return errno;
m.DS_VAL = gid;
m.DS_VAL_LEN = length;
m.DS_FLAGS = flags;
r = do_invoke_ds(DS_PUBLISH, ds_name);
cpf_revoke(gid);
return r;
}
int ds_publish_str(const char *ds_name, char *value, int flags)
{
size_t length;
length = strlen(value) + 1;
value[length - 1] = '\0';
return ds_publish_raw(ds_name, value, length, flags | DSF_TYPE_STR);
}
int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
{
return ds_publish_raw(ds_name, vaddr, length, flags | DSF_TYPE_MEM);
}
int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags)
{
cp_grant_id_t gid;
int r;
if(((vir_bytes)vaddr % CLICK_SIZE != 0) || (length % CLICK_SIZE != 0))
return EINVAL;
/* Grant for mapped memory range. */
gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length,
CPF_READ | CPF_MAP);
if(!GRANT_VALID(gid))
return errno;
m.DS_VAL = gid;
m.DS_VAL_LEN = length;
m.DS_FLAGS = DSF_TYPE_MAP | flags;
r = do_invoke_ds(DS_PUBLISH, ds_name);
return r;
}
int ds_snapshot_map(const char *ds_name, int *nr_snapshot)
{
int r;
r = do_invoke_ds(DS_SNAPSHOT, ds_name);
*nr_snapshot = m.DS_NR_SNAPSHOT;
return r;
}
int ds_retrieve_label_name(char *ds_name, endpoint_t endpoint)
{
int r;
m.DS_VAL = (u32_t) endpoint;
r = do_invoke_ds(DS_RETRIEVE_LABEL, ds_name);
return r;
}
int ds_retrieve_label_endpt(const char *ds_name, endpoint_t *endpoint)
{
int r;
m.DS_FLAGS = DSF_TYPE_LABEL;
r = do_invoke_ds(DS_RETRIEVE, ds_name);
*endpoint = (endpoint_t) m.DS_VAL;
return r;
}
int ds_retrieve_u32(const char *ds_name, u32_t *value)
{
int r;
m.DS_FLAGS = DSF_TYPE_U32;
r = do_invoke_ds(DS_RETRIEVE, ds_name);
*value = m.DS_VAL;
return r;
}
static int ds_retrieve_raw(const char *ds_name, char *vaddr, size_t *length,
int flags)
{
cp_grant_id_t gid;
int r;
/* Grant for memory range. */
gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, *length, CPF_WRITE);
if(!GRANT_VALID(gid))
return errno;
m.DS_VAL = gid;
m.DS_VAL_LEN = *length;
m.DS_FLAGS = flags;
r = do_invoke_ds(DS_RETRIEVE, ds_name);
*length = m.DS_VAL_LEN;
cpf_revoke(gid);
return r;
}
int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
{
int r;
size_t length = len_str + 1;
r = ds_retrieve_raw(ds_name, value, &length, DSF_TYPE_STR);
value[length - 1] = '\0';
return r;
}
int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
{
return ds_retrieve_raw(ds_name, vaddr, length, DSF_TYPE_MEM);
}
int ds_retrieve_map(const char *ds_name, char *vaddr, size_t *length,
int nr_snapshot, int flags)
{
cp_grant_id_t gid;
int r;
/* Map a mapped memory range. */
if(flags & DSMF_MAP_MAPPED) {
/* Request DS to grant. */
m.DS_FLAGS = DSF_TYPE_MAP | DSMF_MAP_MAPPED;
r = do_invoke_ds(DS_RETRIEVE, ds_name);
if(r != OK)
return r;
/* Do the safemap. */
if(*length > (size_t) m.DS_VAL_LEN)
*length = (size_t) m.DS_VAL_LEN;
*length = (size_t) CLICK_FLOOR(*length);
r = sys_safemap(DS_PROC_NR, m.DS_VAL, 0,
(vir_bytes)vaddr, *length, D, 0);
/* Copy mapped memory range or a snapshot. */
} else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
/* Grant for memory range first. */
gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr,
*length, CPF_WRITE);
if(!GRANT_VALID(gid))
return errno;
m.DS_VAL = gid;
m.DS_VAL_LEN = *length;
if(flags & DSMF_COPY_MAPPED) {
m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_MAPPED;
}
else {
m.DS_NR_SNAPSHOT = nr_snapshot;
m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_SNAPSHOT;
}
r = do_invoke_ds(DS_RETRIEVE, ds_name);
*length = m.DS_VAL_LEN;
cpf_revoke(gid);
}
else {
return EINVAL;
}
return r;
}
int ds_delete_u32(const char *ds_name)
{
m.DS_FLAGS = DSF_TYPE_U32;
return do_invoke_ds(DS_DELETE, ds_name);
}
int ds_delete_str(const char *ds_name)
{
m.DS_FLAGS = DSF_TYPE_STR;
return do_invoke_ds(DS_DELETE, ds_name);
}
int ds_delete_mem(const char *ds_name)
{
m.DS_FLAGS = DSF_TYPE_MEM;
return do_invoke_ds(DS_DELETE, ds_name);
}
int ds_delete_map(const char *ds_name)
{
m.DS_FLAGS = DSF_TYPE_MAP;
return do_invoke_ds(DS_DELETE, ds_name);
}
int ds_delete_label(const char *ds_name)
{
m.DS_FLAGS = DSF_TYPE_LABEL;
return do_invoke_ds(DS_DELETE, ds_name);
}
int ds_subscribe(const char *regexp, int flags)
{
m.DS_FLAGS = flags;
return do_invoke_ds(DS_SUBSCRIBE, regexp);
}
int ds_check(char *ds_key, int *type, endpoint_t *owner_e)
{
int r;
r = do_invoke_ds(DS_CHECK, ds_key);
if(type) *type = m.DS_FLAGS;
if(owner_e) *owner_e = m.DS_OWNER;
return r;
}