From: Jorrit Herder Date: Thu, 20 Oct 2005 20:29:52 +0000 (+0000) Subject: New Data Store server. X-Git-Tag: v3.1.2a~594 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=d1f2ba26b0b9cc1e3283e87883b93089de1a098f;p=minix.git New Data Store server. --- diff --git a/servers/ds/Makefile b/servers/ds/Makefile new file mode 100644 index 000000000..f78e608d7 --- /dev/null +++ b/servers/ds/Makefile @@ -0,0 +1,43 @@ +# Makefile for Data Store Server (DS) +SERVER = ds + +# directories +u = /usr +i = $u/include +s = $i/sys +m = $i/minix +b = $i/ibm +k = $u/src/kernel +p = $u/src/servers/pm +f = $u/src/servers/fs + +# programs, flags, etc. +CC = exec cc +CFLAGS = -I$i +LDFLAGS = -i +LIBS = -lsys -lsysutil + +OBJ = main.o store.o + +# build local binary +all build: $(SERVER) +$(SERVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) +# install -S 256w $@ + +# install with other servers +install: /sbin/$(SERVER) +/sbin/$(SERVER): $(SERVER) + install -o root -c $? $@ +# install -o root -cs $? $@ + +# clean up local files +clean: + rm -f $(SERVER) *.o *.bak + +depend: + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/servers/ds/glo.h b/servers/ds/glo.h new file mode 100644 index 000000000..c500db535 --- /dev/null +++ b/servers/ds/glo.h @@ -0,0 +1,7 @@ +/* Global variables. */ + +/* The parameters of the call are kept here. */ +extern int who; /* caller's proc number */ +extern int callnr; /* system call number */ +extern int dont_reply; /* normally 0; set to 1 to inhibit reply */ + diff --git a/servers/ds/inc.h b/servers/ds/inc.h new file mode 100644 index 000000000..76c97455e --- /dev/null +++ b/servers/ds/inc.h @@ -0,0 +1,30 @@ +/* Header file including all needed system headers. */ + +#define _SYSTEM 1 /* get OK and negative error codes */ +#define _MINIX 1 /* tell headers to include MINIX stuff */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "proto.h" +#include "glo.h" +#include "store.h" + diff --git a/servers/ds/main.c b/servers/ds/main.c new file mode 100644 index 000000000..8963ee3c6 --- /dev/null +++ b/servers/ds/main.c @@ -0,0 +1,135 @@ +/* Data Store Server. + * This service implements a little publish/subscribe data store that is + * crucial for the system's fault tolerance. Components that require state + * can store it here, for later retrieval, e.g., after a crash and subsequent + * restart by the reincarnation server. + * + * Created: + * Oct 19, 2005 by Jorrit N. Herder + */ + +#include "inc.h" /* include master header file */ + +/* Allocate space for the global variables. */ +int who; /* caller's proc number */ +int callnr; /* system call number */ +int sys_panic; /* flag to indicate system-wide panic */ + +extern int errno; /* error number set by system library */ + +/* Declare some local functions. */ +FORWARD _PROTOTYPE(void init_server, (int argc, char **argv) ); +FORWARD _PROTOTYPE(void exit_server, (void) ); +FORWARD _PROTOTYPE(void get_work, (message *m_ptr) ); +FORWARD _PROTOTYPE(void reply, (int whom, message *m_ptr) ); + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC int main(int argc, char **argv) +{ +/* This is the main routine of this service. The main loop consists of + * three major activities: getting new work, processing the work, and + * sending the reply. The loop never terminates, unless a panic occurs. + */ + message m; + int result; + sigset_t sigset; + + /* Initialize the server, then go to work. */ + init_server(argc, argv); + + /* Main loop - get work and do it, forever. */ + while (TRUE) { + + /* Wait for incoming message, sets 'callnr' and 'who'. */ + get_work(&m); + + switch (callnr) { + case SYS_SIG: + sigset = (sigset_t) m.NOTIFY_ARG; + if (sigismember(&sigset,SIGTERM) || sigismember(&sigset,SIGKSTOP)) { + exit_server(); + } + continue; + case DS_PUBLISH: + result = do_publish(&m); + break; + case DS_RETRIEVE: + result = do_retrieve(&m); + break; + case DS_SUBSCRIBE: + result = do_subscribe(&m); + break; + case GETSYSINFO: + result = do_getsysinfo(&m); + break; + default: + report("DS","warning, got illegal request from:", m.m_source); + result = EINVAL; + } + + /* Finally send reply message, unless disabled. */ + if (result != EDONTREPLY) { + m.m_type = result; /* build reply message */ + reply(who, &m); /* send it away */ + } + } + return(OK); /* shouldn't come here */ +} + +/*===========================================================================* + * init_server * + *===========================================================================*/ +PRIVATE void init_server(int argc, char **argv) +{ +/* Initialize the data store server. */ + int i, s; + struct sigaction sigact; + + /* Install signal handler. Ask PM to transform signal into message. */ + sigact.sa_handler = SIG_MESS; + sigact.sa_mask = ~0; /* block all other signals */ + sigact.sa_flags = 0; /* default behaviour */ + if (sigaction(SIGTERM, &sigact, NULL) < 0) + report("DS","warning, sigaction() failed", errno); +} + +/*===========================================================================* + * exit_server * + *===========================================================================*/ +PRIVATE void exit_server() +{ +/* Shut down the information service. */ + + /* Done. Now exit. */ + exit(0); +} + +/*===========================================================================* + * get_work * + *===========================================================================*/ +PRIVATE void get_work(m_ptr) +message *m_ptr; /* message buffer */ +{ + int status = 0; + status = receive(ANY, m_ptr); /* this blocks until message arrives */ + if (OK != status) + panic("DS","failed to receive message!", status); + who = m_ptr->m_source; /* message arrived! set sender */ + callnr = m_ptr->m_type; /* set function call number */ +} + +/*===========================================================================* + * reply * + *===========================================================================*/ +PRIVATE void reply(who, m_ptr) +int who; /* destination */ +message *m_ptr; /* message buffer */ +{ + int s; + s = send(who, m_ptr); /* send the message */ + if (OK != s) + panic("DS", "unable to send reply!", s); +} + diff --git a/servers/ds/proto.h b/servers/ds/proto.h new file mode 100644 index 000000000..cb0a86a94 --- /dev/null +++ b/servers/ds/proto.h @@ -0,0 +1,10 @@ +/* Function prototypes. */ + +/* main.c */ +_PROTOTYPE(int main, (int argc, char **argv)); + +/* store.c */ +_PROTOTYPE(int do_publish, (message *m_ptr)); +_PROTOTYPE(int do_retrieve, (message *m_ptr)); +_PROTOTYPE(int do_subscribe, (message *m_ptr)); +_PROTOTYPE(int do_getsysinfo, (message *m_ptr)); diff --git a/servers/ds/store.c b/servers/ds/store.c new file mode 100644 index 000000000..c557145d4 --- /dev/null +++ b/servers/ds/store.c @@ -0,0 +1,163 @@ +/* Implementation of the Data Store. */ + +#include "inc.h" + +/* Allocate space for the data store. */ +PRIVATE struct data_store ds_store[NR_DS_KEYS]; +PRIVATE int nr_in_use; + +PRIVATE _PROTOTYPE(int find_key, (int key, struct data_store **dsp)); +PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, void *auth_ptr)); +PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, void *auth_ptr)); + + +PRIVATE int set_owner(dsp, ap) +struct data_store *dsp; /* data store structure */ +void *ap; /* authorization pointer */ +{ + /* Authorize the caller. */ + return(TRUE); +} + + +PRIVATE int is_authorized(dsp, ap) +struct data_store *dsp; /* data store structure */ +void *ap; /* authorization pointer */ +{ + /* Authorize the caller. */ + return(TRUE); +} + + +PRIVATE int find_key(key, dsp) +int key; /* key to look up */ +struct data_store **dsp; /* store pointer here */ +{ + register int i; + + *dsp = NULL; + for (i=0; iDS_KEY, &dsp)) { /* look up key */ + if (! is_authorized(dsp,m_ptr->DS_AUTH)) { /* check if owner */ + return(EPERM); + } + } + else { /* find a new slot */ + if (nr_in_use >= NR_DS_KEYS) { + return(EAGAIN); /* store is full */ + } else { + dsp = &ds_store[nr_in_use]; /* new slot found */ + dsp->ds_key = m_ptr->DS_KEY; + if (! set_owner(dsp,m_ptr->DS_AUTH)) { /* associate owner */ + return(EINVAL); + } + dsp->ds_nr_subs = 0; /* nr of subscribers */ + dsp->ds_flags = DS_IN_USE; /* 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. + */ + dsp->ds_val_l1 = m_ptr->DS_VAL_L1; /* store all data */ + dsp->ds_val_l2 = m_ptr->DS_VAL_L2; + + /* If the data is public. Check if there are any subscribers to this key. + * If so, notify all subscribers so that they can retrieve the data, if + * they're still interested. + */ + if ((dsp->ds_flags & DS_PUBLIC) && dsp->ds_nr_subs > 0) { + + /* Subscriptions are not yet implemented. */ + } + + return(OK); +} + + +PUBLIC int do_retrieve(m_ptr) +message *m_ptr; /* request message */ +{ + struct data_store *dsp; + + /* 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. + */ + if (find_key(m_ptr->DS_KEY, &dsp)) { /* look up key */ + + /* If the data is not public, the caller must be authorized. */ + if (! dsp->ds_flags & DS_PUBLIC) { /* check if private */ + if (! is_authorized(dsp,m_ptr->DS_AUTH)) { /* authorize call */ + return(EPERM); /* not allowed */ + } + } + + /* Data is public or the caller is authorized to retrieve it. */ + printf("DS retrieves data: key %d (found %d), l1 %u, l2 %u\n", + m_ptr->DS_KEY, dsp->ds_key, dsp->ds_val_l1, dsp->ds_val_l2); + m_ptr->DS_VAL_L1 = dsp->ds_val_l1; /* return value */ + m_ptr->DS_VAL_L2 = dsp->ds_val_l2; /* return value */ + return(OK); /* report success */ + } + return(ESRCH); /* key not found */ +} + + +PUBLIC int do_subscribe(m_ptr) +message *m_ptr; /* request message */ +{ + /* Subscribe to a key of interest. Only existing and public keys can be + * subscribed to. 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. + */ + return(ENOSYS); +} + + +/*===========================================================================* + * 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))) + return(s); + return(OK); +} + diff --git a/servers/ds/store.h b/servers/ds/store.h new file mode 100644 index 000000000..7194318d8 --- /dev/null +++ b/servers/ds/store.h @@ -0,0 +1,19 @@ +/* Type definitions for the Data Store Server. */ +struct data_store { + int ds_flags; /* flags for this store */ + int ds_key; /* key to lookup information */ + long ds_val_l1; /* data associated with key */ + long ds_val_l2; /* data associated with key */ + long ds_auth; /* secret given by owner of data */ + int ds_nr_subs; /* number of subscribers for key */ +}; + +/* Flag values. */ +#define DS_IN_USE 0x01 +#define DS_PUBLIC 0x02 + +/* Constants for the Data Store Server. */ +#define NR_DS_KEYS 64 /* reserve space for so many items */ + + +