rs: New RS.
Change-Id: I46e335d5dac49104028d7cb0706b3e85de752bfe
This commit is contained in:
parent
d196e2c333
commit
fb6bd596bf
14 changed files with 2424 additions and 566 deletions
|
@ -55,6 +55,8 @@ disabled()
|
||||||
exec > /dev/console
|
exec > /dev/console
|
||||||
echo "Arguments: $@"
|
echo "Arguments: $@"
|
||||||
|
|
||||||
|
restarts=$(grep restarts /proc/service/$1 |cut -d: -f2)
|
||||||
|
restarts=$(( $restarts + 1 ))
|
||||||
service down "$1"
|
service down "$1"
|
||||||
kill_by_name dhcpd
|
kill_by_name dhcpd
|
||||||
kill_by_name nonamed
|
kill_by_name nonamed
|
||||||
|
@ -64,10 +66,10 @@ kill_by_name syslogd
|
||||||
sleep 3
|
sleep 3
|
||||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||||
then
|
then
|
||||||
service up /service/lwip -script /etc/rs.inet -dev /dev/ip
|
service up /service/lwip -script /etc/rs.inet -dev /dev/ip -restarts $restarts
|
||||||
dhcpd --lwip &
|
dhcpd --lwip &
|
||||||
else
|
else
|
||||||
service up /service/inet -script /etc/rs.inet -dev /dev/ip
|
service up /service/inet -script /etc/rs.inet -dev /dev/ip -restarts $restarts
|
||||||
daemonize dhcpd
|
daemonize dhcpd
|
||||||
fi
|
fi
|
||||||
daemonize nonamed -L
|
daemonize nonamed -L
|
||||||
|
|
|
@ -84,7 +84,8 @@ static int known_request_types[] = {
|
||||||
#define OPT_REUSE "-r" /* reuse executable image */
|
#define OPT_REUSE "-r" /* reuse executable image */
|
||||||
#define OPT_NOBLOCK "-n" /* unblock caller immediately */
|
#define OPT_NOBLOCK "-n" /* unblock caller immediately */
|
||||||
#define OPT_REPLICA "-p" /* create replica for the service */
|
#define OPT_REPLICA "-p" /* create replica for the service */
|
||||||
#define OPT_BATCH "-b" /* batch mode */
|
#define OPT_NO_BIN_EXP "-b" /* no binary exponential backoff */
|
||||||
|
#define OPT_BATCH "-q" /* batch mode */
|
||||||
#define OPT_ASR_LU "-a" /* asr update */
|
#define OPT_ASR_LU "-a" /* asr update */
|
||||||
#define OPT_PREPARE_ONLY_LU "-o" /* prepare-only update */
|
#define OPT_PREPARE_ONLY_LU "-o" /* prepare-only update */
|
||||||
#define OPT_FORCE_SELF_LU "-s" /* force self update */
|
#define OPT_FORCE_SELF_LU "-s" /* force self update */
|
||||||
|
@ -134,6 +135,7 @@ static int known_request_types[] = {
|
||||||
#define ARG_TRG_LABELNAME "-trg-label" /* target label name */
|
#define ARG_TRG_LABELNAME "-trg-label" /* target label name */
|
||||||
#define ARG_LU_IPC_BL "-ipc_bl" /* IPC blacklist filter */
|
#define ARG_LU_IPC_BL "-ipc_bl" /* IPC blacklist filter */
|
||||||
#define ARG_LU_IPC_WL "-ipc_wl" /* IPC whitelist filter */
|
#define ARG_LU_IPC_WL "-ipc_wl" /* IPC whitelist filter */
|
||||||
|
#define ARG_RESTARTS "-restarts" /* number of restarts */
|
||||||
|
|
||||||
/* The function parse_arguments() verifies and parses the command line
|
/* The function parse_arguments() verifies and parses the command line
|
||||||
* parameters passed to this utility. Request parameters that are needed
|
* parameters passed to this utility. Request parameters that are needed
|
||||||
|
@ -154,6 +156,7 @@ static char *req_config = PATH_CONFIG;
|
||||||
static int custom_config_file = 0;
|
static int custom_config_file = 0;
|
||||||
static int req_lu_state = DEFAULT_LU_STATE;
|
static int req_lu_state = DEFAULT_LU_STATE;
|
||||||
static int req_lu_maxtime = DEFAULT_LU_MAXTIME;
|
static int req_lu_maxtime = DEFAULT_LU_MAXTIME;
|
||||||
|
static int req_restarts = 0;
|
||||||
static long req_heap_prealloc = 0;
|
static long req_heap_prealloc = 0;
|
||||||
static long req_map_prealloc = 0;
|
static long req_map_prealloc = 0;
|
||||||
static int req_sysctl_type = 0;
|
static int req_sysctl_type = 0;
|
||||||
|
@ -171,15 +174,16 @@ static void print_usage(char *app_name, char *problem)
|
||||||
fprintf(stderr, "Warning, %s\n", problem);
|
fprintf(stderr, "Warning, %s\n", problem);
|
||||||
fprintf(stderr, "Usage:\n");
|
fprintf(stderr, "Usage:\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" %s [%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <major_nr>] [%s <dev_id>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state value|eval_expression>] [%s <time>] [%s <bytes>] [%s <bytes>] [%s <name>] [(%s|%s <src_label1,src_type1:src_label2,:,src_type3:...>)*]\n",
|
" %s [%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <major_nr>] [%s <dev_id>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state value|eval_expression>] [%s <time>] [%s <bytes>] [%s <bytes>] [%s <name>] [(%s|%s <src_label1,src_type1:src_label2,:,src_type3:...>)*] [%s <restarts>]\n",
|
||||||
app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA,
|
app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA, OPT_NO_BIN_EXP,
|
||||||
OPT_BATCH, OPT_ASR_LU, OPT_PREPARE_ONLY_LU, OPT_FORCE_SELF_LU,
|
OPT_BATCH, OPT_ASR_LU, OPT_PREPARE_ONLY_LU, OPT_FORCE_SELF_LU,
|
||||||
OPT_FORCE_INIT_CRASH, OPT_FORCE_INIT_FAIL, OPT_FORCE_INIT_TIMEOUT,
|
OPT_FORCE_INIT_CRASH, OPT_FORCE_INIT_FAIL, OPT_FORCE_INIT_TIMEOUT,
|
||||||
OPT_FORCE_INIT_DEFCB, OPT_UNSAFE_LU, OPT_NOMMAP_LU, OPT_DETACH,
|
OPT_FORCE_INIT_DEFCB, OPT_UNSAFE_LU, OPT_NOMMAP_LU, OPT_DETACH,
|
||||||
OPT_NORESTART, OPT_FORCE_INIT_ST, SELF_BINARY,
|
OPT_NORESTART, OPT_FORCE_INIT_ST, SELF_BINARY,
|
||||||
ARG_ARGS, ARG_DEV, ARG_MAJOR, ARG_DEVMANID, ARG_PERIOD,
|
ARG_ARGS, ARG_DEV, ARG_MAJOR, ARG_DEVMANID, ARG_PERIOD,
|
||||||
ARG_SCRIPT, ARG_LABELNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME,
|
ARG_SCRIPT, ARG_LABELNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME,
|
||||||
ARG_HEAP_PREALLOC, ARG_MAP_PREALLOC, ARG_TRG_LABELNAME, ARG_LU_IPC_BL, ARG_LU_IPC_WL);
|
ARG_HEAP_PREALLOC, ARG_MAP_PREALLOC, ARG_TRG_LABELNAME, ARG_LU_IPC_BL, ARG_LU_IPC_WL,
|
||||||
|
ARG_RESTARTS);
|
||||||
fprintf(stderr, " %s down <label>\n", app_name);
|
fprintf(stderr, " %s down <label>\n", app_name);
|
||||||
fprintf(stderr, " %s refresh <label>\n", app_name);
|
fprintf(stderr, " %s refresh <label>\n", app_name);
|
||||||
fprintf(stderr, " %s restart <label>\n", app_name);
|
fprintf(stderr, " %s restart <label>\n", app_name);
|
||||||
|
@ -627,6 +631,14 @@ static int parse_arguments(int argc, char **argv, u32_t *rss_flags)
|
||||||
exit(r);
|
exit(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(argv[i], ARG_RESTARTS)==0) {
|
||||||
|
errno=0;
|
||||||
|
req_restarts = strtol(argv[i+1], &buff, 10);
|
||||||
|
if(errno || strcmp(buff, "") || req_restarts<0) {
|
||||||
|
print_usage(argv[ARG_NAME], "bad number of restarts");
|
||||||
|
exit(EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
print_usage(argv[ARG_NAME], "unknown optional argument given");
|
print_usage(argv[ARG_NAME], "unknown optional argument given");
|
||||||
exit(EINVAL);
|
exit(EINVAL);
|
||||||
|
@ -726,6 +738,8 @@ int main(int argc, char **argv)
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
if(!parse_config(progname, custom_config_file, req_config, &config))
|
if(!parse_config(progname, custom_config_file, req_config, &config))
|
||||||
errx(1, "couldn't parse config");
|
errx(1, "couldn't parse config");
|
||||||
|
assert(config.rs_start.rss_priority < NR_SCHED_QUEUES);
|
||||||
|
assert(config.rs_start.rss_quantum > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set specifics */
|
/* Set specifics */
|
||||||
|
@ -734,6 +748,7 @@ int main(int argc, char **argv)
|
||||||
config.rs_start.rss_major= req_major;
|
config.rs_start.rss_major= req_major;
|
||||||
config.rs_start.rss_period= req_period;
|
config.rs_start.rss_period= req_period;
|
||||||
config.rs_start.rss_script= req_script;
|
config.rs_start.rss_script= req_script;
|
||||||
|
config.rs_start.rss_restarts= req_restarts;
|
||||||
config.rs_start.devman_id= devman_id;
|
config.rs_start.devman_id= devman_id;
|
||||||
config.rs_start.rss_heap_prealloc_bytes= req_heap_prealloc;
|
config.rs_start.rss_heap_prealloc_bytes= req_heap_prealloc;
|
||||||
config.rs_start.rss_map_prealloc_bytes= req_map_prealloc;
|
config.rs_start.rss_map_prealloc_bytes= req_map_prealloc;
|
||||||
|
@ -757,9 +772,6 @@ int main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
config.rs_start.rss_scriptlen= 0;
|
config.rs_start.rss_scriptlen= 0;
|
||||||
|
|
||||||
assert(config.rs_start.rss_priority < NR_SCHED_QUEUES);
|
|
||||||
assert(config.rs_start.rss_quantum > 0);
|
|
||||||
|
|
||||||
/* State-related data. */
|
/* State-related data. */
|
||||||
config.rs_start.rss_state_data.size =
|
config.rs_start.rss_state_data.size =
|
||||||
sizeof(config.rs_start.rss_state_data);
|
sizeof(config.rs_start.rss_state_data);
|
||||||
|
|
|
@ -114,6 +114,7 @@ struct rs_start
|
||||||
long rss_period;
|
long rss_period;
|
||||||
char *rss_script;
|
char *rss_script;
|
||||||
size_t rss_scriptlen;
|
size_t rss_scriptlen;
|
||||||
|
long rss_restarts;
|
||||||
long rss_heap_prealloc_bytes;
|
long rss_heap_prealloc_bytes;
|
||||||
long rss_map_prealloc_bytes;
|
long rss_map_prealloc_bytes;
|
||||||
int rss_nr_irq;
|
int rss_nr_irq;
|
||||||
|
@ -191,9 +192,10 @@ struct rprocpub {
|
||||||
#define SF_USE_SCRIPT 0x200 /* set when process has restart script */
|
#define SF_USE_SCRIPT 0x200 /* set when process has restart script */
|
||||||
#define SF_DET_RESTART 0x400 /* set when process detaches on restart */
|
#define SF_DET_RESTART 0x400 /* set when process detaches on restart */
|
||||||
#define SF_NORESTART 0x800 /* set when process should not be restarted */
|
#define SF_NORESTART 0x800 /* set when process should not be restarted */
|
||||||
|
#define SF_NO_BIN_EXP 0x1000 /* set when we should ignore binary exp. offset */
|
||||||
|
|
||||||
#define IMM_SF \
|
#define IMM_SF \
|
||||||
(SF_CORE_SRV | SF_SYNCH_BOOT | SF_NEED_COPY | SF_NEED_REPL) /* immutable */
|
(SF_NO_BIN_EXP | SF_CORE_SRV | SF_SYNCH_BOOT | SF_NEED_COPY | SF_NEED_REPL) /* immutable */
|
||||||
|
|
||||||
int minix_rs_lookup(const char *name, endpoint_t *value);
|
int minix_rs_lookup(const char *name, endpoint_t *value);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
# Makefile for Reincarnation Server (RS)
|
# Makefile for Reincarnation Server (RS)
|
||||||
PROG= rs
|
PROG= rs
|
||||||
SRCS= exec.c main.c request.c manager.c table.c utility.c error.c
|
SRCS= exec.c main.c request.c manager.c table.c utility.c error.c update.c
|
||||||
|
|
||||||
|
.if ${USE_PCI} != "no"
|
||||||
|
CPPFLAGS+= -DUSE_PCI
|
||||||
|
.endif
|
||||||
|
|
||||||
.if ${USE_PCI} != "no"
|
.if ${USE_PCI} != "no"
|
||||||
CPPFLAGS+= -DUSE_PCI
|
CPPFLAGS+= -DUSE_PCI
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define MAX_IPC_LIST 256 /* Max size of list for IPC target
|
#define MAX_IPC_LIST 256 /* Max size of list for IPC target
|
||||||
* process names
|
* process names
|
||||||
*/
|
*/
|
||||||
|
#define MAX_DET_RESTART 10 /* maximum number of detached restarts. */
|
||||||
|
|
||||||
/* Flag values. */
|
/* Flag values. */
|
||||||
#define RS_IN_USE 0x001 /* set when process slot is in use */
|
#define RS_IN_USE 0x001 /* set when process slot is in use */
|
||||||
|
@ -32,17 +33,16 @@
|
||||||
#define RS_LATEREPLY 0x020 /* no reply sent to RS_DOWN caller yet */
|
#define RS_LATEREPLY 0x020 /* no reply sent to RS_DOWN caller yet */
|
||||||
#define RS_INITIALIZING 0x040 /* set when init is in progress */
|
#define RS_INITIALIZING 0x040 /* set when init is in progress */
|
||||||
#define RS_UPDATING 0x080 /* set when update is in progress */
|
#define RS_UPDATING 0x080 /* set when update is in progress */
|
||||||
#define RS_ACTIVE 0x100 /* set for the active instance of a service */
|
#define RS_PREPARE_DONE 0x100 /* set when updating and preparation is done */
|
||||||
#define RS_REINCARNATE 0x200 /* after exit, restart with a new endpoint */
|
#define RS_INIT_DONE 0x200 /* set when updating and init is done */
|
||||||
|
#define RS_INIT_PENDING 0x400 /* set when updating and init is pending */
|
||||||
|
#define RS_ACTIVE 0x800 /* set for the active instance of a service */
|
||||||
|
#define RS_DEAD 0x1000 /* set for an instance ready to be cleaned up */
|
||||||
|
#define RS_CLEANUP_DETACH 0x2000 /* detach at cleanup time */
|
||||||
|
#define RS_CLEANUP_SCRIPT 0x4000 /* run script at cleanup time */
|
||||||
|
#define RS_REINCARNATE 0x8000 /* after exit, restart with a new endpoint */
|
||||||
|
|
||||||
/* Sys flag values. */
|
#define RS_SRV_IS_IDLE(S) (((S)->r_flags & RS_DEAD) || ((S)->r_flags & ~(RS_IN_USE|RS_ACTIVE|RS_CLEANUP_DETACH|RS_CLEANUP_SCRIPT)) == 0)
|
||||||
#define SF_CORE_SRV 0x001 /* set for core system services */
|
|
||||||
#define SF_SYNCH_BOOT 0X002 /* set when process needs synch boot init */
|
|
||||||
#define SF_NEED_COPY 0x004 /* set when process needs copy to start */
|
|
||||||
#define SF_USE_COPY 0x008 /* set when process has a copy in memory */
|
|
||||||
#define SF_NEED_REPL 0x010 /* set when process needs replica to start */
|
|
||||||
#define SF_USE_REPL 0x020 /* set when process has a replica */
|
|
||||||
#define SF_NO_BIN_EXP 0x040 /* set when we should ignore binary exp. offset */
|
|
||||||
|
|
||||||
/* Constants determining RS period and binary exponential backoff. */
|
/* Constants determining RS period and binary exponential backoff. */
|
||||||
#define RS_INIT_T (system_hz * 10) /* allow T ticks for init */
|
#define RS_INIT_T (system_hz * 10) /* allow T ticks for init */
|
||||||
|
@ -56,8 +56,6 @@
|
||||||
|
|
||||||
/* Constants for live update. */
|
/* Constants for live update. */
|
||||||
#define RS_DEFAULT_PREPARE_MAXTIME 2*RS_DELTA_T /* default prepare max time */
|
#define RS_DEFAULT_PREPARE_MAXTIME 2*RS_DELTA_T /* default prepare max time */
|
||||||
#define RS_MAX_PREPARE_MAXTIME 20*RS_DELTA_T /* max prepare max time */
|
|
||||||
|
|
||||||
|
|
||||||
/* Definitions for boot info tables. */
|
/* Definitions for boot info tables. */
|
||||||
#define NULL_BOOT_NR NR_BOOT_PROCS /* marks a null boot entry */
|
#define NULL_BOOT_NR NR_BOOT_PROCS /* marks a null boot entry */
|
||||||
|
@ -75,10 +73,54 @@
|
||||||
/* Reply flags. */
|
/* Reply flags. */
|
||||||
#define RS_DONTREPLY 0
|
#define RS_DONTREPLY 0
|
||||||
#define RS_REPLY 1
|
#define RS_REPLY 1
|
||||||
|
#define RS_CANCEL 2
|
||||||
|
|
||||||
/* Swap flags. */
|
/* Swap flags. */
|
||||||
#define RS_DONTSWAP 0
|
#define RS_DONTSWAP 0
|
||||||
#define RS_SWAP 1
|
#define RS_SWAP 1
|
||||||
|
|
||||||
|
/* Configuration constants */
|
||||||
|
#define RS_VM_DEFAULT_MAP_PREALLOC_LEN (1024*1024*8)
|
||||||
|
#define RS_USE_PAGING 0
|
||||||
|
|
||||||
|
/* Update macros. */
|
||||||
|
#define RUPDATE_INIT() memset(&rupdate, 0, sizeof(rupdate))
|
||||||
|
#define RUPDATE_CLEAR() RUPDATE_INIT()
|
||||||
|
|
||||||
|
#define RUPDATE_ITER(HEAD, RPUPD_PREV, RPUPD, B) do { \
|
||||||
|
RPUPD = HEAD; \
|
||||||
|
RPUPD_PREV = NULL; \
|
||||||
|
while(RPUPD) { \
|
||||||
|
B \
|
||||||
|
RPUPD_PREV = RPUPD; \
|
||||||
|
RPUPD = RPUPD->next_rpupd; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#define RUPDATE_REV_ITER(TAIL, RPUPD_PREV, RPUPD, B) do { \
|
||||||
|
RPUPD = TAIL; \
|
||||||
|
while(RPUPD) { \
|
||||||
|
RPUPD_PREV = RPUPD->prev_rpupd; \
|
||||||
|
B \
|
||||||
|
RPUPD = RPUPD->prev_rpupd; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define RUPDATE_IS_UPDATING() (rupdate.flags & RS_UPDATING)
|
||||||
|
#define RUPDATE_IS_VM_UPDATING() ((rupdate.flags & RS_UPDATING) && rupdate.vm_rpupd)
|
||||||
|
#define RUPDATE_IS_VM_INIT_DONE() (rproc_ptr[_ENDPOINT_P(VM_PROC_NR)]->r_flags & RS_INIT_DONE)
|
||||||
|
#define RUPDATE_IS_RS_UPDATING() ((rupdate.flags & RS_UPDATING) && rupdate.rs_rpupd)
|
||||||
|
#define RUPDATE_IS_RS_INIT_DONE() (rproc_ptr[_ENDPOINT_P(RS_PROC_NR)]->r_flags & RS_INIT_DONE)
|
||||||
|
#define RUPDATE_IS_INITIALIZING() (rupdate.flags & RS_INITIALIZING)
|
||||||
|
#define RUPDATE_IS_UPD_SCHEDULED() (rupdate.num_rpupds > 0 && !RUPDATE_IS_UPDATING())
|
||||||
|
#define RUPDATE_IS_UPD_MULTI() (rupdate.num_rpupds > 1)
|
||||||
|
#define RUPDATE_IS_UPD_VM_MULTI() (rupdate.vm_rpupd && RUPDATE_IS_UPD_MULTI())
|
||||||
|
#define SRV_IS_UPDATING(RP) ((RP)->r_flags & RS_UPDATING)
|
||||||
|
#define SRV_IS_UPDATING_AND_INITIALIZING(RP) (((RP)->r_flags & (RS_UPDATING|RS_INITIALIZING)) == (RS_UPDATING|RS_INITIALIZING))
|
||||||
|
#define UPD_INIT_MAXTIME(RPUPD) ((RPUPD)->prepare_maxtime != RS_DEFAULT_PREPARE_MAXTIME ? (RPUPD)->prepare_maxtime : RS_INIT_T)
|
||||||
|
#define UPD_IS_PREPARING_ONLY(RPUPD) ((RPUPD)->lu_flags & SEF_LU_PREPARE_ONLY)
|
||||||
|
#define SRV_IS_PREPARING_ONLY(RP) ((RP)->r_upd.rp && UPD_IS_PREPARING_ONLY(&(RP)->r_upd))
|
||||||
|
#define UPD_IS_UPD_SCHEDULED(RPUPD) (RUPDATE_IS_UPD_SCHEDULED() && (RPUPD)->rp)
|
||||||
|
#define SRV_IS_UPD_SCHEDULED(RP) UPD_IS_UPD_SCHEDULED(&(RP)->r_upd)
|
||||||
|
|
||||||
#endif /* RS_CONST_H */
|
#endif /* RS_CONST_H */
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ struct errentry {
|
||||||
|
|
||||||
/* Initialization errors. */
|
/* Initialization errors. */
|
||||||
static struct errentry init_errlist[] = {
|
static struct errentry init_errlist[] = {
|
||||||
{ ENOSYS, "service does not support the requested initialization type" }
|
{ ENOSYS, "service does not support the requested initialization type" },
|
||||||
|
{ ERESTART, "service requested an initialization reset" }
|
||||||
};
|
};
|
||||||
static const int init_nerr = sizeof(init_errlist) / sizeof(init_errlist[0]);
|
static const int init_nerr = sizeof(init_errlist) / sizeof(init_errlist[0]);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@ static void get_work(message *m_ptr, int *status_ptr);
|
||||||
/* SEF functions and variables. */
|
/* SEF functions and variables. */
|
||||||
static void sef_local_startup(void);
|
static void sef_local_startup(void);
|
||||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
||||||
|
static int sef_cb_init_restart(int type, sef_init_info_t *info);
|
||||||
|
static int sef_cb_init_lu(int type, sef_init_info_t *info);
|
||||||
|
static int sef_cb_init_response(message *m_ptr);
|
||||||
|
static int sef_cb_lu_response(message *m_ptr);
|
||||||
static void sef_cb_signal_handler(int signo);
|
static void sef_cb_signal_handler(int signo);
|
||||||
static int sef_cb_signal_manager(endpoint_t target, int signo);
|
static int sef_cb_signal_manager(endpoint_t target, int signo);
|
||||||
|
|
||||||
|
@ -54,6 +58,8 @@ int main(void)
|
||||||
|
|
||||||
/* Main loop - get work and do it, forever. */
|
/* Main loop - get work and do it, forever. */
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
|
/* Perform sensitive background operations when RS is idle. */
|
||||||
|
rs_idle_period();
|
||||||
|
|
||||||
/* Wait for request message. */
|
/* Wait for request message. */
|
||||||
get_work(&m, &ipc_status);
|
get_work(&m, &ipc_status);
|
||||||
|
@ -103,8 +109,10 @@ int main(void)
|
||||||
case RS_SHUTDOWN: result = do_shutdown(&m); break;
|
case RS_SHUTDOWN: result = do_shutdown(&m); break;
|
||||||
case RS_UPDATE: result = do_update(&m); break;
|
case RS_UPDATE: result = do_update(&m); break;
|
||||||
case RS_CLONE: result = do_clone(&m); break;
|
case RS_CLONE: result = do_clone(&m); break;
|
||||||
|
case RS_UNCLONE: result = do_unclone(&m); break;
|
||||||
case RS_EDIT: result = do_edit(&m); break;
|
case RS_EDIT: result = do_edit(&m); break;
|
||||||
case RS_GETSYSINFO: result = do_getsysinfo(&m); break;
|
case RS_SYSCTL: result = do_sysctl(&m); break;
|
||||||
|
case RS_GETSYSINFO: result = do_getsysinfo(&m); break;
|
||||||
case RS_LOOKUP: result = do_lookup(&m); break;
|
case RS_LOOKUP: result = do_lookup(&m); break;
|
||||||
/* Ready messages. */
|
/* Ready messages. */
|
||||||
case RS_INIT: result = do_init_ready(&m); break;
|
case RS_INIT: result = do_init_ready(&m); break;
|
||||||
|
@ -130,12 +138,15 @@ int main(void)
|
||||||
static void sef_local_startup()
|
static void sef_local_startup()
|
||||||
{
|
{
|
||||||
/* Register init callbacks. */
|
/* Register init callbacks. */
|
||||||
sef_setcb_init_response(do_init_ready);
|
|
||||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||||
sef_setcb_init_restart(sef_cb_init_fail);
|
sef_setcb_init_restart(sef_cb_init_restart);
|
||||||
|
sef_setcb_init_lu(sef_cb_init_lu);
|
||||||
|
|
||||||
/* Register live update callbacks. */
|
/* Register response callbacks. */
|
||||||
sef_setcb_lu_response(do_upd_ready);
|
sef_setcb_init_response(sef_cb_init_response);
|
||||||
|
sef_setcb_lu_response(sef_cb_lu_response);
|
||||||
|
|
||||||
|
/* No live update support for now. */
|
||||||
|
|
||||||
/* Register signal callbacks. */
|
/* Register signal callbacks. */
|
||||||
sef_setcb_signal_handler(sef_cb_signal_handler);
|
sef_setcb_signal_handler(sef_cb_signal_handler);
|
||||||
|
@ -155,11 +166,14 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
int s,i;
|
int s,i;
|
||||||
int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs;
|
int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs;
|
||||||
struct rproc *rp;
|
struct rproc *rp;
|
||||||
|
struct rproc *replica_rp;
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
struct boot_image image[NR_BOOT_PROCS];
|
struct boot_image image[NR_BOOT_PROCS];
|
||||||
struct boot_image_priv *boot_image_priv;
|
struct boot_image_priv *boot_image_priv;
|
||||||
struct boot_image_sys *boot_image_sys;
|
struct boot_image_sys *boot_image_sys;
|
||||||
struct boot_image_dev *boot_image_dev;
|
struct boot_image_dev *boot_image_dev;
|
||||||
|
int pid, replica_pid;
|
||||||
|
endpoint_t replica_endpoint;
|
||||||
int ipc_to;
|
int ipc_to;
|
||||||
int *calls;
|
int *calls;
|
||||||
int all_c[] = { ALL_C, NULL_C };
|
int all_c[] = { ALL_C, NULL_C };
|
||||||
|
@ -179,7 +193,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize some global variables. */
|
/* Initialize some global variables. */
|
||||||
rupdate.flags = 0;
|
RUPDATE_INIT();
|
||||||
shutting_down = FALSE;
|
shutting_down = FALSE;
|
||||||
|
|
||||||
/* Get a copy of the boot image table. */
|
/* Get a copy of the boot image table. */
|
||||||
|
@ -219,8 +233,11 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
/* Reset the system process table. */
|
/* Reset the system process table. */
|
||||||
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
||||||
rp->r_flags = 0;
|
rp->r_flags = 0;
|
||||||
|
rp->r_init_err = ERESTART;
|
||||||
rp->r_pub = &rprocpub[rp - rproc];
|
rp->r_pub = &rprocpub[rp - rproc];
|
||||||
rp->r_pub->in_use = FALSE;
|
rp->r_pub->in_use = FALSE;
|
||||||
|
rp->r_pub->old_endpoint = NONE;
|
||||||
|
rp->r_pub->new_endpoint = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the system process table in 4 steps, each of them following
|
/* Initialize the system process table in 4 steps, each of them following
|
||||||
|
@ -254,6 +271,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
|
|
||||||
/* Initialize privilege bitmaps and signal manager. */
|
/* Initialize privilege bitmaps and signal manager. */
|
||||||
rp->r_priv.s_flags = boot_image_priv->flags; /* priv flags */
|
rp->r_priv.s_flags = boot_image_priv->flags; /* priv flags */
|
||||||
|
rp->r_priv.s_init_flags = SRV_OR_USR(rp, SRV_I, USR_I); /* init flags */
|
||||||
rp->r_priv.s_trap_mask= SRV_OR_USR(rp, SRV_T, USR_T); /* traps */
|
rp->r_priv.s_trap_mask= SRV_OR_USR(rp, SRV_T, USR_T); /* traps */
|
||||||
ipc_to = SRV_OR_USR(rp, SRV_M, USR_M); /* targets */
|
ipc_to = SRV_OR_USR(rp, SRV_M, USR_M); /* targets */
|
||||||
fill_send_mask(&rp->r_priv.s_ipc_to, ipc_to == ALL_M);
|
fill_send_mask(&rp->r_priv.s_ipc_to, ipc_to == ALL_M);
|
||||||
|
@ -345,7 +363,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
/* RS/VM are already running as we speak. */
|
/* RS/VM are already running as we speak. */
|
||||||
if(boot_image_priv->endpoint == RS_PROC_NR ||
|
if(boot_image_priv->endpoint == RS_PROC_NR ||
|
||||||
boot_image_priv->endpoint == VM_PROC_NR) {
|
boot_image_priv->endpoint == VM_PROC_NR) {
|
||||||
if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
|
if ((s = init_service(rp, SEF_INIT_FRESH, rp->r_priv.s_init_flags)) != OK) {
|
||||||
panic("unable to initialize %d: %d", boot_image_priv->endpoint, s);
|
panic("unable to initialize %d: %d", boot_image_priv->endpoint, s);
|
||||||
}
|
}
|
||||||
/* VM will still send an RS_INIT message, though. */
|
/* VM will still send an RS_INIT message, though. */
|
||||||
|
@ -367,7 +385,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
* back to us here at boot time.
|
* back to us here at boot time.
|
||||||
*/
|
*/
|
||||||
if(boot_image_priv->flags & SYS_PROC) {
|
if(boot_image_priv->flags & SYS_PROC) {
|
||||||
if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
|
if ((s = init_service(rp, SEF_INIT_FRESH, rp->r_priv.s_init_flags)) != OK) {
|
||||||
panic("unable to initialize service: %d", s);
|
panic("unable to initialize service: %d", s);
|
||||||
}
|
}
|
||||||
if(rpub->sys_flags & SF_SYNCH_BOOT) {
|
if(rpub->sys_flags & SF_SYNCH_BOOT) {
|
||||||
|
@ -440,7 +458,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
/* New RS instance running. */
|
/* New RS instance running. */
|
||||||
|
|
||||||
/* Live update the old instance into the new one. */
|
/* Live update the old instance into the new one. */
|
||||||
s = update_service(&rp, &replica_rp, RS_SWAP);
|
s = update_service(&rp, &replica_rp, RS_SWAP, 0);
|
||||||
if(s != OK) {
|
if(s != OK) {
|
||||||
panic("unable to live update RS: %d", s);
|
panic("unable to live update RS: %d", s);
|
||||||
}
|
}
|
||||||
|
@ -450,7 +468,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
cleanup_service(rp);
|
cleanup_service(rp);
|
||||||
|
|
||||||
/* Ask VM to pin memory for the new RS instance. */
|
/* Ask VM to pin memory for the new RS instance. */
|
||||||
if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN)) != OK) {
|
if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0)) != OK) {
|
||||||
panic("unable to pin memory for the new RS instance: %d", s);
|
panic("unable to pin memory for the new RS instance: %d", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,6 +494,138 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
return(OK);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_cb_init_restart *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int sef_cb_init_restart(int type, sef_init_info_t *info)
|
||||||
|
{
|
||||||
|
/* Restart the reincarnation server. */
|
||||||
|
int r;
|
||||||
|
struct rproc *old_rs_rp, *new_rs_rp;
|
||||||
|
|
||||||
|
assert(info->endpoint == RS_PROC_NR);
|
||||||
|
|
||||||
|
/* Perform default state transfer first. */
|
||||||
|
r = SEF_CB_INIT_RESTART_DEFAULT(type, info);
|
||||||
|
if(r != OK) {
|
||||||
|
printf("SEF_CB_INIT_RESTART_DEFAULT failed: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* New RS takes over. */
|
||||||
|
old_rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
|
||||||
|
new_rs_rp = rproc_ptr[_ENDPOINT_P(info->old_endpoint)];
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s is the new RS after restart\n", srv_to_string(new_rs_rp));
|
||||||
|
|
||||||
|
/* If an update was in progress, end it. */
|
||||||
|
if(SRV_IS_UPDATING(old_rs_rp)) {
|
||||||
|
end_update(ERESTART, RS_REPLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the service into the replica. */
|
||||||
|
r = update_service(&old_rs_rp, &new_rs_rp, RS_DONTSWAP, 0);
|
||||||
|
if(r != OK) {
|
||||||
|
printf("update_service failed: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the new RS instance. */
|
||||||
|
r = init_service(new_rs_rp, SEF_INIT_RESTART, 0);
|
||||||
|
if(r != OK) {
|
||||||
|
printf("init_service failed: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reschedule a synchronous alarm for the next period. */
|
||||||
|
if (OK != (r=sys_setalarm(RS_DELTA_T, 0)))
|
||||||
|
panic("couldn't set alarm: %d", r);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_cb_init_lu *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int sef_cb_init_lu(int type, sef_init_info_t *info)
|
||||||
|
{
|
||||||
|
/* Start a new version of the reincarnation server. */
|
||||||
|
int r;
|
||||||
|
struct rproc *old_rs_rp, *new_rs_rp;
|
||||||
|
|
||||||
|
assert(info->endpoint == RS_PROC_NR);
|
||||||
|
|
||||||
|
/* Perform default state transfer first. */
|
||||||
|
sef_setcb_init_restart(SEF_CB_INIT_RESTART_DEFAULT);
|
||||||
|
r = SEF_CB_INIT_LU_DEFAULT(type, info);
|
||||||
|
if(r != OK) {
|
||||||
|
printf("SEF_CB_INIT_LU_DEFAULT failed: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* New RS takes over. */
|
||||||
|
old_rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
|
||||||
|
new_rs_rp = rproc_ptr[_ENDPOINT_P(info->old_endpoint)];
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s is the new RS after live update\n",
|
||||||
|
srv_to_string(new_rs_rp));
|
||||||
|
|
||||||
|
/* Update the service into the replica. */
|
||||||
|
r = update_service(&old_rs_rp, &new_rs_rp, RS_DONTSWAP, 0);
|
||||||
|
if(r != OK) {
|
||||||
|
printf("update_service failed: %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if everything is as expected. */
|
||||||
|
assert(RUPDATE_IS_UPDATING());
|
||||||
|
assert(RUPDATE_IS_INITIALIZING());
|
||||||
|
assert(rupdate.num_rpupds > 0);
|
||||||
|
assert(rupdate.num_init_ready_pending > 0);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_cb_init_response *
|
||||||
|
*===========================================================================*/
|
||||||
|
int sef_cb_init_response(message *m_ptr)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Return now if RS initialization failed. */
|
||||||
|
r = m_ptr->m_rs_init.result;
|
||||||
|
if(r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simulate an RS-to-RS init message. */
|
||||||
|
r = do_init_ready(m_ptr);
|
||||||
|
|
||||||
|
/* Assume everything is OK if EDONTREPLY was returned. */
|
||||||
|
if(r == EDONTREPLY) {
|
||||||
|
r = OK;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_cb_lu_response *
|
||||||
|
*===========================================================================*/
|
||||||
|
int sef_cb_lu_response(message *m_ptr)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Simulate an RS-to-RS update ready message. */
|
||||||
|
r = do_upd_ready(m_ptr);
|
||||||
|
|
||||||
|
/* If we get this far, we didn't get updated for some reason. Report error. */
|
||||||
|
if(r == EDONTREPLY) {
|
||||||
|
r = EGENERIC;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* sef_cb_signal_handler *
|
* sef_cb_signal_handler *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -500,7 +650,6 @@ static int sef_cb_signal_manager(endpoint_t target, int signo)
|
||||||
/* Process system signal on behalf of the kernel. */
|
/* Process system signal on behalf of the kernel. */
|
||||||
int target_p;
|
int target_p;
|
||||||
struct rproc *rp;
|
struct rproc *rp;
|
||||||
struct rprocpub *rpub;
|
|
||||||
message m;
|
message m;
|
||||||
|
|
||||||
/* Lookup slot. */
|
/* Lookup slot. */
|
||||||
|
@ -511,7 +660,6 @@ static int sef_cb_signal_manager(endpoint_t target, int signo)
|
||||||
return OK; /* clear the signal */
|
return OK; /* clear the signal */
|
||||||
}
|
}
|
||||||
rp = rproc_ptr[target_p];
|
rp = rproc_ptr[target_p];
|
||||||
rpub = rp->r_pub;
|
|
||||||
|
|
||||||
/* Don't bother if a termination signal has already been processed. */
|
/* Don't bother if a termination signal has already been processed. */
|
||||||
if((rp->r_flags & RS_TERMINATED) && !(rp->r_flags & RS_EXITING)) {
|
if((rp->r_flags & RS_TERMINATED) && !(rp->r_flags & RS_EXITING)) {
|
||||||
|
@ -539,14 +687,19 @@ static int sef_cb_signal_manager(endpoint_t target, int signo)
|
||||||
if(SIGS_IS_TERMINATION(signo)) {
|
if(SIGS_IS_TERMINATION(signo)) {
|
||||||
rp->r_flags |= RS_TERMINATED;
|
rp->r_flags |= RS_TERMINATED;
|
||||||
terminate_service(rp);
|
terminate_service(rp);
|
||||||
|
rs_idle_period();
|
||||||
|
|
||||||
return EDEADEPT; /* process is now gone */
|
return EDEADEPT; /* process is now gone */
|
||||||
}
|
}
|
||||||
|
/* Never deliver signals to VM. */
|
||||||
|
if (rp->r_pub->endpoint == VM_PROC_NR) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Translate every non-termination signal into a message. */
|
/* Translate every non-termination signal into a message. */
|
||||||
m.m_type = SIGS_SIGNAL_RECEIVED;
|
m.m_type = SIGS_SIGNAL_RECEIVED;
|
||||||
m.m_pm_lsys_sigs_signal.num = signo;
|
m.m_pm_lsys_sigs_signal.num = signo;
|
||||||
asynsend3(rpub->endpoint, &m, AMF_NOREPLY);
|
rs_asynsend(rp, &m, 1);
|
||||||
|
|
||||||
return OK; /* signal has been delivered */
|
return OK; /* signal has been delivered */
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include "kernel/proc.h"
|
#include "kernel/proc.h"
|
||||||
|
|
||||||
|
static int run_script(struct rproc *rp);
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* caller_is_root *
|
* caller_is_root *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -102,9 +104,14 @@ struct rproc *rp;
|
||||||
if(call != RS_EDIT) return EPERM;
|
if(call != RS_EDIT) return EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disallow the call if an update is in progress. */
|
||||||
|
if(RUPDATE_IS_UPDATING()) {
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/* Disallow the call if another call is in progress for the service. */
|
/* Disallow the call if another call is in progress for the service. */
|
||||||
if((rp->r_flags & RS_LATEREPLY)
|
if((rp->r_flags & RS_LATEREPLY)
|
||||||
|| (rp->r_flags & RS_INITIALIZING) || (rp->r_flags & RS_UPDATING)) {
|
|| (rp->r_flags & RS_INITIALIZING)) {
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +168,121 @@ size_t dst_len;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* init_state_data *
|
||||||
|
*===========================================================================*/
|
||||||
|
int init_state_data(endpoint_t src_e, int prepare_state,
|
||||||
|
struct rs_state_data *src_rs_state_data,
|
||||||
|
struct rs_state_data *dst_rs_state_data)
|
||||||
|
{
|
||||||
|
int s, i, j, num_ipc_filters = 0;
|
||||||
|
struct rs_ipc_filter_el (*rs_ipc_filter_els)[IPCF_MAX_ELEMENTS];
|
||||||
|
struct rs_ipc_filter_el rs_ipc_filter[IPCF_MAX_ELEMENTS];
|
||||||
|
size_t rs_ipc_filter_size = sizeof(rs_ipc_filter);
|
||||||
|
ipc_filter_el_t (*ipcf_els_buff)[IPCF_MAX_ELEMENTS];
|
||||||
|
size_t ipcf_els_buff_size;
|
||||||
|
|
||||||
|
dst_rs_state_data->size = 0;
|
||||||
|
dst_rs_state_data->eval_addr = NULL;
|
||||||
|
dst_rs_state_data->eval_len = 0;
|
||||||
|
dst_rs_state_data->ipcf_els = NULL;
|
||||||
|
dst_rs_state_data->ipcf_els_size = 0;
|
||||||
|
if(src_rs_state_data->size != sizeof(struct rs_state_data)) {
|
||||||
|
return E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize eval expression. */
|
||||||
|
if(prepare_state == SEF_LU_STATE_EVAL) {
|
||||||
|
if(src_rs_state_data->eval_len == 0 || !src_rs_state_data->eval_addr) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
dst_rs_state_data->eval_addr = malloc(src_rs_state_data->eval_len+1);
|
||||||
|
dst_rs_state_data->eval_len = src_rs_state_data->eval_len;
|
||||||
|
if(!dst_rs_state_data->eval_addr) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
s = sys_datacopy(src_e, (vir_bytes) src_rs_state_data->eval_addr,
|
||||||
|
SELF, (vir_bytes) dst_rs_state_data->eval_addr,
|
||||||
|
dst_rs_state_data->eval_len);
|
||||||
|
if(s != OK) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
*((char*)dst_rs_state_data->eval_addr + dst_rs_state_data->eval_len) = '\0';
|
||||||
|
dst_rs_state_data->size = src_rs_state_data->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize ipc filters. */
|
||||||
|
if(src_rs_state_data->ipcf_els_size % rs_ipc_filter_size) {
|
||||||
|
return E2BIG;
|
||||||
|
}
|
||||||
|
rs_ipc_filter_els = src_rs_state_data->ipcf_els;
|
||||||
|
num_ipc_filters = src_rs_state_data->ipcf_els_size / rs_ipc_filter_size;
|
||||||
|
if(!rs_ipc_filter_els) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcf_els_buff_size = sizeof(ipc_filter_el_t)*IPCF_MAX_ELEMENTS*num_ipc_filters;
|
||||||
|
if(src_e == VM_PROC_NR) {
|
||||||
|
ipcf_els_buff_size += sizeof(ipc_filter_el_t)*IPCF_MAX_ELEMENTS;
|
||||||
|
}
|
||||||
|
ipcf_els_buff = malloc(ipcf_els_buff_size);
|
||||||
|
if(!ipcf_els_buff) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
memset(ipcf_els_buff, 0, ipcf_els_buff_size);
|
||||||
|
for(i=0;i<num_ipc_filters;i++) {
|
||||||
|
s = sys_datacopy(src_e, (vir_bytes) rs_ipc_filter_els[i],
|
||||||
|
SELF, (vir_bytes) rs_ipc_filter, rs_ipc_filter_size);
|
||||||
|
if(s != OK) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
for(j=0;j<IPCF_MAX_ELEMENTS && rs_ipc_filter[j].flags;j++) {
|
||||||
|
endpoint_t m_source = 0;
|
||||||
|
int m_type = 0;
|
||||||
|
int flags = rs_ipc_filter[j].flags;
|
||||||
|
if(flags & IPCF_MATCH_M_TYPE) {
|
||||||
|
m_type = rs_ipc_filter[j].m_type;
|
||||||
|
}
|
||||||
|
if(flags & IPCF_MATCH_M_SOURCE) {
|
||||||
|
if(ds_retrieve_label_endpt(rs_ipc_filter[j].m_label,&m_source) != OK) {
|
||||||
|
/* try to see if an endpoint was provided as label */
|
||||||
|
char *buff;
|
||||||
|
if(!strcmp("ANY_USR", rs_ipc_filter[j].m_label)) {
|
||||||
|
m_source = ANY_USR;
|
||||||
|
}
|
||||||
|
else if(!strcmp("ANY_SYS", rs_ipc_filter[j].m_label)) {
|
||||||
|
m_source = ANY_SYS;
|
||||||
|
}
|
||||||
|
else if(!strcmp("ANY_TSK", rs_ipc_filter[j].m_label)) {
|
||||||
|
m_source = ANY_TSK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errno=0;
|
||||||
|
m_source = strtol(rs_ipc_filter[j].m_label, &buff, 10);
|
||||||
|
if(errno || strcmp(buff, "")) {
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipcf_els_buff[i][j].flags = flags;
|
||||||
|
ipcf_els_buff[i][j].m_source = m_source;
|
||||||
|
ipcf_els_buff[i][j].m_type = m_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(src_e == VM_PROC_NR) {
|
||||||
|
/* Make sure VM can still talk to us at update time. */
|
||||||
|
ipcf_els_buff[i][0].flags = (IPCF_EL_WHITELIST|IPCF_MATCH_M_SOURCE|IPCF_MATCH_M_TYPE);
|
||||||
|
ipcf_els_buff[i][0].m_source = RS_PROC_NR;
|
||||||
|
ipcf_els_buff[i][0].m_type = VM_RS_UPDATE;
|
||||||
|
}
|
||||||
|
dst_rs_state_data->size = src_rs_state_data->size;
|
||||||
|
dst_rs_state_data->ipcf_els = ipcf_els_buff;
|
||||||
|
dst_rs_state_data->ipcf_els_size = ipcf_els_buff_size;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* build_cmd_dep *
|
* build_cmd_dep *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -213,122 +335,35 @@ void build_cmd_dep(struct rproc *rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* srv_update *
|
* end_srv_init *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int srv_update(endpoint_t src_e, endpoint_t dst_e)
|
void end_srv_init(struct rproc *rp)
|
||||||
{
|
{
|
||||||
int r;
|
|
||||||
int sys_upd_flags = 0;
|
|
||||||
|
|
||||||
/* Ask VM to swap the slots of the two processes and tell the kernel to
|
|
||||||
* do the same. If VM is the service being updated, only perform the kernel
|
|
||||||
* part of the call. The new instance of VM will do the rest at
|
|
||||||
* initialization time.
|
|
||||||
*/
|
|
||||||
if(src_e != VM_PROC_NR) {
|
|
||||||
r = vm_update(src_e, dst_e, sys_upd_flags);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
r = sys_update(src_e, dst_e, sys_upd_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* update_period *
|
|
||||||
*===========================================================================*/
|
|
||||||
void update_period(message *m_ptr)
|
|
||||||
{
|
|
||||||
clock_t now = m_ptr->m_notify.timestamp;
|
|
||||||
short has_update_timed_out;
|
|
||||||
message m;
|
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
|
int r;
|
||||||
|
|
||||||
rpub = rupdate.rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
/* See if a timeout has occurred. */
|
/* See if a late reply has to be sent. */
|
||||||
has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime);
|
late_reply(rp, OK);
|
||||||
|
|
||||||
/* If an update timed out, end the update process and notify
|
/* If the service has completed initialization after a crash
|
||||||
* the old version that the update has been canceled. From now on, the old
|
* make the new instance active and cleanup the old replica.
|
||||||
* version will continue executing.
|
* If the service was part of a scheduled update, schedule the new
|
||||||
|
* replica for the same update.
|
||||||
*/
|
*/
|
||||||
if(has_update_timed_out) {
|
if(rp->r_prev_rp) {
|
||||||
printf("RS: update failed: maximum prepare time reached\n");
|
if(SRV_IS_UPD_SCHEDULED(rp->r_prev_rp)) {
|
||||||
end_update(EINTR, RS_DONTREPLY);
|
rupdate_upd_move(rp->r_prev_rp, rp);
|
||||||
|
|
||||||
/* Prepare cancel request. */
|
|
||||||
m.m_type = RS_LU_PREPARE;
|
|
||||||
m.m_rs_update.state = SEF_LU_STATE_NULL;
|
|
||||||
if(rpub->endpoint == RS_PROC_NR) {
|
|
||||||
/* RS can process the request directly. */
|
|
||||||
do_sef_lu_request(&m);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Send request message to the system service. */
|
|
||||||
asynsend(rpub->endpoint, &m);
|
|
||||||
}
|
}
|
||||||
|
cleanup_service(rp->r_prev_rp);
|
||||||
|
rp->r_prev_rp = NULL;
|
||||||
|
rp->r_restarts += 1;
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s completed restart\n", srv_to_string(rp));
|
||||||
}
|
}
|
||||||
}
|
rp->r_next_rp = NULL;
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* end_update *
|
|
||||||
*===========================================================================*/
|
|
||||||
void end_update(int result, int reply_flag)
|
|
||||||
{
|
|
||||||
/* End the update process. There are two possibilities:
|
|
||||||
* 1) the update succeeded. In that case, cleanup the old version and mark the
|
|
||||||
* new version as no longer under update.
|
|
||||||
* 2) the update failed. In that case, cleanup the new version and mark the old
|
|
||||||
* version as no longer under update. Eventual late ready to update
|
|
||||||
* messages (if any) will simply be ignored and the service can
|
|
||||||
* continue executing. In addition, reset the check timestamp, so that if the
|
|
||||||
* service has a period, a status request will be forced in the next period.
|
|
||||||
*/
|
|
||||||
struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
|
|
||||||
struct rproc **rps;
|
|
||||||
int nr_rps, i;
|
|
||||||
|
|
||||||
old_rp = rupdate.rp;
|
|
||||||
new_rp = old_rp->r_new_rp;
|
|
||||||
|
|
||||||
if(rs_verbose)
|
|
||||||
printf("RS: ending update from %s to %s with result: %d\n",
|
|
||||||
srv_to_string(old_rp), srv_to_string(new_rp), result);
|
|
||||||
|
|
||||||
/* Decide which version has to die out and which version has to survive. */
|
|
||||||
surviving_rp = (result == OK ? new_rp : old_rp);
|
|
||||||
exiting_rp = (result == OK ? old_rp : new_rp);
|
|
||||||
|
|
||||||
/* End update. */
|
|
||||||
rupdate.flags &= ~RS_UPDATING;
|
|
||||||
rupdate.rp = NULL;
|
|
||||||
old_rp->r_new_rp = NULL;
|
|
||||||
new_rp->r_old_rp = NULL;
|
|
||||||
old_rp->r_check_tm = 0;
|
|
||||||
|
|
||||||
/* Send a late reply if necessary. */
|
|
||||||
late_reply(old_rp, result);
|
|
||||||
|
|
||||||
/* Mark the version that has to survive as no longer updating and
|
|
||||||
* reply when asked to.
|
|
||||||
*/
|
|
||||||
surviving_rp->r_flags &= ~RS_UPDATING;
|
|
||||||
if(reply_flag == RS_REPLY) {
|
|
||||||
message m;
|
|
||||||
m.m_type = result;
|
|
||||||
reply(surviving_rp->r_pub->endpoint, surviving_rp, &m);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cleanup the version that has to die out. */
|
|
||||||
get_service_instances(exiting_rp, &rps, &nr_rps);
|
|
||||||
for(i=0;i<nr_rps;i++) {
|
|
||||||
cleanup_service(rps[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rs_verbose)
|
|
||||||
printf("RS: %s ended the update\n", srv_to_string(surviving_rp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -385,30 +420,120 @@ int line;
|
||||||
struct rproc *rp;
|
struct rproc *rp;
|
||||||
{
|
{
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
|
int detach, cleanup_script;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
if(rs_verbose)
|
if(!(rp->r_flags & RS_DEAD)) {
|
||||||
printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp),
|
if(rs_verbose)
|
||||||
file, line);
|
printf("RS: %s marked for cleanup at %s:%d\n", srv_to_string(rp),
|
||||||
|
file, line);
|
||||||
|
|
||||||
/* Tell scheduler this process is finished */
|
/* Unlink service the first time. */
|
||||||
if ((s = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
|
if(rp->r_next_rp) {
|
||||||
printf("RS: warning: scheduler won't give up process: %d\n", s);
|
rp->r_next_rp->r_prev_rp = NULL;
|
||||||
|
rp->r_next_rp = NULL;
|
||||||
|
}
|
||||||
|
if(rp->r_prev_rp) {
|
||||||
|
rp->r_prev_rp->r_next_rp = NULL;
|
||||||
|
rp->r_prev_rp = NULL;
|
||||||
|
}
|
||||||
|
if(rp->r_new_rp) {
|
||||||
|
rp->r_new_rp->r_old_rp = NULL;
|
||||||
|
rp->r_new_rp = NULL;
|
||||||
|
}
|
||||||
|
if(rp->r_old_rp) {
|
||||||
|
rp->r_old_rp->r_new_rp = NULL;
|
||||||
|
rp->r_old_rp = NULL;
|
||||||
|
}
|
||||||
|
rp->r_flags |= RS_DEAD;
|
||||||
|
|
||||||
|
/* Make sure the service can no longer run and unblock IPC callers. */
|
||||||
|
sys_privctl(rpub->endpoint, SYS_PRIV_DISALLOW, NULL);
|
||||||
|
sys_privctl(rpub->endpoint, SYS_PRIV_CLEAR_IPC_REFS, NULL);
|
||||||
|
rp->r_flags &= ~RS_ACTIVE;
|
||||||
|
|
||||||
|
/* Send a late reply if there is any pending. */
|
||||||
|
late_reply(rp, OK);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ask PM to exit the service */
|
cleanup_script = rp->r_flags & RS_CLEANUP_SCRIPT;
|
||||||
if(rp->r_pid == -1) {
|
detach = rp->r_flags & RS_CLEANUP_DETACH;
|
||||||
printf("RS: warning: attempt to kill pid -1!\n");
|
|
||||||
|
/* Cleanup the service when not detaching. */
|
||||||
|
if(!detach) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp),
|
||||||
|
file, line);
|
||||||
|
|
||||||
|
/* Tell scheduler this process is finished */
|
||||||
|
if ((s = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
|
||||||
|
printf("RS: warning: scheduler won't give up process: %d\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask PM to exit the service */
|
||||||
|
if(rp->r_pid == -1) {
|
||||||
|
printf("RS: warning: attempt to kill pid -1!\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srv_kill(rp->r_pid, SIGKILL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we need to run a script now. */
|
||||||
|
if(cleanup_script) {
|
||||||
|
rp->r_flags &= ~RS_CLEANUP_SCRIPT;
|
||||||
|
s = run_script(rp);
|
||||||
|
if(s != OK) {
|
||||||
|
printf("RS: warning: cannot run cleanup script: %d\n", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(detach) {
|
||||||
|
/* Detach service when asked to. */
|
||||||
|
detach_service(rp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
srv_kill(rp->r_pid, SIGKILL);
|
/* Free slot otherwise, unless we're about to reuse it */
|
||||||
|
if (!(rp->r_flags & RS_REINCARNATE))
|
||||||
|
free_slot(rp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Free slot, unless we're about to reuse it */
|
/*===========================================================================*
|
||||||
if (!(rp->r_flags & RS_REINCARNATE))
|
* detach_service_debug *
|
||||||
free_slot(rp);
|
*===========================================================================*/
|
||||||
|
void detach_service_debug(file, line, rp)
|
||||||
|
char *file;
|
||||||
|
int line;
|
||||||
|
struct rproc *rp;
|
||||||
|
{
|
||||||
|
/* Detach the given system service. */
|
||||||
|
static unsigned long detach_counter = 0;
|
||||||
|
char label[RS_MAX_LABEL_LEN];
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
/* Publish a new unique label for the system service. */
|
||||||
|
rpub->label[RS_MAX_LABEL_LEN-1] = '\0';
|
||||||
|
strcpy(label, rpub->label);
|
||||||
|
snprintf(rpub->label, RS_MAX_LABEL_LEN, "%lu.%s", ++detach_counter, label);
|
||||||
|
ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s detached at %s:%d\n", srv_to_string(rp),
|
||||||
|
file, line);
|
||||||
|
|
||||||
|
/* Allow the service to run. */
|
||||||
|
rp->r_flags = RS_IN_USE | RS_ACTIVE;
|
||||||
|
rpub->sys_flags &= ~(SF_CORE_SRV|SF_DET_RESTART);
|
||||||
|
rp->r_period = 0;
|
||||||
|
rpub->dev_nr = 0;
|
||||||
|
sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -495,7 +620,7 @@ struct rproc *rp;
|
||||||
if ((s = sched_init_proc(rp)) != OK) {
|
if ((s = sched_init_proc(rp)) != OK) {
|
||||||
printf("RS: unable to start scheduling: %d\n", s);
|
printf("RS: unable to start scheduling: %d\n", s);
|
||||||
cleanup_service(rp);
|
cleanup_service(rp);
|
||||||
vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN,0,0);
|
vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,8 +654,37 @@ struct rproc *rp;
|
||||||
free_exec(rp);
|
free_exec(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The purpose of non-blocking forks is to avoid involving VFS in the forking
|
||||||
|
* process, because VFS may be blocked on a sendrec() to a MFS that is
|
||||||
|
* waiting for a endpoint update for a dead driver. We have just published
|
||||||
|
* that update, but VFS may still be blocked. As a result, VFS may not yet
|
||||||
|
* have received PM's fork message. Hence, if we call mapdriver()
|
||||||
|
* immediately, VFS may not know about the process and thus refuse to add the
|
||||||
|
* driver entry. The following temporary hack works around this by forcing
|
||||||
|
* blocking communication from PM to VFS. Once VFS has been made non-blocking
|
||||||
|
* towards MFS instances, this hack and the big part of srv_fork() can go.
|
||||||
|
*/
|
||||||
|
setuid(0);
|
||||||
|
|
||||||
|
/* If this is a RS instance, pin memory. */
|
||||||
|
if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: pinning memory of RS instance %s\n", srv_to_string(rp));
|
||||||
|
|
||||||
|
s = vm_memctl(rpub->endpoint, VM_RS_MEM_PIN, 0, 0);
|
||||||
|
if(s != OK) {
|
||||||
|
printf("vm_memctl failed: %d\n", s);
|
||||||
|
cleanup_service(rp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If this is a VM instance, let VM know now. */
|
/* If this is a VM instance, let VM know now. */
|
||||||
if(rp->r_priv.s_flags & VM_SYS_PROC) {
|
if(rp->r_priv.s_flags & VM_SYS_PROC) {
|
||||||
|
struct rproc *rs_rp;
|
||||||
|
struct rproc **rs_rps;
|
||||||
|
int i, nr_rs_rps;
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: informing VM of instance %s\n", srv_to_string(rp));
|
printf("RS: informing VM of instance %s\n", srv_to_string(rp));
|
||||||
|
|
||||||
|
@ -540,6 +694,15 @@ struct rproc *rp;
|
||||||
cleanup_service(rp);
|
cleanup_service(rp);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VM may start actually pinning memory for us only now.
|
||||||
|
* Ask again for all our instances.
|
||||||
|
*/
|
||||||
|
rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
|
||||||
|
get_service_instances(rs_rp, &rs_rps, &nr_rs_rps);
|
||||||
|
for(i=0;i<nr_rs_rps;i++) {
|
||||||
|
vm_memctl(rs_rps[i]->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell VM about allowed calls. */
|
/* Tell VM about allowed calls. */
|
||||||
|
@ -558,9 +721,7 @@ struct rproc *rp;
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* clone_service *
|
* clone_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int clone_service(rp, instance_flag)
|
int clone_service(struct rproc *rp, int instance_flag, int init_flags)
|
||||||
struct rproc *rp;
|
|
||||||
int instance_flag;
|
|
||||||
{
|
{
|
||||||
/* Clone the given system service instance. */
|
/* Clone the given system service instance. */
|
||||||
struct rproc *replica_rp;
|
struct rproc *replica_rp;
|
||||||
|
@ -572,7 +733,16 @@ int instance_flag;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: creating a replica for %s\n", srv_to_string(rp));
|
printf("RS: %s creating a replica\n", srv_to_string(rp));
|
||||||
|
|
||||||
|
/* VM can only reliably support one replica at the time for now.
|
||||||
|
* XXX TO-DO: Fix VM's rs_memctl_make_vm_instance to allow multiple replicas.
|
||||||
|
*/
|
||||||
|
if(rp->r_pub->endpoint == VM_PROC_NR && instance_flag == LU_SYS_PROC
|
||||||
|
&& rp->r_next_rp) {
|
||||||
|
cleanup_service_now(rp->r_next_rp);
|
||||||
|
rp->r_next_rp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clone slot. */
|
/* Clone slot. */
|
||||||
if((r = clone_slot(rp, &replica_rp)) != OK) {
|
if((r = clone_slot(rp, &replica_rp)) != OK) {
|
||||||
|
@ -590,6 +760,7 @@ int instance_flag;
|
||||||
replica_link = &replica_rp->r_prev_rp;
|
replica_link = &replica_rp->r_prev_rp;
|
||||||
}
|
}
|
||||||
replica_rp->r_priv.s_flags |= instance_flag;
|
replica_rp->r_priv.s_flags |= instance_flag;
|
||||||
|
replica_rp->r_priv.s_init_flags |= init_flags;
|
||||||
|
|
||||||
/* Link the two slots. */
|
/* Link the two slots. */
|
||||||
*rp_link = replica_rp;
|
*rp_link = replica_rp;
|
||||||
|
@ -737,7 +908,7 @@ struct rproc *rp; /* pointer to service slot */
|
||||||
r = ds_retrieve_label_endpt("devman",&ep);
|
r = ds_retrieve_label_endpt("devman",&ep);
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
printf("RS: devman not running?");
|
printf("RS: devman not running?");
|
||||||
} else {
|
} else {
|
||||||
m.m_type = DEVMAN_UNBIND;
|
m.m_type = DEVMAN_UNBIND;
|
||||||
m.DEVMAN_ENDPOINT = rpub->endpoint;
|
m.DEVMAN_ENDPOINT = rpub->endpoint;
|
||||||
|
@ -759,9 +930,7 @@ struct rproc *rp; /* pointer to service slot */
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* run_service *
|
* run_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int run_service(rp, init_type)
|
int run_service(struct rproc *rp, int init_type, int init_flags)
|
||||||
struct rproc *rp;
|
|
||||||
int init_type;
|
|
||||||
{
|
{
|
||||||
/* Let a newly created service run. */
|
/* Let a newly created service run. */
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
|
@ -775,7 +944,7 @@ int init_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize service. */
|
/* Initialize service. */
|
||||||
if((s = init_service(rp, init_type)) != OK) {
|
if((s = init_service(rp, init_type, init_flags)) != OK) {
|
||||||
return kill_service(rp, "unable to initialize service", s);
|
return kill_service(rp, "unable to initialize service", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,16 +957,16 @@ int init_type;
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* start_service *
|
* start_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int start_service(rp)
|
int start_service(struct rproc *rp, int init_flags)
|
||||||
struct rproc *rp;
|
|
||||||
{
|
{
|
||||||
/* Start a system service. */
|
/* Start a system service. */
|
||||||
int r, init_type;
|
int r;
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
/* Create and make active. */
|
/* Create and make active. */
|
||||||
|
rp->r_priv.s_init_flags |= init_flags;
|
||||||
r = create_service(rp);
|
r = create_service(rp);
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
return r;
|
return r;
|
||||||
|
@ -811,8 +980,7 @@ struct rproc *rp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run. */
|
/* Run. */
|
||||||
init_type = SEF_INIT_FRESH;
|
r = run_service(rp, SEF_INIT_FRESH, init_flags);
|
||||||
r = run_service(rp, init_type);
|
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -849,66 +1017,6 @@ void stop_service(struct rproc *rp,int how)
|
||||||
getticks(&rp->r_stop_tm); /* record current time */
|
getticks(&rp->r_stop_tm); /* record current time */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* update_service *
|
|
||||||
*===========================================================================*/
|
|
||||||
int update_service(src_rpp, dst_rpp, swap_flag)
|
|
||||||
struct rproc **src_rpp;
|
|
||||||
struct rproc **dst_rpp;
|
|
||||||
int swap_flag;
|
|
||||||
{
|
|
||||||
/* Update an existing service. */
|
|
||||||
int r;
|
|
||||||
struct rproc *src_rp;
|
|
||||||
struct rproc *dst_rp;
|
|
||||||
struct rprocpub *src_rpub;
|
|
||||||
struct rprocpub *dst_rpub;
|
|
||||||
int pid;
|
|
||||||
endpoint_t endpoint;
|
|
||||||
|
|
||||||
src_rp = *src_rpp;
|
|
||||||
dst_rp = *dst_rpp;
|
|
||||||
src_rpub = src_rp->r_pub;
|
|
||||||
dst_rpub = dst_rp->r_pub;
|
|
||||||
|
|
||||||
if(rs_verbose)
|
|
||||||
printf("RS: %s updating into %s\n",
|
|
||||||
srv_to_string(src_rp), srv_to_string(dst_rp));
|
|
||||||
|
|
||||||
/* Swap the slots of the two processes when asked to. */
|
|
||||||
if(swap_flag == RS_SWAP) {
|
|
||||||
if((r = srv_update(src_rpub->endpoint, dst_rpub->endpoint)) != OK) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Swap slots here as well. */
|
|
||||||
pid = src_rp->r_pid;
|
|
||||||
endpoint = src_rpub->endpoint;
|
|
||||||
swap_slot(&src_rp, &dst_rp);
|
|
||||||
|
|
||||||
/* Reassign pids and endpoints. */
|
|
||||||
src_rp->r_pid = dst_rp->r_pid;
|
|
||||||
src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint;
|
|
||||||
rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp;
|
|
||||||
dst_rp->r_pid = pid;
|
|
||||||
dst_rp->r_pub->endpoint = endpoint;
|
|
||||||
rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
|
|
||||||
|
|
||||||
/* Adjust input pointers. */
|
|
||||||
*src_rpp = src_rp;
|
|
||||||
*dst_rpp = dst_rp;
|
|
||||||
|
|
||||||
/* Make the new version active. */
|
|
||||||
activate_service(dst_rp, src_rp);
|
|
||||||
|
|
||||||
if(rs_verbose)
|
|
||||||
printf("RS: %s updated into %s\n",
|
|
||||||
srv_to_string(src_rp), srv_to_string(dst_rp));
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* activate_service *
|
* activate_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -932,35 +1040,23 @@ void activate_service(struct rproc *rp, struct rproc *ex_rp)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* reincarnate_service *
|
* reincarnate_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void reincarnate_service(struct rproc *rp)
|
void reincarnate_service(struct rproc *old_rp)
|
||||||
{
|
{
|
||||||
/* Restart a service as if it were never started before. */
|
/* Restart a service as if it were never started before. */
|
||||||
struct rprocpub *rpub;
|
struct rproc *rp;
|
||||||
int i;
|
int r, restarts;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
if ((r = clone_slot(old_rp, &rp)) != OK) {
|
||||||
|
printf("RS: Failed to clone the slot: %d\n", r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rp->r_flags &= RS_IN_USE;
|
rp->r_flags = RS_IN_USE;
|
||||||
rp->r_pid = -1;
|
rproc_ptr[_ENDPOINT_P(rp->r_pub->endpoint)] = NULL;
|
||||||
rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL;
|
|
||||||
|
|
||||||
/* Restore original IRQ and I/O range tables in the priv struct. This is the
|
restarts = rp->r_restarts;
|
||||||
* only part of the privilege structure that can be modified by processes
|
start_service(rp, SEF_INIT_FRESH);
|
||||||
* other than RS itself.
|
rp->r_restarts = restarts + 1;
|
||||||
*/
|
|
||||||
rp->r_priv.s_nr_irq = rp->r_nr_irq;
|
|
||||||
for (i = 0; i < rp->r_nr_irq; i++)
|
|
||||||
rp->r_priv.s_irq_tab[i] = rp->r_irq_tab[i];
|
|
||||||
rp->r_priv.s_nr_io_range = rp->r_nr_io_range;
|
|
||||||
for (i = 0; i < rp->r_nr_io_range; i++)
|
|
||||||
rp->r_priv.s_io_tab[i] = rp->r_io_tab[i];
|
|
||||||
|
|
||||||
rp->r_old_rp = NULL;
|
|
||||||
rp->r_new_rp = NULL;
|
|
||||||
rp->r_prev_rp = NULL;
|
|
||||||
rp->r_next_rp = NULL;
|
|
||||||
|
|
||||||
start_service(rp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -971,7 +1067,7 @@ void terminate_service(struct rproc *rp)
|
||||||
/* Handle a termination event for a system service. */
|
/* Handle a termination event for a system service. */
|
||||||
struct rproc **rps;
|
struct rproc **rps;
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
int nr_rps;
|
int nr_rps, norestart;
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
@ -981,6 +1077,14 @@ void terminate_service(struct rproc *rp)
|
||||||
|
|
||||||
/* Deal with failures during initialization. */
|
/* Deal with failures during initialization. */
|
||||||
if(rp->r_flags & RS_INITIALIZING) {
|
if(rp->r_flags & RS_INITIALIZING) {
|
||||||
|
/* If updating, rollback. */
|
||||||
|
if(SRV_IS_UPDATING(rp)) {
|
||||||
|
printf("RS: update failed: state transfer failed. Rolling back...\n");
|
||||||
|
end_update(rp->r_init_err, RS_REPLY);
|
||||||
|
rp->r_init_err = ERESTART;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (rpub->sys_flags & SF_NO_BIN_EXP) {
|
if (rpub->sys_flags & SF_NO_BIN_EXP) {
|
||||||
/* If service was deliberately started with binary exponential offset
|
/* If service was deliberately started with binary exponential offset
|
||||||
* disabled, we're going to assume we want to refresh a service upon
|
* disabled, we're going to assume we want to refresh a service upon
|
||||||
|
@ -993,33 +1097,51 @@ void terminate_service(struct rproc *rp)
|
||||||
} else {
|
} else {
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: service '%s' exited during initialization; "
|
printf("RS: service '%s' exited during initialization; "
|
||||||
"not restarting\n", rpub->label);
|
"exiting\n", rpub->label);
|
||||||
rp->r_flags |= RS_EXITING; /* don't restart. */
|
rp->r_flags |= RS_EXITING; /* don't restart. */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If updating, rollback. */
|
/* If an update process is in progress, end it before doing anything else.
|
||||||
if(rp->r_flags & RS_UPDATING) {
|
* This is to be on the safe side, since there may be some weird dependencies
|
||||||
struct rproc *old_rp, *new_rp;
|
* with services under update, while we perform recovery actions.
|
||||||
printf("RS: update failed: state transfer failed. Rolling back...\n");
|
*/
|
||||||
new_rp = rp;
|
if(RUPDATE_IS_UPDATING()) {
|
||||||
old_rp = new_rp->r_old_rp;
|
printf("RS: aborting the update after a crash...\n");
|
||||||
new_rp->r_flags &= ~RS_INITIALIZING;
|
abort_update_proc(ERESTART);
|
||||||
r = update_service(&new_rp, &old_rp, RS_SWAP);
|
}
|
||||||
assert(r == OK); /* can't fail */
|
|
||||||
end_update(ERESTART, RS_REPLY);
|
/* Force exit when no restart is requested. */
|
||||||
return;
|
norestart = !(rp->r_flags & RS_EXITING) && (rp->r_pub->sys_flags & SF_NORESTART);
|
||||||
|
if(norestart) {
|
||||||
|
rp->r_flags |= RS_EXITING;
|
||||||
|
if((rp->r_pub->sys_flags & SF_DET_RESTART)
|
||||||
|
&& (rp->r_restarts < MAX_DET_RESTART)) {
|
||||||
|
/* Detach at cleanup time. */
|
||||||
|
rp->r_flags |= RS_CLEANUP_DETACH;
|
||||||
|
}
|
||||||
|
if(rp->r_script[0] != '\0') {
|
||||||
|
/* Run script at cleanup time. */
|
||||||
|
rp->r_flags |= RS_CLEANUP_SCRIPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rp->r_flags & RS_EXITING) {
|
if (rp->r_flags & RS_EXITING) {
|
||||||
/* If a core system service is exiting, we are in trouble. */
|
/* If a core system service is exiting, we are in trouble. */
|
||||||
if (rp->r_pub->sys_flags & SF_CORE_SRV && !shutting_down) {
|
if ((rp->r_pub->sys_flags & SF_CORE_SRV) && !shutting_down) {
|
||||||
printf("core system service died: %s\n", srv_to_string(rp));
|
printf("core system service died: %s\n", srv_to_string(rp));
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this service was scheduled for the update, abort the update now. */
|
||||||
|
if(SRV_IS_UPD_SCHEDULED(rp)) {
|
||||||
|
printf("RS: aborting the scheduled update, one of the services part of it is exiting...\n");
|
||||||
|
abort_update_proc(EDEADSRCDST);
|
||||||
|
}
|
||||||
|
|
||||||
/* See if a late reply has to be sent. */
|
/* See if a late reply has to be sent. */
|
||||||
r = (rp->r_caller_request == RS_DOWN ? OK : EDEADEPT);
|
r = (rp->r_caller_request == RS_DOWN
|
||||||
|
|| (rp->r_caller_request == RS_REFRESH && norestart) ? OK : EDEADEPT);
|
||||||
late_reply(rp, r);
|
late_reply(rp, r);
|
||||||
|
|
||||||
/* Unpublish the service. */
|
/* Unpublish the service. */
|
||||||
|
@ -1036,6 +1158,7 @@ void terminate_service(struct rproc *rp)
|
||||||
* If this fails, start_service() itself will perform cleanup.
|
* If this fails, start_service() itself will perform cleanup.
|
||||||
*/
|
*/
|
||||||
if (rp->r_flags & RS_REINCARNATE) {
|
if (rp->r_flags & RS_REINCARNATE) {
|
||||||
|
rp->r_flags &= ~RS_REINCARNATE;
|
||||||
reincarnate_service(rp);
|
reincarnate_service(rp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1044,13 +1167,6 @@ void terminate_service(struct rproc *rp)
|
||||||
restart_service(rp);
|
restart_service(rp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* If an update is in progress, end it. The old version
|
|
||||||
* that just exited will continue executing.
|
|
||||||
*/
|
|
||||||
if(rp->r_flags & RS_UPDATING) {
|
|
||||||
end_update(ERESTART, RS_DONTREPLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine what to do. If this is the first unexpected
|
/* Determine what to do. If this is the first unexpected
|
||||||
* exit, immediately restart this service. Otherwise use
|
* exit, immediately restart this service. Otherwise use
|
||||||
* a binary exponential backoff.
|
* a binary exponential backoff.
|
||||||
|
@ -1104,7 +1220,7 @@ static int run_script(struct rproc *rp)
|
||||||
switch(pid)
|
switch(pid)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
return kill_service(rp, "unable to fork script", errno);
|
return errno;
|
||||||
case 0:
|
case 0:
|
||||||
execle(_PATH_BSHELL, "sh", rp->r_script, rpub->label, reason,
|
execle(_PATH_BSHELL, "sh", rp->r_script, rpub->label, reason,
|
||||||
incarnation_str, (char*) NULL, envp);
|
incarnation_str, (char*) NULL, envp);
|
||||||
|
@ -1146,25 +1262,19 @@ void restart_service(struct rproc *rp)
|
||||||
/* See if a late reply has to be sent. */
|
/* See if a late reply has to be sent. */
|
||||||
late_reply(rp, OK);
|
late_reply(rp, OK);
|
||||||
|
|
||||||
/* This hack disables restarting of file servers, which at the moment always
|
|
||||||
* cause VFS to hang indefinitely. As soon as VFS no longer blocks on calls
|
|
||||||
* to file servers, this exception can be removed again.
|
|
||||||
*/
|
|
||||||
if (!strncmp(rp->r_pub->label, "fs_", 3)) {
|
|
||||||
kill_service(rp, "file servers cannot be restarted yet", ENOSYS);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Run a recovery script if available. */
|
/* Run a recovery script if available. */
|
||||||
if (rp->r_script[0] != '\0') {
|
if (rp->r_script[0] != '\0') {
|
||||||
run_script(rp);
|
r = run_script(rp);
|
||||||
|
if(r != OK) {
|
||||||
|
kill_service(rp, "unable to run script", errno);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart directly. We need a replica if not already available. */
|
/* Restart directly. We need a replica if not already available. */
|
||||||
if(rp->r_next_rp == NULL) {
|
if(rp->r_next_rp == NULL) {
|
||||||
/* Create the replica. */
|
/* Create the replica. */
|
||||||
r = clone_service(rp, RST_SYS_PROC);
|
r = clone_service(rp, RST_SYS_PROC, 0);
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
kill_service(rp, "unable to clone service", r);
|
kill_service(rp, "unable to clone service", r);
|
||||||
return;
|
return;
|
||||||
|
@ -1173,19 +1283,25 @@ void restart_service(struct rproc *rp)
|
||||||
replica_rp = rp->r_next_rp;
|
replica_rp = rp->r_next_rp;
|
||||||
|
|
||||||
/* Update the service into the replica. */
|
/* Update the service into the replica. */
|
||||||
r = update_service(&rp, &replica_rp, RS_SWAP);
|
r = update_service(&rp, &replica_rp, RS_SWAP, 0);
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
kill_service(rp, "unable to update into new replica", r);
|
kill_service(rp, "unable to update into new replica", r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Let the new replica run. */
|
/* Let the new replica run. */
|
||||||
r = run_service(replica_rp, SEF_INIT_RESTART);
|
r = run_service(replica_rp, SEF_INIT_RESTART, 0);
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
kill_service(rp, "unable to let the replica run", r);
|
kill_service(rp, "unable to let the replica run", r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See if the old version needs to be detached. */
|
||||||
|
if((rp->r_pub->sys_flags & SF_DET_RESTART)
|
||||||
|
&& (rp->r_restarts < MAX_DET_RESTART)) {
|
||||||
|
rp->r_flags |= RS_CLEANUP_DETACH;
|
||||||
|
}
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s restarted into %s\n",
|
printf("RS: %s restarted into %s\n",
|
||||||
srv_to_string(rp), srv_to_string(replica_rp));
|
srv_to_string(rp), srv_to_string(replica_rp));
|
||||||
|
@ -1499,11 +1615,13 @@ endpoint_t source;
|
||||||
|
|
||||||
/* Update recovery script. */
|
/* Update recovery script. */
|
||||||
if (rs_start->rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
|
if (rs_start->rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
|
||||||
if (rs_start->rss_script != NULL && !(rpub->sys_flags & SF_CORE_SRV)) {
|
if (rs_start->rss_script != NULL && rs_start->rss_scriptlen > 0
|
||||||
|
&& !(rpub->sys_flags & SF_CORE_SRV)) {
|
||||||
s=sys_datacopy(source, (vir_bytes) rs_start->rss_script,
|
s=sys_datacopy(source, (vir_bytes) rs_start->rss_script,
|
||||||
SELF, (vir_bytes) rp->r_script, rs_start->rss_scriptlen);
|
SELF, (vir_bytes) rp->r_script, rs_start->rss_scriptlen);
|
||||||
if (s != OK) return(s);
|
if (s != OK) return(s);
|
||||||
rp->r_script[rs_start->rss_scriptlen] = '\0';
|
rp->r_script[rs_start->rss_scriptlen] = '\0';
|
||||||
|
rpub->sys_flags |= SF_USE_SCRIPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update system flags and in-memory copy. */
|
/* Update system flags and in-memory copy. */
|
||||||
|
@ -1518,9 +1636,6 @@ endpoint_t source;
|
||||||
|
|
||||||
for(i = 0; i < NR_SYS_PROCS; i++) {
|
for(i = 0; i < NR_SYS_PROCS; i++) {
|
||||||
rp2 = &rproc[i];
|
rp2 = &rproc[i];
|
||||||
if (!(rp2->r_flags & RS_IN_USE)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rpub2 = rproc[i].r_pub;
|
rpub2 = rproc[i].r_pub;
|
||||||
if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
|
if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
|
||||||
(rpub2->sys_flags & SF_USE_COPY)) {
|
(rpub2->sys_flags & SF_USE_COPY)) {
|
||||||
|
@ -1549,12 +1664,32 @@ endpoint_t source;
|
||||||
if (rs_start->rss_flags & RSS_NO_BIN_EXP) {
|
if (rs_start->rss_flags & RSS_NO_BIN_EXP) {
|
||||||
rpub->sys_flags |= SF_NO_BIN_EXP;
|
rpub->sys_flags |= SF_NO_BIN_EXP;
|
||||||
}
|
}
|
||||||
|
if (rs_start->rss_flags & RSS_DETACH) {
|
||||||
|
rpub->sys_flags |= SF_DET_RESTART;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rpub->sys_flags &= ~SF_DET_RESTART;
|
||||||
|
}
|
||||||
|
if (rs_start->rss_flags & RSS_NORESTART) {
|
||||||
|
if(rpub->sys_flags & SF_CORE_SRV) {
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
rpub->sys_flags |= SF_NORESTART;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rpub->sys_flags &= ~SF_NORESTART;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update period. */
|
/* Update period. */
|
||||||
if(rpub->endpoint != RS_PROC_NR) {
|
if(rpub->endpoint != RS_PROC_NR) {
|
||||||
rp->r_period = rs_start->rss_period;
|
rp->r_period = rs_start->rss_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update restarts. */
|
||||||
|
if(rs_start->rss_restarts) {
|
||||||
|
rp->r_restarts = rs_start->rss_restarts;
|
||||||
|
}
|
||||||
|
|
||||||
/* (Re)initialize privilege settings. */
|
/* (Re)initialize privilege settings. */
|
||||||
init_privs(rp, &rp->r_priv);
|
init_privs(rp, &rp->r_priv);
|
||||||
|
|
||||||
|
@ -1581,6 +1716,7 @@ endpoint_t source;
|
||||||
*/
|
*/
|
||||||
rpub->sys_flags = DSRV_SF; /* system flags */
|
rpub->sys_flags = DSRV_SF; /* system flags */
|
||||||
rp->r_priv.s_flags = DSRV_F; /* privilege flags */
|
rp->r_priv.s_flags = DSRV_F; /* privilege flags */
|
||||||
|
rp->r_priv.s_init_flags = DSRV_I; /* init flags */
|
||||||
rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */
|
rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */
|
||||||
rp->r_priv.s_bak_sig_mgr = NONE; /* backup signal manager */
|
rp->r_priv.s_bak_sig_mgr = NONE; /* backup signal manager */
|
||||||
|
|
||||||
|
@ -1622,7 +1758,7 @@ endpoint_t source;
|
||||||
(unsigned int) rpub->pci_acl.rsp_class[i].pciclass,
|
(unsigned int) rpub->pci_acl.rsp_class[i].pciclass,
|
||||||
(unsigned int) rpub->pci_acl.rsp_class[i].mask);
|
(unsigned int) rpub->pci_acl.rsp_class[i].mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize some fields. */
|
/* Initialize some fields. */
|
||||||
rp->r_restarts = 0; /* no restarts yet */
|
rp->r_restarts = 0; /* no restarts yet */
|
||||||
rp->r_old_rp = NULL; /* no old version yet */
|
rp->r_old_rp = NULL; /* no old version yet */
|
||||||
|
@ -1635,6 +1771,9 @@ endpoint_t source;
|
||||||
rpub->label[0]= '\0'; /* no label yet */
|
rpub->label[0]= '\0'; /* no label yet */
|
||||||
rp->r_scheduler = -1; /* no scheduler yet */
|
rp->r_scheduler = -1; /* no scheduler yet */
|
||||||
rp->r_priv.s_sig_mgr = -1; /* no signal manager yet */
|
rp->r_priv.s_sig_mgr = -1; /* no signal manager yet */
|
||||||
|
rp->r_map_prealloc_addr = 0; /* no preallocated memory */
|
||||||
|
rp->r_map_prealloc_len = 0;
|
||||||
|
rp->r_init_err = ERESTART; /* default init error `*/
|
||||||
|
|
||||||
/* Initialize editable slot settings. */
|
/* Initialize editable slot settings. */
|
||||||
return edit_slot(rp, rs_start, source);
|
return edit_slot(rp, rs_start, source);
|
||||||
|
@ -1671,6 +1810,7 @@ struct rproc **clone_rpp;
|
||||||
*clone_rpub = *rpub;
|
*clone_rpub = *rpub;
|
||||||
|
|
||||||
/* Deep copy. */
|
/* Deep copy. */
|
||||||
|
clone_rp->r_init_err = ERESTART; /* default init error */
|
||||||
clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
|
clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
|
||||||
clone_rp->r_pid = -1; /* no pid yet */
|
clone_rp->r_pid = -1; /* no pid yet */
|
||||||
clone_rpub->endpoint = -1; /* no endpoint yet */
|
clone_rpub->endpoint = -1; /* no endpoint yet */
|
||||||
|
@ -1689,6 +1829,7 @@ struct rproc **clone_rpp;
|
||||||
|
|
||||||
/* Clear instance flags. */
|
/* Clear instance flags. */
|
||||||
clone_rp->r_priv.s_flags &= ~(LU_SYS_PROC | RST_SYS_PROC);
|
clone_rp->r_priv.s_flags &= ~(LU_SYS_PROC | RST_SYS_PROC);
|
||||||
|
clone_rp->r_priv.s_init_flags = 0;
|
||||||
|
|
||||||
*clone_rpp = clone_rp;
|
*clone_rpp = clone_rp;
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -1716,12 +1857,11 @@ struct rproc **src_rpp;
|
||||||
struct rproc **dst_rpp;
|
struct rproc **dst_rpp;
|
||||||
{
|
{
|
||||||
/* Swap two service slots. */
|
/* Swap two service slots. */
|
||||||
struct rproc *src_rp;
|
struct rproc *src_rp, *dst_rp;
|
||||||
struct rproc *dst_rp;
|
struct rprocpub *src_rpub, *dst_rpub;
|
||||||
struct rprocpub *src_rpub;
|
|
||||||
struct rprocpub *dst_rpub;
|
|
||||||
struct rproc orig_src_rproc, orig_dst_rproc;
|
struct rproc orig_src_rproc, orig_dst_rproc;
|
||||||
struct rprocpub orig_src_rprocpub, orig_dst_rprocpub;
|
struct rprocpub orig_src_rprocpub, orig_dst_rprocpub;
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
|
||||||
src_rp = *src_rpp;
|
src_rp = *src_rpp;
|
||||||
dst_rp = *dst_rpp;
|
dst_rp = *dst_rpp;
|
||||||
|
@ -1740,9 +1880,11 @@ struct rproc **dst_rpp;
|
||||||
*dst_rp = orig_src_rproc;
|
*dst_rp = orig_src_rproc;
|
||||||
*dst_rpub = orig_src_rprocpub;
|
*dst_rpub = orig_src_rprocpub;
|
||||||
|
|
||||||
/* Restore public entries. */
|
/* Restore public entries and update descriptors. */
|
||||||
src_rp->r_pub = orig_src_rproc.r_pub;
|
src_rp->r_pub = orig_src_rproc.r_pub;
|
||||||
dst_rp->r_pub = orig_dst_rproc.r_pub;
|
dst_rp->r_pub = orig_dst_rproc.r_pub;
|
||||||
|
src_rp->r_upd = orig_src_rproc.r_upd;
|
||||||
|
dst_rp->r_upd = orig_dst_rproc.r_upd;
|
||||||
|
|
||||||
/* Rebuild command dependencies. */
|
/* Rebuild command dependencies. */
|
||||||
build_cmd_dep(src_rp);
|
build_cmd_dep(src_rp);
|
||||||
|
@ -1759,7 +1901,9 @@ struct rproc **dst_rpp;
|
||||||
swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp);
|
swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp);
|
||||||
|
|
||||||
/* Swap global slot pointers. */
|
/* Swap global slot pointers. */
|
||||||
swap_slot_pointer(&rupdate.rp, src_rp, dst_rp);
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
swap_slot_pointer(&rpupd->rp, src_rp, dst_rp);
|
||||||
|
);
|
||||||
swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)],
|
swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)],
|
||||||
src_rp, dst_rp);
|
src_rp, dst_rp);
|
||||||
swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)],
|
swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)],
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
/* Structs used in prototypes must be declared as such first. */
|
/* Structs used in prototypes must be declared as such first. */
|
||||||
struct rproc;
|
struct rproc;
|
||||||
|
struct rprocupd;
|
||||||
|
|
||||||
/* exec.c */
|
/* exec.c */
|
||||||
int srv_execve(int proc_e, char *exec, size_t exec_len, char *argv[],
|
int srv_execve(int proc_e, char *exec, size_t exec_len, char *argv[],
|
||||||
|
@ -16,6 +17,7 @@ int do_down(message *m);
|
||||||
int do_refresh(message *m);
|
int do_refresh(message *m);
|
||||||
int do_restart(message *m);
|
int do_restart(message *m);
|
||||||
int do_clone(message *m);
|
int do_clone(message *m);
|
||||||
|
int do_unclone(message *m);
|
||||||
int do_edit(message *m);
|
int do_edit(message *m);
|
||||||
int do_shutdown(message *m);
|
int do_shutdown(message *m);
|
||||||
void do_period(message *m);
|
void do_period(message *m);
|
||||||
|
@ -25,6 +27,7 @@ int do_upd_ready(message *m);
|
||||||
void do_sigchld(void);
|
void do_sigchld(void);
|
||||||
int do_getsysinfo(message *m);
|
int do_getsysinfo(message *m);
|
||||||
int do_lookup(message *m);
|
int do_lookup(message *m);
|
||||||
|
int do_sysctl(message *m);
|
||||||
|
|
||||||
/* manager.c */
|
/* manager.c */
|
||||||
int check_call_permission(endpoint_t caller, int call, struct rproc
|
int check_call_permission(endpoint_t caller, int call, struct rproc
|
||||||
|
@ -33,8 +36,10 @@ int copy_rs_start(endpoint_t src_e, char *src_rs_start, struct rs_start
|
||||||
*rs_start);
|
*rs_start);
|
||||||
int copy_label(endpoint_t src_e, char *src_label, size_t src_len, char
|
int copy_label(endpoint_t src_e, char *src_label, size_t src_len, char
|
||||||
*dst_label, size_t dst_len);
|
*dst_label, size_t dst_len);
|
||||||
|
int init_state_data(endpoint_t src_e, int prepare_state,
|
||||||
|
struct rs_state_data *src_rs_state_data,
|
||||||
|
struct rs_state_data *dst_rs_state_data);
|
||||||
void build_cmd_dep(struct rproc *rp);
|
void build_cmd_dep(struct rproc *rp);
|
||||||
int srv_update(endpoint_t src_e, endpoint_t dst_e);
|
|
||||||
#define kill_service(rp, errstr, err) \
|
#define kill_service(rp, errstr, err) \
|
||||||
kill_service_debug(__FILE__, __LINE__, rp, errstr, err)
|
kill_service_debug(__FILE__, __LINE__, rp, errstr, err)
|
||||||
int kill_service_debug(char *file, int line, struct rproc *rp, char
|
int kill_service_debug(char *file, int line, struct rproc *rp, char
|
||||||
|
@ -44,29 +49,35 @@ int kill_service_debug(char *file, int line, struct rproc *rp, char
|
||||||
int crash_service_debug(char *file, int line, struct rproc *rp);
|
int crash_service_debug(char *file, int line, struct rproc *rp);
|
||||||
#define cleanup_service(rp) \
|
#define cleanup_service(rp) \
|
||||||
cleanup_service_debug(__FILE__, __LINE__, rp)
|
cleanup_service_debug(__FILE__, __LINE__, rp)
|
||||||
void cleanup_service_debug(char *file, int line, struct rproc *rp);
|
#define cleanup_service_now(rp) \
|
||||||
|
do { struct rproc *rpt = rp; cleanup_service(rpt); cleanup_service(rpt); } while(0)
|
||||||
|
void cleanup_service_debug(char *file, int line,
|
||||||
|
struct rproc *rp);
|
||||||
|
#define detach_service(rp) \
|
||||||
|
detach_service_debug(__FILE__, __LINE__, rp)
|
||||||
|
void detach_service_debug(char *file, int line,
|
||||||
|
struct rproc *rp);
|
||||||
int create_service(struct rproc *rp);
|
int create_service(struct rproc *rp);
|
||||||
int clone_service(struct rproc *rp, int instance_flag);
|
int clone_service(struct rproc *rp, int instance_flag, int init_flags);
|
||||||
int publish_service(struct rproc *rp);
|
int publish_service(struct rproc *rp);
|
||||||
int unpublish_service(struct rproc *rp);
|
int unpublish_service(struct rproc *rp);
|
||||||
int run_service(struct rproc *rp, int init_type);
|
int run_service(struct rproc *rp, int init_type, int init_flags);
|
||||||
int start_service(struct rproc *rp);
|
int start_service(struct rproc *rp, int init_flags);
|
||||||
void stop_service(struct rproc *rp,int how);
|
void stop_service(struct rproc *rp,int how);
|
||||||
int update_service(struct rproc **src_rpp, struct rproc **dst_rpp, int
|
|
||||||
swap_flag);
|
|
||||||
void activate_service(struct rproc *rp, struct rproc *ex_rp);
|
void activate_service(struct rproc *rp, struct rproc *ex_rp);
|
||||||
void terminate_service(struct rproc *rp);
|
void terminate_service(struct rproc *rp);
|
||||||
void restart_service(struct rproc *rp);
|
void restart_service(struct rproc *rp);
|
||||||
void inherit_service_defaults(struct rproc *def_rp, struct rproc *rp);
|
void inherit_service_defaults(struct rproc *def_rp,
|
||||||
void get_service_instances(struct rproc *rp, struct rproc ***rps, int
|
struct rproc *rp);
|
||||||
*length);
|
void get_service_instances(struct rproc *rp, struct rproc ***rps,
|
||||||
|
int *length);
|
||||||
int read_exec(struct rproc *rp);
|
int read_exec(struct rproc *rp);
|
||||||
void share_exec(struct rproc *rp_src, struct rproc *rp_dst);
|
void share_exec(struct rproc *rp_src, struct rproc *rp_dst);
|
||||||
void free_exec(struct rproc *rp);
|
void free_exec(struct rproc *rp);
|
||||||
int init_slot(struct rproc *rp, struct rs_start *rs_start, endpoint_t
|
int init_slot(struct rproc *rp, struct rs_start *rs_start,
|
||||||
source);
|
endpoint_t source);
|
||||||
int edit_slot(struct rproc *rp, struct rs_start *rs_start, endpoint_t
|
int edit_slot(struct rproc *rp, struct rs_start *rs_start,
|
||||||
source);
|
endpoint_t source);
|
||||||
int clone_slot(struct rproc *rp, struct rproc **clone_rpp);
|
int clone_slot(struct rproc *rp, struct rproc **clone_rpp);
|
||||||
void swap_slot(struct rproc **src_rpp, struct rproc **dst_rpp);
|
void swap_slot(struct rproc **src_rpp, struct rproc **dst_rpp);
|
||||||
struct rproc* lookup_slot_by_label(char *label);
|
struct rproc* lookup_slot_by_label(char *label);
|
||||||
|
@ -79,21 +90,58 @@ char *get_next_label(char *ptr, char *label, char *caller_label);
|
||||||
void add_forward_ipc(struct rproc *rp, struct priv *privp);
|
void add_forward_ipc(struct rproc *rp, struct priv *privp);
|
||||||
void add_backward_ipc(struct rproc *rp, struct priv *privp);
|
void add_backward_ipc(struct rproc *rp, struct priv *privp);
|
||||||
void init_privs(struct rproc *rp, struct priv *privp);
|
void init_privs(struct rproc *rp, struct priv *privp);
|
||||||
|
void end_srv_init(struct rproc *rp);
|
||||||
|
|
||||||
|
/* update.c */
|
||||||
|
void rupdate_clear_upds(void);
|
||||||
|
void rupdate_add_upd(struct rprocupd* rpupd);
|
||||||
|
void rupdate_set_new_upd_flags(struct rprocupd* rpupd);
|
||||||
|
void rupdate_upd_init(struct rprocupd* rpupd, struct rproc *rp);
|
||||||
|
void rupdate_upd_clear(struct rprocupd* rpupd);
|
||||||
|
void rupdate_upd_move(struct rproc* src_rp, struct rproc* dst_rp);
|
||||||
|
#define request_prepare_update_service(rp, state) \
|
||||||
|
request_prepare_update_service_debug(__FILE__, __LINE__, rp, state)
|
||||||
|
void request_prepare_update_service_debug(char *file, int line,
|
||||||
|
struct rproc *rp, int state);
|
||||||
|
int srv_update(endpoint_t src_e, endpoint_t dst_e, int sys_upd_flags);
|
||||||
|
int update_service(struct rproc **src_rpp,
|
||||||
|
struct rproc **dst_rpp, int swap_flag, int sys_upd_flags);
|
||||||
|
void rollback_service(struct rproc **src_rpp,
|
||||||
|
struct rproc **dst_rpp);
|
||||||
void update_period(message *m_ptr);
|
void update_period(message *m_ptr);
|
||||||
void end_update(int result, int reply_flag);
|
int start_update_prepare(int allow_retries);
|
||||||
|
struct rprocupd* start_update_prepare_next(void);
|
||||||
|
int start_update(void);
|
||||||
|
int start_srv_update(struct rprocupd *rpupd);
|
||||||
|
int complete_srv_update(struct rprocupd *rpupd);
|
||||||
|
void end_srv_update(struct rprocupd *rpupd, int result, int reply_flag);
|
||||||
|
int abort_update_proc(int reason);
|
||||||
|
#define end_update(result, reply_flag) \
|
||||||
|
end_update_debug(__FILE__, __LINE__, result, reply_flag)
|
||||||
|
void end_update_debug(char *file, int line,
|
||||||
|
int result, int reply_flag);
|
||||||
|
|
||||||
/* utility.c */
|
/* utility.c */
|
||||||
int init_service(struct rproc *rp, int type);
|
int init_service(struct rproc *rp, int type, int flags);
|
||||||
void fill_send_mask(sys_map_t *send_mask, int set_bits);
|
void fill_send_mask(sys_map_t *send_mask, int set_bits);
|
||||||
void fill_call_mask( int *calls, int tot_nr_calls, bitchunk_t
|
void fill_call_mask( int *calls, int tot_nr_calls,
|
||||||
*call_mask, int call_base, int is_init);
|
bitchunk_t *call_mask, int call_base, int is_init);
|
||||||
char* srv_to_string(struct rproc *rp);
|
#define srv_to_string(RP) srv_to_string_gen(RP, DEBUG)
|
||||||
|
char* srv_to_string_gen(struct rproc *rp, int is_verbose);
|
||||||
|
char* srv_upd_to_string(struct rprocupd *rpupd);
|
||||||
|
int rs_asynsend(struct rproc *rp, message *m_ptr, int no_reply);
|
||||||
|
int rs_receive_ticks(endpoint_t src, message *m_ptr,
|
||||||
|
int *status_ptr, int ticks);
|
||||||
void reply(endpoint_t who, struct rproc *rp, message *m_ptr);
|
void reply(endpoint_t who, struct rproc *rp, message *m_ptr);
|
||||||
void late_reply(struct rproc *rp, int code);
|
void late_reply(struct rproc *rp, int code);
|
||||||
int rs_isokendpt(endpoint_t endpoint, int *proc);
|
int rs_isokendpt(endpoint_t endpoint, int *proc);
|
||||||
int sched_init_proc(struct rproc *rp);
|
int sched_init_proc(struct rproc *rp);
|
||||||
int update_sig_mgrs(struct rproc *rp, endpoint_t sig_mgr, endpoint_t
|
int update_sig_mgrs(struct rproc *rp, endpoint_t sig_mgr,
|
||||||
bak_sig_mgr);
|
endpoint_t bak_sig_mgr);
|
||||||
|
int rs_is_idle(void);
|
||||||
|
void rs_idle_period(void);
|
||||||
|
void print_services_status(void);
|
||||||
|
void print_update_status(void);
|
||||||
|
|
||||||
/* error.c */
|
/* error.c */
|
||||||
char * init_strerror(int errnum);
|
char * init_strerror(int errnum);
|
||||||
|
|
666
minix/servers/rs/request.c
Executable file → Normal file
666
minix/servers/rs/request.c
Executable file → Normal file
|
@ -21,6 +21,7 @@ message *m_ptr; /* request message pointer */
|
||||||
int r;
|
int r;
|
||||||
struct rs_start rs_start;
|
struct rs_start rs_start;
|
||||||
int noblock;
|
int noblock;
|
||||||
|
int init_flags = 0;
|
||||||
|
|
||||||
/* Check if the call can be allowed. */
|
/* Check if the call can be allowed. */
|
||||||
if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
|
if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
|
||||||
|
@ -43,7 +44,21 @@ message *m_ptr; /* request message pointer */
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check flags. */
|
||||||
noblock = (rs_start.rss_flags & RSS_NOBLOCK);
|
noblock = (rs_start.rss_flags & RSS_NOBLOCK);
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_CRASH) {
|
||||||
|
init_flags |= SEF_INIT_CRASH;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_FAIL) {
|
||||||
|
init_flags |= SEF_INIT_FAIL;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_TIMEOUT) {
|
||||||
|
init_flags |= SEF_INIT_TIMEOUT;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_DEFCB) {
|
||||||
|
init_flags |= SEF_INIT_DEFCB;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the slot as requested. */
|
/* Initialize the slot as requested. */
|
||||||
r = init_slot(rp, &rs_start, m_ptr->m_source);
|
r = init_slot(rp, &rs_start, m_ptr->m_source);
|
||||||
|
@ -65,7 +80,7 @@ message *m_ptr; /* request message pointer */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All information was gathered. Now try to start the system service. */
|
/* All information was gathered. Now try to start the system service. */
|
||||||
r = start_service(rp);
|
r = start_service(rp, init_flags);
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +232,7 @@ int do_clone(message *m_ptr)
|
||||||
|
|
||||||
/* Clone the service as requested. */
|
/* Clone the service as requested. */
|
||||||
rpub->sys_flags |= SF_USE_REPL;
|
rpub->sys_flags |= SF_USE_REPL;
|
||||||
if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
|
if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
|
||||||
rpub->sys_flags &= ~SF_USE_REPL;
|
rpub->sys_flags &= ~SF_USE_REPL;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -225,6 +240,51 @@ int do_clone(message *m_ptr)
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* do_unclone *
|
||||||
|
*===========================================================================*/
|
||||||
|
int do_unclone(message *m_ptr)
|
||||||
|
{
|
||||||
|
struct rproc *rp;
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
int s, r;
|
||||||
|
char label[RS_MAX_LABEL_LEN];
|
||||||
|
|
||||||
|
/* Copy label. */
|
||||||
|
s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
|
||||||
|
m_ptr->m_rs_req.len, label, sizeof(label));
|
||||||
|
if(s != OK) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup slot by label. */
|
||||||
|
rp = lookup_slot_by_label(label);
|
||||||
|
if(!rp) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: do_unclone: service '%s' not found\n", label);
|
||||||
|
return(ESRCH);
|
||||||
|
}
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
/* Check if the call can be allowed. */
|
||||||
|
if((r = check_call_permission(m_ptr->m_source, RS_UNCLONE, rp)) != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Don't unclone if no replica is available. */
|
||||||
|
if(!(rpub->sys_flags & SF_USE_REPL)) {
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unclone the service as requested. */
|
||||||
|
rpub->sys_flags &= ~SF_USE_REPL;
|
||||||
|
if(rp->r_next_rp) {
|
||||||
|
cleanup_service_now(rp->r_next_rp);
|
||||||
|
rp->r_next_rp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_edit *
|
* do_edit *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -309,7 +369,7 @@ int do_edit(message *m_ptr)
|
||||||
cleanup_service(rp->r_next_rp);
|
cleanup_service(rp->r_next_rp);
|
||||||
rp->r_next_rp = NULL;
|
rp->r_next_rp = NULL;
|
||||||
}
|
}
|
||||||
if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
|
if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
|
||||||
printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
|
printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,7 +410,12 @@ int do_refresh(message *m_ptr)
|
||||||
printf("RS: %s refreshing\n", srv_to_string(rp));
|
printf("RS: %s refreshing\n", srv_to_string(rp));
|
||||||
stop_service(rp,RS_REFRESHING);
|
stop_service(rp,RS_REFRESHING);
|
||||||
|
|
||||||
return OK;
|
/* Late reply - send a reply when refresh completes. */
|
||||||
|
rp->r_flags |= RS_LATEREPLY;
|
||||||
|
rp->r_caller = m_ptr->m_source;
|
||||||
|
rp->r_caller_request = RS_REFRESH;
|
||||||
|
|
||||||
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -391,20 +456,14 @@ int do_init_ready(message *m_ptr)
|
||||||
{
|
{
|
||||||
int who_p;
|
int who_p;
|
||||||
message m;
|
message m;
|
||||||
struct rproc *rp;
|
struct rproc *rp, *new_rp;
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
int result, is_rs;
|
int result;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
is_rs = (m_ptr->m_source == RS_PROC_NR);
|
|
||||||
who_p = _ENDPOINT_P(m_ptr->m_source);
|
who_p = _ENDPOINT_P(m_ptr->m_source);
|
||||||
result = m_ptr->m_rs_init.result;
|
result = m_ptr->m_rs_init.result;
|
||||||
|
|
||||||
/* Check for RS failing initialization first. */
|
|
||||||
if(is_rs && result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
rp = rproc_ptr[who_p];
|
rp = rproc_ptr[who_p];
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
@ -423,55 +482,43 @@ int do_init_ready(message *m_ptr)
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s initialization error: %s\n", srv_to_string(rp),
|
printf("RS: %s initialization error: %s\n", srv_to_string(rp),
|
||||||
init_strerror(result));
|
init_strerror(result));
|
||||||
if (result == ERESTART)
|
if (result == ERESTART && !SRV_IS_UPDATING(rp))
|
||||||
rp->r_flags |= RS_REINCARNATE;
|
rp->r_flags |= RS_REINCARNATE;
|
||||||
crash_service(rp); /* simulate crash */
|
crash_service(rp); /* simulate crash */
|
||||||
|
rp->r_init_err = result;
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the slot as no longer initializing. */
|
|
||||||
rp->r_flags &= ~RS_INITIALIZING;
|
|
||||||
rp->r_check_tm = 0;
|
|
||||||
getticks(&rp->r_alive_tm);
|
|
||||||
|
|
||||||
/* Reply and unblock the service before doing anything else. */
|
|
||||||
m.m_type = OK;
|
|
||||||
reply(rpub->endpoint, rp, &m);
|
|
||||||
|
|
||||||
/* See if a late reply has to be sent. */
|
|
||||||
late_reply(rp, OK);
|
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s initialized\n", srv_to_string(rp));
|
printf("RS: %s initialized\n", srv_to_string(rp));
|
||||||
|
|
||||||
/* If the service has completed initialization after a live
|
/* If updating, check if there is no service to update left. In that case,
|
||||||
* update, end the update now.
|
* end the update process. If VM has completed initialization as part of
|
||||||
|
* multi-component live update, let the other services under update run now.
|
||||||
*/
|
*/
|
||||||
if(rp->r_flags & RS_UPDATING) {
|
if(SRV_IS_UPDATING(rp)) {
|
||||||
printf("RS: update succeeded\n");
|
rupdate.num_init_ready_pending--;
|
||||||
end_update(OK, RS_DONTREPLY);
|
rp->r_flags |= RS_INIT_DONE;
|
||||||
}
|
if(rupdate.num_init_ready_pending == 0) {
|
||||||
|
printf("RS: update succeeded\n");
|
||||||
/* If the service has completed initialization after a crash
|
end_update(OK, RS_REPLY);
|
||||||
* make the new instance active and cleanup the old replica.
|
|
||||||
*/
|
|
||||||
if(rp->r_prev_rp) {
|
|
||||||
cleanup_service(rp->r_prev_rp);
|
|
||||||
rp->r_prev_rp = NULL;
|
|
||||||
rp->r_restarts += 1;
|
|
||||||
|
|
||||||
if(rs_verbose)
|
|
||||||
printf("RS: %s completed restart\n", srv_to_string(rp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we must keep a replica of this system service, create it now. */
|
|
||||||
if(rpub->sys_flags & SF_USE_REPL) {
|
|
||||||
if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
|
|
||||||
printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Mark the slot as no longer initializing. */
|
||||||
|
rp->r_flags &= ~RS_INITIALIZING;
|
||||||
|
rp->r_check_tm = 0;
|
||||||
|
getticks(&rp->r_alive_tm);
|
||||||
|
|
||||||
|
/* Reply and unblock the service before doing anything else. */
|
||||||
|
m.m_type = OK;
|
||||||
|
reply(rpub->endpoint, rp, &m);
|
||||||
|
|
||||||
|
/* Finalize initialization. */
|
||||||
|
end_srv_init(rp);
|
||||||
|
}
|
||||||
|
|
||||||
return is_rs ? OK : EDONTREPLY; /* return what the caller expects */
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -480,26 +527,25 @@ int do_init_ready(message *m_ptr)
|
||||||
int do_update(message *m_ptr)
|
int do_update(message *m_ptr)
|
||||||
{
|
{
|
||||||
struct rproc *rp;
|
struct rproc *rp;
|
||||||
|
struct rproc *trg_rp;
|
||||||
struct rproc *new_rp;
|
struct rproc *new_rp;
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
|
struct rprocupd *rpupd;
|
||||||
struct rs_start rs_start;
|
struct rs_start rs_start;
|
||||||
int noblock, do_self_update;
|
int noblock, do_self_update, force_self_update, batch_mode, prepare_only;
|
||||||
int s;
|
int s;
|
||||||
char label[RS_MAX_LABEL_LEN];
|
char label[RS_MAX_LABEL_LEN];
|
||||||
int lu_state;
|
int prepare_state, prepare_maxtime;
|
||||||
int prepare_maxtime;
|
endpoint_t state_endpoint;
|
||||||
|
int lu_flags = 0;
|
||||||
|
int init_flags = 0;
|
||||||
|
int allow_retries = 0;
|
||||||
|
|
||||||
/* Copy the request structure. */
|
/* Copy the request structure. */
|
||||||
s = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
|
s = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
|
||||||
if (s != OK) {
|
if (s != OK) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
noblock = (rs_start.rss_flags & RSS_NOBLOCK);
|
|
||||||
do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
|
|
||||||
s = check_request(&rs_start);
|
|
||||||
if (s != OK) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy label. */
|
/* Copy label. */
|
||||||
s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
|
s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
|
||||||
|
@ -517,130 +563,323 @@ int do_update(message *m_ptr)
|
||||||
}
|
}
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
/* Check flags. */
|
||||||
|
noblock = (rs_start.rss_flags & RSS_NOBLOCK);
|
||||||
|
do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
|
||||||
|
force_self_update = (rs_start.rss_flags & RSS_FORCE_SELF_LU);
|
||||||
|
batch_mode = (rs_start.rss_flags & RSS_BATCH);
|
||||||
|
prepare_only = (rs_start.rss_flags & RSS_PREPARE_ONLY_LU);
|
||||||
|
if(do_self_update || force_self_update) {
|
||||||
|
lu_flags |= SEF_LU_SELF;
|
||||||
|
}
|
||||||
|
if(prepare_only) {
|
||||||
|
lu_flags |= SEF_LU_PREPARE_ONLY;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_ASR_LU) {
|
||||||
|
lu_flags |= SEF_LU_ASR;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_UNSAFE_LU) {
|
||||||
|
lu_flags |= SEF_LU_UNSAFE;
|
||||||
|
}
|
||||||
|
if(!prepare_only && (rs_start.rss_flags & RSS_DETACH)) {
|
||||||
|
lu_flags |= SEF_LU_DETACHED;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_map_prealloc_bytes <= 0
|
||||||
|
&& rpub->endpoint == VM_PROC_NR
|
||||||
|
&& (((lu_flags & (SEF_LU_SELF|SEF_LU_ASR)) != SEF_LU_SELF) || rs_start.rss_flags & RSS_FORCE_INIT_ST)
|
||||||
|
&& RS_VM_DEFAULT_MAP_PREALLOC_LEN > 0) {
|
||||||
|
/* Give VM some mmapped regions by default on non-identical updates.*/
|
||||||
|
rs_start.rss_map_prealloc_bytes = RS_VM_DEFAULT_MAP_PREALLOC_LEN;
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s gets %ld default mmap bytes\n", srv_to_string(rp),
|
||||||
|
rs_start.rss_map_prealloc_bytes);
|
||||||
|
}
|
||||||
|
if((rs_start.rss_flags & RSS_NOMMAP_LU) || rs_start.rss_map_prealloc_bytes) {
|
||||||
|
/* Don't inherit mmapped regions at update time if requested or if
|
||||||
|
* mmap preallocation is used.
|
||||||
|
*/
|
||||||
|
lu_flags |= SEF_LU_NOMMAP;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_CRASH) {
|
||||||
|
init_flags |= SEF_INIT_CRASH;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_FAIL) {
|
||||||
|
init_flags |= SEF_INIT_FAIL;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_TIMEOUT) {
|
||||||
|
init_flags |= SEF_INIT_TIMEOUT;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_DEFCB) {
|
||||||
|
init_flags |= SEF_INIT_DEFCB;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_flags & RSS_FORCE_INIT_ST) {
|
||||||
|
init_flags |= SEF_INIT_ST;
|
||||||
|
}
|
||||||
|
init_flags |= lu_flags;
|
||||||
|
|
||||||
|
/* Lookup target label (if any). */
|
||||||
|
trg_rp = NULL;
|
||||||
|
state_endpoint = NONE;
|
||||||
|
if(rs_start.rss_trg_label.l_len > 0) {
|
||||||
|
s = copy_label(m_ptr->m_source, rs_start.rss_trg_label.l_addr,
|
||||||
|
rs_start.rss_trg_label.l_len, label, sizeof(label));
|
||||||
|
if(s != OK) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
trg_rp = lookup_slot_by_label(label);
|
||||||
|
if(!trg_rp) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: do_update: target service '%s' not found\n", label);
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
state_endpoint = trg_rp->r_pub->endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if the call can be allowed. */
|
/* Check if the call can be allowed. */
|
||||||
if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
|
if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
/* Retrieve live update state. */
|
/* Retrieve live update state. */
|
||||||
lu_state = m_ptr->m_rs_update.state;
|
prepare_state = m_ptr->m_rs_update.state;
|
||||||
if(lu_state == SEF_LU_STATE_NULL) {
|
if(prepare_state == SEF_LU_STATE_NULL) {
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve prepare max time. */
|
/* Retrieve prepare max time. */
|
||||||
prepare_maxtime = m_ptr->m_rs_update.prepare_maxtime;
|
prepare_maxtime = m_ptr->m_rs_update.prepare_maxtime;
|
||||||
if(prepare_maxtime) {
|
if(prepare_maxtime == 0) {
|
||||||
if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
|
|
||||||
return(EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
|
prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we are not already updating. */
|
/* Make sure we are not already updating. */
|
||||||
if(rupdate.flags & RS_UPDATING) {
|
if(RUPDATE_IS_UPDATING()) {
|
||||||
if(rs_verbose)
|
printf("RS: an update is already in progress\n");
|
||||||
printf("RS: do_update: an update is already in progress\n");
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If an update is already scheduled, check constraints. */
|
||||||
|
if(RUPDATE_IS_UPD_SCHEDULED()) {
|
||||||
|
if(!batch_mode) {
|
||||||
|
printf("RS: an update is already scheduled, cannot start a new one\n");
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
if(SRV_IS_UPD_SCHEDULED(rp)) {
|
||||||
|
printf("RS: the specified process is already part of the currently scheduled update\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if(rupdate.last_rpupd->rp->r_pub->endpoint == RS_PROC_NR) {
|
||||||
|
printf("RS: RS should always be the last service to update in a multi-component update\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare-only update for VM, PM, and VFS is only supported with an unreachable state. */
|
||||||
|
if(prepare_only
|
||||||
|
&& (rp->r_pub->endpoint == VM_PROC_NR || rp->r_pub->endpoint == PM_PROC_NR || rp->r_pub->endpoint == VFS_PROC_NR)) {
|
||||||
|
if(prepare_state != SEF_LU_STATE_UNREACHABLE) {
|
||||||
|
printf("RS: prepare-only update for VM, PM and VFS is only supported with state %d\n", SEF_LU_STATE_UNREACHABLE);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare-only update for RS is not supported. */
|
||||||
|
if(prepare_only && rp->r_pub->endpoint == RS_PROC_NR) {
|
||||||
|
printf("RS: prepare-only update for RS is not supported\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize update descriptor. */
|
||||||
|
rpupd = &rp->r_upd;
|
||||||
|
rupdate_upd_init(rpupd, rp);
|
||||||
|
rpupd->lu_flags |= lu_flags;
|
||||||
|
rpupd->init_flags |= init_flags;
|
||||||
|
rupdate_set_new_upd_flags(rpupd);
|
||||||
|
|
||||||
/* A self update live updates a service instance into a replica, a regular
|
/* A self update live updates a service instance into a replica, a regular
|
||||||
* update live updates a service instance into a new version, as specified
|
* update live updates a service instance into a new version, as specified
|
||||||
* by the given binary.
|
* by the given binary.
|
||||||
*/
|
*/
|
||||||
if(do_self_update) {
|
if(!prepare_only) {
|
||||||
if(rs_verbose)
|
if(do_self_update) {
|
||||||
printf("RS: %s performs self update\n", srv_to_string(rp));
|
if(rs_verbose)
|
||||||
|
printf("RS: %s requested to perform self update\n", srv_to_string(rp));
|
||||||
/* Clone the system service and use the replica as the new version. */
|
|
||||||
s = clone_service(rp, LU_SYS_PROC);
|
/* Clone the system service and use the replica as the new version. */
|
||||||
if(s != OK) {
|
s = clone_service(rp, LU_SYS_PROC, rpupd->init_flags);
|
||||||
printf("RS: do_update: unable to clone service: %d\n", s);
|
if(s != OK) {
|
||||||
return s;
|
printf("RS: do_update: unable to clone service: %d\n", s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
new_rp = rp->r_new_rp;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
if(rs_verbose)
|
||||||
if(rs_verbose)
|
printf("RS: %s requested to perform %s update\n", srv_to_string(rp),
|
||||||
printf("RS: %s performs regular update\n", srv_to_string(rp));
|
force_self_update ? "(forced) self" : "regular");
|
||||||
|
|
||||||
/* Allocate a system service slot for the new version. */
|
/* Allocate a system service slot for the new version. */
|
||||||
s = alloc_slot(&new_rp);
|
s = alloc_slot(&new_rp);
|
||||||
if(s != OK) {
|
if(s != OK) {
|
||||||
printf("RS: do_update: unable to allocate a new slot: %d\n", s);
|
printf("RS: do_update: unable to allocate a new slot: %d\n", s);
|
||||||
return s;
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the slot as requested. */
|
||||||
|
s = init_slot(new_rp, &rs_start, m_ptr->m_source);
|
||||||
|
if(s != OK) {
|
||||||
|
printf("RS: do_update: unable to init the new slot: %d\n", s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the new version inherit defaults from the old one. */
|
||||||
|
inherit_service_defaults(rp, new_rp);
|
||||||
|
|
||||||
|
/* Link the two versions. */
|
||||||
|
rp->r_new_rp = new_rp;
|
||||||
|
new_rp->r_old_rp = rp;
|
||||||
|
|
||||||
|
/* Create new version of the service but don't let it run. */
|
||||||
|
new_rp->r_priv.s_flags |= LU_SYS_PROC;
|
||||||
|
new_rp->r_priv.s_init_flags |= rpupd->init_flags;
|
||||||
|
s = create_service(new_rp);
|
||||||
|
if(s != OK) {
|
||||||
|
printf("RS: do_update: unable to create a new service: %d\n", s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the slot as requested. */
|
/* Set default state endpoint. */
|
||||||
s = init_slot(new_rp, &rs_start, m_ptr->m_source);
|
if(state_endpoint == NONE) {
|
||||||
if(s != OK) {
|
state_endpoint = new_rp->r_pub->endpoint;
|
||||||
printf("RS: do_update: unable to init the new slot: %d\n", s);
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Let the new version inherit defaults from the old one. */
|
/* If RS is updating, set up signal managers for the new instance.
|
||||||
inherit_service_defaults(rp, new_rp);
|
* The current RS instance must be made the backup signal manager to
|
||||||
|
* support rollback in case of a crash during initialization.
|
||||||
|
*/
|
||||||
|
if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
|
||||||
|
s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
|
||||||
|
if(s != OK) {
|
||||||
|
cleanup_service(new_rp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Link the two versions. */
|
/* Preallocate heap regions if requested. */
|
||||||
rp->r_new_rp = new_rp;
|
if(rs_start.rss_heap_prealloc_bytes < 0) {
|
||||||
new_rp->r_old_rp = rp;
|
rs_start.rss_heap_prealloc_bytes = 0;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_heap_prealloc_bytes) {
|
||||||
|
size_t len;
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s preallocating %ld heap bytes\n", srv_to_string(new_rp),
|
||||||
|
rs_start.rss_heap_prealloc_bytes);
|
||||||
|
|
||||||
/* Create new version of the service but don't let it run. */
|
len = rs_start.rss_heap_prealloc_bytes;
|
||||||
new_rp->r_priv.s_flags |= LU_SYS_PROC;
|
s = vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_HEAP_PREALLOC,
|
||||||
s = create_service(new_rp);
|
NULL, &len);
|
||||||
if(s != OK) {
|
if(s != OK) {
|
||||||
printf("RS: do_update: unable to create a new service: %d\n", s);
|
printf("vm_memctl(VM_RS_MEM_HEAP_PREALLOC) failed: %d\n", s);
|
||||||
return s;
|
cleanup_service(new_rp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
|
||||||
|
vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preallocate mmapped regions if requested. */
|
||||||
|
if(rs_start.rss_map_prealloc_bytes < 0) {
|
||||||
|
rs_start.rss_map_prealloc_bytes = 0;
|
||||||
|
}
|
||||||
|
if(rs_start.rss_map_prealloc_bytes) {
|
||||||
|
void *addr = NULL;
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s preallocating %ld mmap bytes\n", srv_to_string(new_rp),
|
||||||
|
rs_start.rss_map_prealloc_bytes);
|
||||||
|
|
||||||
|
new_rp->r_map_prealloc_len = rs_start.rss_map_prealloc_bytes;
|
||||||
|
s = vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_MAP_PREALLOC,
|
||||||
|
&addr, &new_rp->r_map_prealloc_len);
|
||||||
|
if(s != OK) {
|
||||||
|
printf("vm_memctl(VM_RS_MEM_MAP_PREALLOC) failed: %d\n", s);
|
||||||
|
cleanup_service(new_rp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
new_rp->r_map_prealloc_addr = (vir_bytes) addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark both versions as updating. */
|
/* Process state data. */
|
||||||
rp->r_flags |= RS_UPDATING;
|
s = init_state_data(m_ptr->m_source, prepare_state, &rs_start.rss_state_data, &rpupd->prepare_state_data);
|
||||||
rp->r_new_rp->r_flags |= RS_UPDATING;
|
if(s != OK) {
|
||||||
rupdate.flags |= RS_UPDATING;
|
rupdate_upd_clear(rpupd);
|
||||||
getticks(&rupdate.prepare_tm);
|
return s;
|
||||||
rupdate.prepare_maxtime = prepare_maxtime;
|
}
|
||||||
rupdate.rp = rp;
|
|
||||||
|
/* Create update grants. */
|
||||||
|
if(rpupd->prepare_state_data.size > 0) {
|
||||||
|
struct rs_state_data *state_data = &rpupd->prepare_state_data;
|
||||||
|
rpupd->prepare_state_data_gid = cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data,
|
||||||
|
state_data->size, CPF_READ);
|
||||||
|
if(rpupd->prepare_state_data_gid == GRANT_INVALID) {
|
||||||
|
rupdate_upd_clear(rpupd);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
state_data->ipcf_els_gid = GRANT_INVALID;
|
||||||
|
if(state_data->ipcf_els) {
|
||||||
|
state_data->ipcf_els_gid = (int) cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data->ipcf_els,
|
||||||
|
state_data->ipcf_els_size, CPF_READ);
|
||||||
|
if(state_data->ipcf_els_gid == GRANT_INVALID) {
|
||||||
|
rupdate_upd_clear(rpupd);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state_data->eval_gid = GRANT_INVALID;
|
||||||
|
if(state_data->eval_addr) {
|
||||||
|
state_data->eval_gid = (int) cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data->eval_addr,
|
||||||
|
state_data->eval_len, CPF_READ);
|
||||||
|
if(state_data->eval_gid == GRANT_INVALID) {
|
||||||
|
rupdate_upd_clear(rpupd);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the new update descriptor and add it to the update chain. */
|
||||||
|
rpupd->prepare_state = prepare_state;
|
||||||
|
rpupd->state_endpoint = state_endpoint;
|
||||||
|
getticks(&rpupd->prepare_tm);
|
||||||
|
rpupd->prepare_maxtime = prepare_maxtime;
|
||||||
|
rupdate_add_upd(rpupd);
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s updating\n", srv_to_string(rp));
|
printf("RS: %s scheduled for %s\n", srv_to_string(rp), srv_upd_to_string(rpupd));
|
||||||
|
|
||||||
/* If RS is updating, set up signal managers for the new instance.
|
/* If batch mode, reply immediately. More services to update will follow. */
|
||||||
* The current RS instance must be made the backup signal manager to
|
if(batch_mode) {
|
||||||
* support rollback in case of a crash during initialization.
|
return OK;
|
||||||
*/
|
|
||||||
if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
|
|
||||||
new_rp = rp->r_new_rp;
|
|
||||||
|
|
||||||
s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
|
|
||||||
if(s != OK) {
|
|
||||||
cleanup_service(new_rp);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start preparing for the update process. */
|
||||||
|
s = start_update_prepare(allow_retries);
|
||||||
|
if(s == ESRCH) {
|
||||||
|
/* No process left in the update chain. We are done already. */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if(s != OK) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unblock the caller immediately if requested. */
|
||||||
if(noblock) {
|
if(noblock) {
|
||||||
/* Unblock the caller immediately if requested. */
|
return OK;
|
||||||
m_ptr->m_type = OK;
|
|
||||||
reply(m_ptr->m_source, NULL, m_ptr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Send a reply when the new version completes initialization. */
|
|
||||||
rp->r_flags |= RS_LATEREPLY;
|
|
||||||
rp->r_caller = m_ptr->m_source;
|
|
||||||
rp->r_caller_request = RS_UPDATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request to update. */
|
/* Otherwise, send a reply when the new version completes initialization. */
|
||||||
m_ptr->m_type = RS_LU_PREPARE;
|
rupdate.last_rpupd->rp->r_flags |= RS_LATEREPLY;
|
||||||
if(rpub->endpoint == RS_PROC_NR) {
|
rupdate.last_rpupd->rp->r_caller = m_ptr->m_source;
|
||||||
/* RS can process the request directly. */
|
rupdate.last_rpupd->rp->r_caller_request = RS_UPDATE;
|
||||||
do_sef_lu_request(m_ptr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Send request message to the system service. */
|
|
||||||
asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
@ -650,75 +889,51 @@ int do_update(message *m_ptr)
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int do_upd_ready(message *m_ptr)
|
int do_upd_ready(message *m_ptr)
|
||||||
{
|
{
|
||||||
struct rproc *rp, *old_rp, *new_rp;
|
struct rproc *rp;
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
int who_p;
|
int who_p;
|
||||||
int result;
|
int result;
|
||||||
int is_rs;
|
int is_rs;
|
||||||
int r;
|
int i;
|
||||||
|
|
||||||
who_p = _ENDPOINT_P(m_ptr->m_source);
|
who_p = _ENDPOINT_P(m_ptr->m_source);
|
||||||
rp = rproc_ptr[who_p];
|
rp = rproc_ptr[who_p];
|
||||||
result = m_ptr->m_rs_update.result;
|
result = m_ptr->m_rs_update.result;
|
||||||
is_rs = (m_ptr->m_source == RS_PROC_NR);
|
|
||||||
|
|
||||||
/* Make sure the originating service was requested to prepare for update. */
|
/* Make sure the originating service was requested to prepare for update. */
|
||||||
if(rp != rupdate.rp) {
|
rpupd = rupdate.curr_rpupd;
|
||||||
|
if(!rpupd || rp != rpupd->rp || RUPDATE_IS_INITIALIZING()) {
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
|
printf("RS: %s sent late/unexpected update ready msg\n",
|
||||||
m_ptr->m_source);
|
srv_to_string(rp));
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
rp->r_flags |= RS_PREPARE_DONE;
|
||||||
|
|
||||||
/* Check if something went wrong and the service failed to prepare
|
/* Check if something went wrong and the service failed to prepare
|
||||||
* for the update. In that case, end the update process. The old version will
|
* for the update. In that case, end the update process. The old version will
|
||||||
* be replied to and continue executing.
|
* be replied to and continue executing.
|
||||||
*/
|
*/
|
||||||
if(result != OK) {
|
if(result != OK) {
|
||||||
|
printf("RS: update failed: %s\n", lu_strerror(result));
|
||||||
end_update(result, RS_REPLY);
|
end_update(result, RS_REPLY);
|
||||||
|
|
||||||
printf("RS: update failed: %s\n", lu_strerror(result));
|
|
||||||
return is_rs ? result : EDONTREPLY; /* return what the caller expects */
|
|
||||||
}
|
|
||||||
|
|
||||||
old_rp = rp;
|
|
||||||
new_rp = rp->r_new_rp;
|
|
||||||
|
|
||||||
/* If RS itself is updating, yield control to the new version immediately. */
|
|
||||||
if(is_rs) {
|
|
||||||
r = init_service(new_rp, SEF_INIT_LU);
|
|
||||||
if(r != OK) {
|
|
||||||
panic("unable to initialize the new RS instance: %d", r);
|
|
||||||
}
|
|
||||||
r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
|
|
||||||
if(r != OK) {
|
|
||||||
panic("unable to yield control to the new RS instance: %d", r);
|
|
||||||
}
|
|
||||||
/* If we get this far, the new version failed to initialize. Rollback. */
|
|
||||||
r = srv_update(RS_PROC_NR, new_rp->r_pub->endpoint);
|
|
||||||
assert(r == OK); /* can't fail */
|
|
||||||
end_update(ERESTART, RS_REPLY);
|
|
||||||
return ERESTART;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform the update. */
|
|
||||||
r = update_service(&old_rp, &new_rp, RS_SWAP);
|
|
||||||
if(r != OK) {
|
|
||||||
end_update(r, RS_REPLY);
|
|
||||||
printf("RS: update failed: error %d\n", r);
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Let the new version run. */
|
if(rs_verbose)
|
||||||
r = run_service(new_rp, SEF_INIT_LU);
|
printf("RS: %s ready to update\n", srv_to_string(rp));
|
||||||
if(r != OK) {
|
|
||||||
/* Something went wrong. Rollback. */
|
/* If this is a multi-component update and this is not the last service
|
||||||
r = update_service(&new_rp, &old_rp, RS_SWAP);
|
* in the update, request the next process to update.
|
||||||
assert(r == OK); /* can't fail */
|
*/
|
||||||
end_update(r, RS_REPLY);
|
if(start_update_prepare_next() != NULL) {
|
||||||
printf("RS: update failed: error %d\n", r);
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now perform the update and request each new instance to initialize. */
|
||||||
|
start_update();
|
||||||
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,7 +950,7 @@ message *m_ptr;
|
||||||
long period;
|
long period;
|
||||||
|
|
||||||
/* If an update is in progress, check its status. */
|
/* If an update is in progress, check its status. */
|
||||||
if(rupdate.flags & RS_UPDATING) {
|
if(RUPDATE_IS_UPDATING() && !RUPDATE_IS_INITIALIZING()) {
|
||||||
update_period(m_ptr);
|
update_period(m_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,12 +959,13 @@ message *m_ptr;
|
||||||
*/
|
*/
|
||||||
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
if ((rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_UPDATING)) {
|
|
||||||
|
if ((rp->r_flags & RS_ACTIVE) && (!SRV_IS_UPDATING(rp) || ((rp->r_flags & (RS_INITIALIZING|RS_INIT_DONE|RS_INIT_PENDING)) == RS_INITIALIZING))) {
|
||||||
|
|
||||||
/* Compute period. */
|
/* Compute period. */
|
||||||
period = rp->r_period;
|
period = rp->r_period;
|
||||||
if(rp->r_flags & RS_INITIALIZING) {
|
if(rp->r_flags & RS_INITIALIZING) {
|
||||||
period = RS_INIT_T;
|
period = SRV_IS_UPDATING(rp) ? UPD_INIT_MAXTIME(&rp->r_upd) : RS_INIT_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the service is to be revived (because it repeatedly exited,
|
/* If the service is to be revived (because it repeatedly exited,
|
||||||
|
@ -787,10 +1003,16 @@ message *m_ptr;
|
||||||
*/
|
*/
|
||||||
if (rp->r_alive_tm < rp->r_check_tm) {
|
if (rp->r_alive_tm < rp->r_check_tm) {
|
||||||
if (now - rp->r_alive_tm > 2*period &&
|
if (now - rp->r_alive_tm > 2*period &&
|
||||||
rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
|
rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
|
||||||
|
struct rproc *rp2;
|
||||||
|
int init_flag;
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s reported late\n", srv_to_string(rp));
|
printf("RS: %s reported late\n", srv_to_string(rp));
|
||||||
if(lookup_slot_by_flags(RS_INITIALIZING)) {
|
init_flag = rp->r_flags & RS_INITIALIZING;
|
||||||
|
rp->r_flags &= ~RS_INITIALIZING;
|
||||||
|
rp2 = lookup_slot_by_flags(RS_INITIALIZING);
|
||||||
|
rp->r_flags |= init_flag;
|
||||||
|
if(rp2 != NULL && !SRV_IS_UPDATING(rp)) {
|
||||||
/* Skip for now. */
|
/* Skip for now. */
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: %s gets a free pass\n",
|
printf("RS: %s gets a free pass\n",
|
||||||
|
@ -801,6 +1023,9 @@ message *m_ptr;
|
||||||
}
|
}
|
||||||
rp->r_flags |= RS_NOPINGREPLY;
|
rp->r_flags |= RS_NOPINGREPLY;
|
||||||
crash_service(rp); /* simulate crash */
|
crash_service(rp); /* simulate crash */
|
||||||
|
if(rp->r_flags & RS_INITIALIZING) {
|
||||||
|
rp->r_init_err = EINTR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,7 +1055,7 @@ void do_sigchld()
|
||||||
int status;
|
int status;
|
||||||
struct rproc *rp;
|
struct rproc *rp;
|
||||||
struct rproc **rps;
|
struct rproc **rps;
|
||||||
int i, nr_rps;
|
int i, nr_rps, found;
|
||||||
|
|
||||||
if(rs_verbose)
|
if(rs_verbose)
|
||||||
printf("RS: got SIGCHLD signal, cleaning up dead children\n");
|
printf("RS: got SIGCHLD signal, cleaning up dead children\n");
|
||||||
|
@ -848,13 +1073,18 @@ void do_sigchld()
|
||||||
* free slots for all the service instances and send a late
|
* free slots for all the service instances and send a late
|
||||||
* reply if necessary.
|
* reply if necessary.
|
||||||
*/
|
*/
|
||||||
|
found = 0;
|
||||||
get_service_instances(rp, &rps, &nr_rps);
|
get_service_instances(rp, &rps, &nr_rps);
|
||||||
for(i=0;i<nr_rps;i++) {
|
for(i=0;i<nr_rps;i++) {
|
||||||
if(rupdate.flags & RS_UPDATING) {
|
if(SRV_IS_UPDATING(rps[i])) {
|
||||||
rupdate.flags &= ~RS_UPDATING;
|
rps[i]->r_flags &= ~(RS_UPDATING|RS_PREPARE_DONE|RS_INIT_DONE|RS_INIT_PENDING);
|
||||||
|
found = 1;
|
||||||
}
|
}
|
||||||
free_slot(rps[i]);
|
free_slot(rps[i]);
|
||||||
}
|
}
|
||||||
|
if(found) {
|
||||||
|
rupdate_clear_upds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -945,6 +1175,54 @@ message *m_ptr;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* do_sysctl *
|
||||||
|
*===========================================================================*/
|
||||||
|
int do_sysctl(message *m_ptr)
|
||||||
|
{
|
||||||
|
int request_type = m_ptr->m_rs_req.subtype;
|
||||||
|
int r, allow_retries = 1;
|
||||||
|
switch(request_type) {
|
||||||
|
case RS_SYSCTL_SRV_STATUS:
|
||||||
|
print_services_status();
|
||||||
|
break;
|
||||||
|
case RS_SYSCTL_UPD_START:
|
||||||
|
case RS_SYSCTL_UPD_RUN:
|
||||||
|
r = start_update_prepare(allow_retries);
|
||||||
|
print_update_status();
|
||||||
|
if(r != OK) {
|
||||||
|
if(r == ESRCH) {
|
||||||
|
/* We are done already. */
|
||||||
|
r = OK;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if(request_type == RS_SYSCTL_UPD_START) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
/* Send a reply when done. */
|
||||||
|
rupdate.last_rpupd->rp->r_flags |= RS_LATEREPLY;
|
||||||
|
rupdate.last_rpupd->rp->r_caller = m_ptr->m_source;
|
||||||
|
rupdate.last_rpupd->rp->r_caller_request = RS_UPDATE;
|
||||||
|
return EDONTREPLY;
|
||||||
|
break;
|
||||||
|
case RS_SYSCTL_UPD_STOP:
|
||||||
|
r = abort_update_proc(EINTR);
|
||||||
|
print_update_status();
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
case RS_SYSCTL_UPD_STATUS:
|
||||||
|
print_update_status();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("RS: bad sysctl type\n");
|
||||||
|
return EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* check_request *
|
* check_request *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
|
@ -25,6 +25,32 @@ struct boot_image_dev {
|
||||||
dev_t dev_nr; /* major device number */
|
dev_t dev_nr; /* major device number */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Definition of the update descriptors. */
|
||||||
|
struct rproc;
|
||||||
|
struct rprocupd {
|
||||||
|
int lu_flags; /* user-specified live update flags */
|
||||||
|
int init_flags; /* user-specified init flags */
|
||||||
|
int prepare_state; /* the state the process has to prepare for the update */
|
||||||
|
endpoint_t state_endpoint; /* the custom process to transfer the state from (if any). */
|
||||||
|
clock_t prepare_tm; /* timestamp of when the update was scheduled */
|
||||||
|
clock_t prepare_maxtime; /* max time to wait for the process to be ready */
|
||||||
|
struct rproc *rp; /* the process under update */
|
||||||
|
struct rs_state_data prepare_state_data; /* state data for the update */
|
||||||
|
cp_grant_id_t prepare_state_data_gid; /* state data gid */
|
||||||
|
struct rprocupd *prev_rpupd; /* the previous process under update */
|
||||||
|
struct rprocupd *next_rpupd; /* the next process under update */
|
||||||
|
};
|
||||||
|
struct rupdate {
|
||||||
|
int flags; /* flags to keep track of the status of the update */
|
||||||
|
int num_rpupds; /* number of descriptors scheduled for the update */
|
||||||
|
int num_init_ready_pending; /* number of pending init ready messages */
|
||||||
|
struct rprocupd *curr_rpupd; /* the current descriptor under update */
|
||||||
|
struct rprocupd *first_rpupd; /* first descriptor scheduled for the update */
|
||||||
|
struct rprocupd *last_rpupd; /* last descriptor scheduled for the update */
|
||||||
|
struct rprocupd *vm_rpupd; /* VM descriptor scheduled for the update */
|
||||||
|
struct rprocupd *rs_rpupd; /* RS descriptor scheduled for the update */
|
||||||
|
};
|
||||||
|
|
||||||
/* Definition of an entry of the system process table. */
|
/* Definition of an entry of the system process table. */
|
||||||
struct rproc {
|
struct rproc {
|
||||||
struct rprocpub *r_pub; /* pointer to the corresponding public entry */
|
struct rprocpub *r_pub; /* pointer to the corresponding public entry */
|
||||||
|
@ -32,11 +58,13 @@ struct rproc {
|
||||||
struct rproc *r_new_rp; /* pointer to the slot with the new version */
|
struct rproc *r_new_rp; /* pointer to the slot with the new version */
|
||||||
struct rproc *r_prev_rp; /* pointer to the slot with the prev replica */
|
struct rproc *r_prev_rp; /* pointer to the slot with the prev replica */
|
||||||
struct rproc *r_next_rp; /* pointer to the slot with the next replica */
|
struct rproc *r_next_rp; /* pointer to the slot with the next replica */
|
||||||
|
struct rprocupd r_upd; /* update descriptor */
|
||||||
pid_t r_pid; /* process id, -1 if the process is not there */
|
pid_t r_pid; /* process id, -1 if the process is not there */
|
||||||
|
|
||||||
int r_restarts; /* number of restarts (initially zero) */
|
int r_restarts; /* number of restarts (initially zero) */
|
||||||
long r_backoff; /* number of periods to wait before revive */
|
long r_backoff; /* number of periods to wait before revive */
|
||||||
unsigned r_flags; /* status and policy flags */
|
unsigned r_flags; /* status and policy flags */
|
||||||
|
int r_init_err; /* error code at initialization time */
|
||||||
|
|
||||||
long r_period; /* heartbeat period (or zero) */
|
long r_period; /* heartbeat period (or zero) */
|
||||||
clock_t r_check_tm; /* timestamp of last check */
|
clock_t r_check_tm; /* timestamp of last check */
|
||||||
|
@ -63,6 +91,8 @@ struct rproc {
|
||||||
int r_priority; /* negative values are reserved for special meanings */
|
int r_priority; /* negative values are reserved for special meanings */
|
||||||
int r_quantum;
|
int r_quantum;
|
||||||
int r_cpu;
|
int r_cpu;
|
||||||
|
vir_bytes r_map_prealloc_addr; /* preallocated mmap address */
|
||||||
|
size_t r_map_prealloc_len; /* preallocated mmap len */
|
||||||
|
|
||||||
/* Backup values from the privilege structure. */
|
/* Backup values from the privilege structure. */
|
||||||
struct io_range r_io_tab[NR_IO_RANGE];
|
struct io_range r_io_tab[NR_IO_RANGE];
|
||||||
|
@ -75,12 +105,6 @@ struct rproc {
|
||||||
char r_control[RS_NR_CONTROL][RS_MAX_LABEL_LEN];
|
char r_control[RS_NR_CONTROL][RS_MAX_LABEL_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Definition of the global update descriptor. */
|
|
||||||
struct rupdate {
|
|
||||||
int flags; /* flags to keep track of the status of the update */
|
|
||||||
clock_t prepare_tm; /* timestamp of when the update was scheduled */
|
|
||||||
clock_t prepare_maxtime; /* max time to wait for the process to be ready */
|
|
||||||
struct rproc *rp; /* the process under update */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* RS_TYPE_H */
|
#endif /* RS_TYPE_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
960
minix/servers/rs/update.c
Normal file
960
minix/servers/rs/update.c
Normal file
|
@ -0,0 +1,960 @@
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_clear_upds *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_clear_upds()
|
||||||
|
{
|
||||||
|
/* Clear the update chain and the global update descriptor. */
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(prev_rpupd) {
|
||||||
|
rupdate_upd_clear(prev_rpupd);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
rupdate_upd_clear(rupdate.last_rpupd);
|
||||||
|
RUPDATE_CLEAR();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_add_upd *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_add_upd(struct rprocupd* rpupd)
|
||||||
|
{
|
||||||
|
/* Add an update descriptor to the update chain. */
|
||||||
|
struct rprocupd* prev_rpupd;
|
||||||
|
int lu_flags;
|
||||||
|
|
||||||
|
rpupd->prev_rpupd = rupdate.last_rpupd;
|
||||||
|
if(rupdate.num_rpupds == 0) {
|
||||||
|
rupdate.first_rpupd = rpupd;
|
||||||
|
rupdate.curr_rpupd = rpupd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rupdate.last_rpupd->next_rpupd = rpupd;
|
||||||
|
}
|
||||||
|
rupdate.last_rpupd = rpupd;
|
||||||
|
rupdate.num_rpupds++;
|
||||||
|
|
||||||
|
/* Propagate relevant flags from the new descriptor. */
|
||||||
|
lu_flags = rpupd->lu_flags & (SEF_LU_INCLUDES_VM|SEF_LU_INCLUDES_RS|SEF_LU_UNSAFE|SEF_LU_MULTI);
|
||||||
|
if(lu_flags) {
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
rpupd->lu_flags |= lu_flags;
|
||||||
|
rpupd->init_flags |= lu_flags;
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set VM/RS update descriptor pointers. */
|
||||||
|
if(!rupdate.vm_rpupd && (lu_flags & SEF_LU_INCLUDES_VM)) {
|
||||||
|
rupdate.vm_rpupd = rupdate.last_rpupd;
|
||||||
|
}
|
||||||
|
else if(!rupdate.rs_rpupd && (lu_flags & SEF_LU_INCLUDES_RS)) {
|
||||||
|
rupdate.rs_rpupd = rupdate.last_rpupd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_set_new_upd_flags *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_set_new_upd_flags(struct rprocupd* rpupd)
|
||||||
|
{
|
||||||
|
/* Set multi-component update flags. */
|
||||||
|
if(rupdate.num_rpupds > 0) {
|
||||||
|
rpupd->lu_flags |= SEF_LU_MULTI;
|
||||||
|
rpupd->init_flags |= SEF_LU_MULTI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Propagate relevant flags from last service under update (if any). */
|
||||||
|
if(rupdate.last_rpupd) {
|
||||||
|
int lu_flags = rupdate.last_rpupd->lu_flags & (SEF_LU_INCLUDES_VM|SEF_LU_INCLUDES_RS|SEF_LU_UNSAFE);
|
||||||
|
rpupd->lu_flags |= lu_flags;
|
||||||
|
rpupd->init_flags |= lu_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set VM/RS update flags. */
|
||||||
|
if(rpupd->rp->r_pub->endpoint == VM_PROC_NR) {
|
||||||
|
rpupd->lu_flags |= SEF_LU_INCLUDES_VM;
|
||||||
|
rpupd->init_flags |= SEF_LU_INCLUDES_VM;
|
||||||
|
}
|
||||||
|
else if(rpupd->rp->r_pub->endpoint == RS_PROC_NR) {
|
||||||
|
rpupd->lu_flags |= SEF_LU_INCLUDES_RS;
|
||||||
|
rpupd->init_flags |= SEF_LU_INCLUDES_RS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_upd_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_upd_init(struct rprocupd* rpupd, struct rproc *rp)
|
||||||
|
{
|
||||||
|
/* Initialize an update descriptor for a given service. */
|
||||||
|
memset(rpupd, 0, sizeof(*(rpupd)));
|
||||||
|
rpupd->prepare_state_data_gid = GRANT_INVALID;
|
||||||
|
rpupd->prepare_state_data.ipcf_els_gid = GRANT_INVALID;
|
||||||
|
rpupd->prepare_state_data.eval_gid = GRANT_INVALID;
|
||||||
|
rpupd->state_endpoint = NONE;
|
||||||
|
rpupd->rp = rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_upd_clear *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_upd_clear(struct rprocupd* rpupd)
|
||||||
|
{
|
||||||
|
/* Clear an update descriptor. */
|
||||||
|
if(rpupd->rp->r_new_rp) {
|
||||||
|
cleanup_service(rpupd->rp->r_new_rp);
|
||||||
|
}
|
||||||
|
if(rpupd->prepare_state_data_gid != GRANT_INVALID) {
|
||||||
|
cpf_revoke(rpupd->prepare_state_data_gid);
|
||||||
|
}
|
||||||
|
if(rpupd->prepare_state_data.size > 0) {
|
||||||
|
if(rpupd->prepare_state_data.ipcf_els_gid != GRANT_INVALID) {
|
||||||
|
cpf_revoke(rpupd->prepare_state_data.ipcf_els_gid);
|
||||||
|
}
|
||||||
|
if(rpupd->prepare_state_data.eval_gid != GRANT_INVALID) {
|
||||||
|
cpf_revoke(rpupd->prepare_state_data.eval_gid);
|
||||||
|
}
|
||||||
|
if(rpupd->prepare_state_data.ipcf_els) {
|
||||||
|
free(rpupd->prepare_state_data.ipcf_els);
|
||||||
|
}
|
||||||
|
if(rpupd->prepare_state_data.eval_addr) {
|
||||||
|
free(rpupd->prepare_state_data.eval_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rupdate_upd_init(rpupd,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rupdate_upd_move *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rupdate_upd_move(struct rproc* src_rp, struct rproc* dst_rp)
|
||||||
|
{
|
||||||
|
/* Move an update descriptor from one service instance to another. */
|
||||||
|
dst_rp->r_upd = src_rp->r_upd;
|
||||||
|
dst_rp->r_upd.rp = dst_rp;
|
||||||
|
if(src_rp->r_new_rp) {
|
||||||
|
assert(!dst_rp->r_new_rp);
|
||||||
|
dst_rp->r_new_rp = src_rp->r_new_rp;
|
||||||
|
dst_rp->r_new_rp->r_old_rp = dst_rp;
|
||||||
|
}
|
||||||
|
if(dst_rp->r_upd.prev_rpupd) dst_rp->r_upd.prev_rpupd->next_rpupd = &dst_rp->r_upd;
|
||||||
|
if(dst_rp->r_upd.next_rpupd) dst_rp->r_upd.next_rpupd->prev_rpupd = &dst_rp->r_upd;
|
||||||
|
if(rupdate.first_rpupd == &src_rp->r_upd) rupdate.first_rpupd = &dst_rp->r_upd;
|
||||||
|
if(rupdate.last_rpupd == &src_rp->r_upd) rupdate.last_rpupd = &dst_rp->r_upd;
|
||||||
|
rupdate_upd_init(&src_rp->r_upd, NULL);
|
||||||
|
src_rp->r_new_rp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* request_prepare_update_service_debug *
|
||||||
|
*===========================================================================*/
|
||||||
|
void request_prepare_update_service_debug(char *file, int line,
|
||||||
|
struct rproc *rp, int state)
|
||||||
|
{
|
||||||
|
/* Request a service to prepare/cancel the update. */
|
||||||
|
message m;
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
int no_reply;
|
||||||
|
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
if(state != SEF_LU_STATE_NULL) {
|
||||||
|
struct rprocupd *rpupd = &rp->r_upd;
|
||||||
|
getticks(&rpupd->prepare_tm);
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
assert(rp->r_new_rp);
|
||||||
|
rp->r_flags |= RS_UPDATING;
|
||||||
|
rp->r_new_rp->r_flags |= RS_UPDATING;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(!rp->r_new_rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.m_rs_update.flags = rpupd->lu_flags;
|
||||||
|
m.m_rs_update.state_data_gid = rpupd->prepare_state_data_gid;
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s being requested to prepare for the %s at %s:%d\n",
|
||||||
|
srv_to_string(rp), srv_upd_to_string(rpupd), file, line);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s being requested to cancel the update at %s:%d\n",
|
||||||
|
srv_to_string(rp), file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request to prepare for the update or cancel the update. */
|
||||||
|
m.m_type = RS_LU_PREPARE;
|
||||||
|
m.m_rs_update.state = state;
|
||||||
|
no_reply = !(rp->r_flags & RS_PREPARE_DONE);
|
||||||
|
rs_asynsend(rp, &m, no_reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* srv_update *
|
||||||
|
*===========================================================================*/
|
||||||
|
int srv_update(endpoint_t src_e, endpoint_t dst_e, int sys_upd_flags)
|
||||||
|
{
|
||||||
|
int r = OK;
|
||||||
|
|
||||||
|
/* Ask VM to swap the slots of the two processes and tell the kernel to
|
||||||
|
* do the same. If VM is being updated, only perform the kernel
|
||||||
|
* part of the call. The new instance of VM will do the rest at
|
||||||
|
* initialization time. If a multi-component update includes VM, let VM
|
||||||
|
* handle updates at state transfer time and rollbacks afterwards.
|
||||||
|
*/
|
||||||
|
if(src_e == VM_PROC_NR) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: executing sys_update(%d, %d)\n", src_e, dst_e);
|
||||||
|
r = sys_update(src_e, dst_e,
|
||||||
|
sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0);
|
||||||
|
}
|
||||||
|
else if(!RUPDATE_IS_UPD_VM_MULTI() || RUPDATE_IS_VM_INIT_DONE()) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: executing vm_update(%d, %d)\n", src_e, dst_e);
|
||||||
|
r = vm_update(src_e, dst_e, sys_upd_flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: skipping srv_update(%d, %d)\n", src_e, dst_e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* update_service *
|
||||||
|
*===========================================================================*/
|
||||||
|
int update_service(src_rpp, dst_rpp, swap_flag, sys_upd_flags)
|
||||||
|
struct rproc **src_rpp;
|
||||||
|
struct rproc **dst_rpp;
|
||||||
|
int swap_flag;
|
||||||
|
int sys_upd_flags;
|
||||||
|
{
|
||||||
|
/* Update an existing service. */
|
||||||
|
int r;
|
||||||
|
struct rproc *src_rp;
|
||||||
|
struct rproc *dst_rp;
|
||||||
|
struct rprocpub *src_rpub;
|
||||||
|
struct rprocpub *dst_rpub;
|
||||||
|
int pid;
|
||||||
|
endpoint_t endpoint;
|
||||||
|
|
||||||
|
src_rp = *src_rpp;
|
||||||
|
dst_rp = *dst_rpp;
|
||||||
|
src_rpub = src_rp->r_pub;
|
||||||
|
dst_rpub = dst_rp->r_pub;
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s updating into %s\n",
|
||||||
|
srv_to_string(src_rp), srv_to_string(dst_rp));
|
||||||
|
|
||||||
|
/* Swap the slots of the two processes when asked to. */
|
||||||
|
if(swap_flag == RS_SWAP) {
|
||||||
|
if((r = srv_update(src_rpub->endpoint, dst_rpub->endpoint, sys_upd_flags)) != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap slots here as well. */
|
||||||
|
pid = src_rp->r_pid;
|
||||||
|
endpoint = src_rpub->endpoint;
|
||||||
|
swap_slot(&src_rp, &dst_rp);
|
||||||
|
|
||||||
|
/* Reassign pids and endpoints. */
|
||||||
|
src_rp->r_pid = dst_rp->r_pid;
|
||||||
|
src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint;
|
||||||
|
rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp;
|
||||||
|
dst_rp->r_pid = pid;
|
||||||
|
dst_rp->r_pub->endpoint = endpoint;
|
||||||
|
rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
|
||||||
|
|
||||||
|
/* Adjust input pointers. */
|
||||||
|
*src_rpp = src_rp;
|
||||||
|
*dst_rpp = dst_rp;
|
||||||
|
|
||||||
|
/* Make the new version active. */
|
||||||
|
activate_service(dst_rp, src_rp);
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s updated into %s\n",
|
||||||
|
srv_to_string(src_rp), srv_to_string(dst_rp));
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rollback_service *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rollback_service(struct rproc **new_rpp, struct rproc **old_rpp)
|
||||||
|
{
|
||||||
|
/* Rollback an updated service. */
|
||||||
|
int r = OK;
|
||||||
|
|
||||||
|
/* RS is special, we may only need to swap the slots to rollback. */
|
||||||
|
if((*old_rpp)->r_pub->endpoint == RS_PROC_NR) {
|
||||||
|
endpoint_t me = NONE;
|
||||||
|
char name[20];
|
||||||
|
int priv_flags, init_flags;
|
||||||
|
|
||||||
|
r = sys_whoami(&me, name, sizeof(name), &priv_flags, &init_flags);
|
||||||
|
assert(r == OK);
|
||||||
|
if(me != RS_PROC_NR) {
|
||||||
|
r = vm_update((*new_rpp)->r_pub->endpoint, (*old_rpp)->r_pub->endpoint, SF_VM_ROLLBACK);
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s performed rollback\n", srv_to_string(*new_rpp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int swap_flag = ((*new_rpp)->r_flags & RS_INIT_PENDING ? RS_DONTSWAP : RS_SWAP);
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s performs rollback\n", srv_to_string(*new_rpp));
|
||||||
|
if(swap_flag == RS_SWAP) {
|
||||||
|
/* Freeze the new instance to rollback safely. */
|
||||||
|
sys_privctl((*new_rpp)->r_pub->endpoint, SYS_PRIV_DISALLOW, NULL);
|
||||||
|
}
|
||||||
|
r = update_service(new_rpp, old_rpp, swap_flag, SF_VM_ROLLBACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(r == OK); /* can't fail */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* update_period *
|
||||||
|
*===========================================================================*/
|
||||||
|
void update_period(message *m_ptr)
|
||||||
|
{
|
||||||
|
/* Periodically check the status of the update (preparation phase). */
|
||||||
|
clock_t now = m_ptr->m_notify.timestamp;
|
||||||
|
short has_update_timed_out;
|
||||||
|
message m;
|
||||||
|
struct rprocupd *rpupd;
|
||||||
|
struct rproc *rp;
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
|
||||||
|
rpupd = rupdate.curr_rpupd;
|
||||||
|
rp = rpupd->rp;
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
/* See if a timeout has occurred. */
|
||||||
|
has_update_timed_out = (rpupd->prepare_maxtime > 0) && (now - rpupd->prepare_tm > rpupd->prepare_maxtime);
|
||||||
|
|
||||||
|
/* If an update timed out, end the update process and notify
|
||||||
|
* the old version that the update has been canceled. From now on, the old
|
||||||
|
* version will continue executing.
|
||||||
|
*/
|
||||||
|
if(has_update_timed_out) {
|
||||||
|
printf("RS: update failed: maximum prepare time reached\n");
|
||||||
|
end_update(EINTR, RS_CANCEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* start_update_prepare *
|
||||||
|
*===========================================================================*/
|
||||||
|
int start_update_prepare(int allow_retries)
|
||||||
|
{
|
||||||
|
/* Start the preparation phase of the update process. */
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
struct rproc *rp, *new_rp;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!RUPDATE_IS_UPD_SCHEDULED()) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if(!rs_is_idle()) {
|
||||||
|
printf("RS: not idle now, try again\n");
|
||||||
|
if(!allow_retries) {
|
||||||
|
abort_update_proc(EAGAIN);
|
||||||
|
}
|
||||||
|
return EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: starting the preparation phase of the update process\n");
|
||||||
|
|
||||||
|
if(rupdate.rs_rpupd) {
|
||||||
|
assert(rupdate.rs_rpupd == rupdate.last_rpupd);
|
||||||
|
assert(rupdate.rs_rpupd->rp->r_pub->endpoint == RS_PROC_NR);
|
||||||
|
assert(!UPD_IS_PREPARING_ONLY(rupdate.rs_rpupd));
|
||||||
|
}
|
||||||
|
if(rupdate.vm_rpupd) {
|
||||||
|
assert(rupdate.vm_rpupd->rp->r_pub->endpoint == VM_PROC_NR);
|
||||||
|
assert(!UPD_IS_PREPARING_ONLY(rupdate.vm_rpupd));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a multi-component update includes VM, fill information about old
|
||||||
|
* and new endpoints, as well as update flags. VM needs this to complete
|
||||||
|
* the update internally at state transfer time.
|
||||||
|
*/
|
||||||
|
if(RUPDATE_IS_UPD_VM_MULTI()) {
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
rp = rpupd->rp;
|
||||||
|
new_rp = rp->r_new_rp;
|
||||||
|
assert(rp && new_rp);
|
||||||
|
rp->r_pub->old_endpoint = rpupd->state_endpoint;
|
||||||
|
rp->r_pub->new_endpoint = rp->r_pub->endpoint;
|
||||||
|
if(rpupd != rupdate.vm_rpupd && rpupd != rupdate.rs_rpupd) {
|
||||||
|
rp->r_pub->sys_flags |= SF_VM_UPDATE;
|
||||||
|
if(rpupd->lu_flags & SEF_LU_NOMMAP) {
|
||||||
|
rp->r_pub->sys_flags |= SF_VM_NOMMAP;
|
||||||
|
}
|
||||||
|
if(!(rpupd->lu_flags & SEF_LU_UNSAFE)) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s pinning memory\n", srv_to_string(rp));
|
||||||
|
vm_memctl(rp->r_pub->new_endpoint, VM_RS_MEM_PIN, 0, 0);
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s pinning memory\n", srv_to_string(new_rp));
|
||||||
|
vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request the first service to prepare for the update. */
|
||||||
|
if(start_update_prepare_next() == NULL) {
|
||||||
|
/* If we are done already, end the update now. */
|
||||||
|
end_update(OK, RS_REPLY);
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* start_update_prepare_next *
|
||||||
|
*===========================================================================*/
|
||||||
|
struct rprocupd* start_update_prepare_next()
|
||||||
|
{
|
||||||
|
/* Request the next service in the update chain to prepare for the update. */
|
||||||
|
struct rprocupd *rpupd = NULL;
|
||||||
|
if(!RUPDATE_IS_UPDATING()) {
|
||||||
|
rpupd = rupdate.first_rpupd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rpupd = rupdate.curr_rpupd->next_rpupd;
|
||||||
|
}
|
||||||
|
if(!rpupd) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rupdate.flags |= RS_UPDATING;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
rupdate.curr_rpupd = rpupd;
|
||||||
|
request_prepare_update_service(rupdate.curr_rpupd->rp, rupdate.curr_rpupd->prepare_state);
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
/* Continue only if the current service requires a prepare-only update. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!rupdate.curr_rpupd->next_rpupd) {
|
||||||
|
/* Continue only if there are services left. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rpupd = rupdate.curr_rpupd->next_rpupd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpupd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* start_update *
|
||||||
|
*===========================================================================*/
|
||||||
|
int start_update()
|
||||||
|
{
|
||||||
|
/* Start the update phase of the update process. */
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
int r, init_ready_pending=0;
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: starting a %s-component update process\n",
|
||||||
|
RUPDATE_IS_UPD_MULTI() ? "multi" : "single");
|
||||||
|
|
||||||
|
assert(RUPDATE_IS_UPDATING());
|
||||||
|
assert(rupdate.num_rpupds > 0);
|
||||||
|
assert(rupdate.num_init_ready_pending == 0);
|
||||||
|
assert(rupdate.first_rpupd);
|
||||||
|
assert(rupdate.last_rpupd);
|
||||||
|
assert(rupdate.curr_rpupd == rupdate.last_rpupd);
|
||||||
|
rupdate.flags |= RS_INITIALIZING;
|
||||||
|
|
||||||
|
/* Cancel the update for the prepare-only services now. */
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
request_prepare_update_service(rpupd->rp, SEF_LU_STATE_NULL);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Iterate over all the processes scheduled for the update. Update each
|
||||||
|
* service and initialize the new instance. If VM is part of a
|
||||||
|
* multi-component live update, initialize VM first.
|
||||||
|
*/
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
rupdate.curr_rpupd = rpupd;
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
init_ready_pending=1;
|
||||||
|
r = start_srv_update(rpupd);
|
||||||
|
if(r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if(!RUPDATE_IS_UPD_VM_MULTI() || rpupd == rupdate.vm_rpupd) {
|
||||||
|
r = complete_srv_update(rpupd);
|
||||||
|
if(r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* End update if there is nothing more to do. */
|
||||||
|
if (!init_ready_pending) {
|
||||||
|
end_update(OK, 0);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle multi-component live updates including VM. */
|
||||||
|
if(RUPDATE_IS_UPD_VM_MULTI()) {
|
||||||
|
message m;
|
||||||
|
/* Check VM initialization, assume failure after timeout. */
|
||||||
|
if (rs_verbose)
|
||||||
|
printf("RS: waiting for VM to initialize...\n");
|
||||||
|
r = rs_receive_ticks(VM_PROC_NR, &m, NULL, UPD_INIT_MAXTIME(rupdate.vm_rpupd));
|
||||||
|
if(r != OK || m.m_type != RS_INIT || m.m_rs_init.result != OK) {
|
||||||
|
r = (r == OK && m.m_type == RS_INIT ? m.m_rs_init.result : EINTR);
|
||||||
|
m.m_source = VM_PROC_NR;
|
||||||
|
m.m_type = RS_INIT;
|
||||||
|
m.m_rs_init.result = r;
|
||||||
|
}
|
||||||
|
do_init_ready(&m);
|
||||||
|
/* If initialization was successfull, complete the update. */
|
||||||
|
if(r == OK) {
|
||||||
|
/* Reply and unblock VM immediately. */
|
||||||
|
m.m_type = OK;
|
||||||
|
reply(VM_PROC_NR, NULL, &m);
|
||||||
|
/* Initialize other services. */
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd) && rpupd != rupdate.vm_rpupd) {
|
||||||
|
r = complete_srv_update(rpupd);
|
||||||
|
if(r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* start_srv_update *
|
||||||
|
*===========================================================================*/
|
||||||
|
int start_srv_update(struct rprocupd *rpupd)
|
||||||
|
{
|
||||||
|
/* Start updating a single service given its update descriptor. */
|
||||||
|
struct rproc *old_rp, *new_rp;
|
||||||
|
int r, sys_upd_flags = 0;
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s starting the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
|
||||||
|
|
||||||
|
rupdate.num_init_ready_pending++;
|
||||||
|
new_rp->r_flags |= RS_INITIALIZING;
|
||||||
|
new_rp->r_flags |= RS_INIT_PENDING;
|
||||||
|
if(rpupd->lu_flags & SEF_LU_NOMMAP) {
|
||||||
|
sys_upd_flags |= SF_VM_NOMMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the update, skip for RS. */
|
||||||
|
if(old_rp->r_pub->endpoint != RS_PROC_NR) {
|
||||||
|
r = update_service(&old_rp, &new_rp, RS_SWAP, sys_upd_flags);
|
||||||
|
if(r != OK) {
|
||||||
|
end_update(r, RS_REPLY);
|
||||||
|
printf("RS: update failed: error %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* complete_srv_update *
|
||||||
|
*===========================================================================*/
|
||||||
|
int complete_srv_update(struct rprocupd *rpupd)
|
||||||
|
{
|
||||||
|
/* Complete update of a service given its update descriptor. */
|
||||||
|
struct rproc *old_rp, *new_rp;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s completing the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
|
||||||
|
|
||||||
|
new_rp->r_flags &= ~RS_INIT_PENDING;
|
||||||
|
|
||||||
|
/* If RS itself is updating, yield control to the new version immediately. */
|
||||||
|
if(old_rp->r_pub->endpoint == RS_PROC_NR) {
|
||||||
|
r = init_service(new_rp, SEF_INIT_LU, rpupd->init_flags);
|
||||||
|
if(r != OK) {
|
||||||
|
panic("unable to initialize the new RS instance: %d", r);
|
||||||
|
}
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s is the new RS instance we'll yield control to\n", srv_to_string(new_rp));
|
||||||
|
r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
|
||||||
|
if(r != OK) {
|
||||||
|
panic("unable to yield control to the new RS instance: %d", r);
|
||||||
|
}
|
||||||
|
/* If we get this far, the new version failed to initialize. Rollback. */
|
||||||
|
rollback_service(&new_rp, &old_rp);
|
||||||
|
end_update(ERESTART, RS_REPLY);
|
||||||
|
printf("RS: update failed: state transfer failed for the new RS instance\n");
|
||||||
|
return ERESTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the new version run. */
|
||||||
|
r = run_service(new_rp, SEF_INIT_LU, rpupd->init_flags);
|
||||||
|
if(r != OK) {
|
||||||
|
/* Something went wrong. Rollback. */
|
||||||
|
rollback_service(&new_rp, &old_rp);
|
||||||
|
end_update(r, RS_REPLY);
|
||||||
|
printf("RS: update failed: error %d\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* abort_update_proc *
|
||||||
|
*===========================================================================*/
|
||||||
|
int abort_update_proc(int reason)
|
||||||
|
{
|
||||||
|
/* This function is called to abort a scheduled/in-progress update process
|
||||||
|
* indiscriminately. If the update is in progress, simply pretend the
|
||||||
|
* current service is causing premature termination of the update.
|
||||||
|
*/
|
||||||
|
int is_updating = RUPDATE_IS_UPDATING();
|
||||||
|
assert(reason != OK);
|
||||||
|
|
||||||
|
if(!is_updating && !RUPDATE_IS_UPD_SCHEDULED()) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: aborting the %s update process prematurely\n",
|
||||||
|
is_updating ? "in-progress" : "scheduled");
|
||||||
|
|
||||||
|
if(!is_updating) {
|
||||||
|
rupdate_clear_upds();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rupdate.flags & RS_INITIALIZING) {
|
||||||
|
/* Pretend the current service under update failed to initialize. */
|
||||||
|
end_update(reason, RS_REPLY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Pretend the current service under update failed to prepare. */
|
||||||
|
end_update(reason, RS_CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_curr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void end_update_curr(struct rprocupd *rpupd, int result, int reply_flag)
|
||||||
|
{
|
||||||
|
/* Execute the requested action on the current service under update. */
|
||||||
|
struct rproc *old_rp, *new_rp;
|
||||||
|
assert(rpupd == rupdate.curr_rpupd);
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
if(result != OK && SRV_IS_UPDATING_AND_INITIALIZING(new_rp) && rpupd != rupdate.rs_rpupd) {
|
||||||
|
/* Rollback in case of failures at initialization time. */
|
||||||
|
rollback_service(&new_rp, &old_rp);
|
||||||
|
}
|
||||||
|
end_srv_update(rpupd, result, reply_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_before_prepare *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void end_update_before_prepare(struct rprocupd *rpupd, int result)
|
||||||
|
{
|
||||||
|
/* The service is still waiting for the update. Cleanup the new version and
|
||||||
|
* keep the old version running.
|
||||||
|
*/
|
||||||
|
struct rproc *old_rp, *new_rp;
|
||||||
|
assert(result != OK);
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
cleanup_service(new_rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_prepare_done *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void end_update_prepare_done(struct rprocupd *rpupd, int result)
|
||||||
|
{
|
||||||
|
/* The service is blocked after preparing for the update. Unblock it
|
||||||
|
* and cleanup the new version.
|
||||||
|
*/
|
||||||
|
assert(!RUPDATE_IS_INITIALIZING());
|
||||||
|
assert(result != OK);
|
||||||
|
assert(!(rpupd->rp->r_flags & RS_INITIALIZING));
|
||||||
|
|
||||||
|
end_srv_update(rpupd, result, RS_REPLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_initializing *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void end_update_initializing(struct rprocupd *rpupd, int result)
|
||||||
|
{
|
||||||
|
/* The service is initializing after a live udate. Cleanup the version that
|
||||||
|
* has to die out and let the other version run.
|
||||||
|
*/
|
||||||
|
struct rproc *old_rp, *new_rp;
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
assert(SRV_IS_UPDATING_AND_INITIALIZING(new_rp));
|
||||||
|
if(result != OK && rpupd != rupdate.rs_rpupd) {
|
||||||
|
/* Rollback in case of failures at initialization time. */
|
||||||
|
rollback_service(&new_rp, &old_rp);
|
||||||
|
}
|
||||||
|
end_srv_update(rpupd, result, RS_REPLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_rev_iter *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void end_update_rev_iter(int result, int reply_flag,
|
||||||
|
struct rprocupd *skip_rpupd, struct rprocupd *only_rpupd)
|
||||||
|
{
|
||||||
|
/* End the update for all the requested services. */
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
short is_curr, is_before_curr, is_after_curr;
|
||||||
|
|
||||||
|
is_after_curr = 1;
|
||||||
|
RUPDATE_REV_ITER(rupdate.last_rpupd, prev_rpupd, rpupd,
|
||||||
|
is_curr = (rupdate.curr_rpupd == rpupd);
|
||||||
|
is_after_curr = is_after_curr && !is_curr;
|
||||||
|
if(!UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
short is_before_prepare;
|
||||||
|
short is_prepare_done;
|
||||||
|
short is_initializing;
|
||||||
|
is_before_curr = !is_curr && !is_after_curr;
|
||||||
|
if(RUPDATE_IS_INITIALIZING()) {
|
||||||
|
is_before_prepare = 0;
|
||||||
|
is_prepare_done = is_after_curr;
|
||||||
|
is_initializing = is_before_curr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
is_before_prepare = is_after_curr;
|
||||||
|
is_prepare_done = is_before_curr;
|
||||||
|
is_initializing = 0;
|
||||||
|
}
|
||||||
|
if((!skip_rpupd || rpupd != skip_rpupd) && (!only_rpupd || rpupd == only_rpupd)) {
|
||||||
|
/* Analyze different cases. */
|
||||||
|
if(is_curr) {
|
||||||
|
end_update_curr(rpupd, result, reply_flag);
|
||||||
|
}
|
||||||
|
else if(is_before_prepare) {
|
||||||
|
end_update_before_prepare(rpupd, result);
|
||||||
|
}
|
||||||
|
else if(is_prepare_done) {
|
||||||
|
end_update_prepare_done(rpupd, result);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(is_initializing);
|
||||||
|
end_update_initializing(rpupd, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_update_debug *
|
||||||
|
*===========================================================================*/
|
||||||
|
void end_update_debug(char *file, int line,
|
||||||
|
int result, int reply_flag)
|
||||||
|
{
|
||||||
|
/* End an in-progress update process. */
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd, *rpupd_it;
|
||||||
|
struct rproc *rp, *old_rp, *new_rp;
|
||||||
|
int i, r, slot_nr;
|
||||||
|
|
||||||
|
assert(RUPDATE_IS_UPDATING());
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s ending the update: result=%d, reply=%d at %s:%d\n",
|
||||||
|
srv_to_string(rupdate.curr_rpupd->rp), result, (reply_flag==RS_REPLY),
|
||||||
|
file, line);
|
||||||
|
|
||||||
|
/* If the new instance of RS is active and the update failed, ending
|
||||||
|
* the update couldn't be any easier.
|
||||||
|
*/
|
||||||
|
if(result != OK && RUPDATE_IS_RS_INIT_DONE()) {
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: update failed, new RS instance will now exit\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If VM is updated as part of a multi-component live update and something
|
||||||
|
* goes wrong after VM has completed initialization, rollback is only
|
||||||
|
* supported in a best-effort way in unsafe mode. The new VM instance might
|
||||||
|
* have important state changes that won't be reflected in the old version
|
||||||
|
* once we rollback.
|
||||||
|
*/
|
||||||
|
if(result != OK && RUPDATE_IS_UPD_VM_MULTI() && RUPDATE_IS_VM_INIT_DONE() && (rupdate.vm_rpupd->lu_flags & SEF_LU_UNSAFE)) {
|
||||||
|
printf("RS: Warning rollbacking in unsafe multi-component update including VM!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle prepare-only services first: simply cancel the update. */
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
if(!RUPDATE_IS_INITIALIZING()) {
|
||||||
|
request_prepare_update_service(rpupd->rp, SEF_LU_STATE_NULL);
|
||||||
|
}
|
||||||
|
rpupd->rp->r_flags &= ~RS_PREPARE_DONE;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Handle all the other services now, VM always last to support rollback. */
|
||||||
|
end_update_rev_iter(result, reply_flag, rupdate.vm_rpupd, NULL);
|
||||||
|
if(rupdate.vm_rpupd) {
|
||||||
|
end_update_rev_iter(result, reply_flag, NULL, rupdate.vm_rpupd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End the update and complete initialization in case of success. */
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
if(prev_rpupd) {
|
||||||
|
rupdate_upd_clear(prev_rpupd);
|
||||||
|
}
|
||||||
|
if(result == OK && !UPD_IS_PREPARING_ONLY(rpupd)) {
|
||||||
|
/* The rp pointer points to the new instance in this case. */
|
||||||
|
new_rp = rpupd->rp;
|
||||||
|
end_srv_init(new_rp);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
late_reply(rupdate.last_rpupd->rp, result);
|
||||||
|
rupdate_upd_clear(rupdate.last_rpupd);
|
||||||
|
RUPDATE_CLEAR();
|
||||||
|
|
||||||
|
/* Clear all the old/new endpoints and update flags in the public entries. */
|
||||||
|
for(slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
||||||
|
rp = &rproc[slot_nr];
|
||||||
|
rp->r_pub->old_endpoint = NONE;
|
||||||
|
rp->r_pub->new_endpoint = NONE;
|
||||||
|
rp->r_pub->sys_flags &= ~(SF_VM_UPDATE|SF_VM_ROLLBACK|SF_VM_NOMMAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* end_srv_update *
|
||||||
|
*===========================================================================*/
|
||||||
|
void end_srv_update(struct rprocupd *rpupd, int result, int reply_flag)
|
||||||
|
{
|
||||||
|
/* End the update for the given service. There are two possibilities:
|
||||||
|
* 1) the update succeeded. In that case, cleanup the old version and mark the
|
||||||
|
* new version as no longer under update.
|
||||||
|
* 2) the update failed. In that case, cleanup the new version and mark the old
|
||||||
|
* version as no longer under update. Eventual late ready to update
|
||||||
|
* messages (if any) will simply be ignored and the service can
|
||||||
|
* continue executing. In addition, reset the check timestamp, so that if the
|
||||||
|
* service has a period, a status request will be forced in the next period.
|
||||||
|
*/
|
||||||
|
struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
|
||||||
|
struct rproc **rps;
|
||||||
|
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
int nr_rps, i;
|
||||||
|
|
||||||
|
old_rp = rpupd->rp;
|
||||||
|
new_rp = old_rp->r_new_rp;
|
||||||
|
assert(old_rp && new_rp);
|
||||||
|
if(result == OK && new_rp->r_pub->endpoint == VM_PROC_NR && RUPDATE_IS_UPD_MULTI()) {
|
||||||
|
/* VM has already been replied to in case of multi-component live update.
|
||||||
|
* Send an update cancel message to trigger cleanup.
|
||||||
|
*/
|
||||||
|
reply_flag = RS_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: ending update from %s to %s with result=%d, reply=%d\n",
|
||||||
|
srv_to_string(old_rp), srv_to_string(new_rp), result, (reply_flag==RS_REPLY));
|
||||||
|
|
||||||
|
/* Decide which version has to die out and which version has to survive. */
|
||||||
|
surviving_rp = (result == OK ? new_rp : old_rp);
|
||||||
|
exiting_rp = (result == OK ? old_rp : new_rp);
|
||||||
|
surviving_rp->r_flags &= ~RS_INITIALIZING;
|
||||||
|
surviving_rp->r_check_tm = 0;
|
||||||
|
getticks(&surviving_rp->r_alive_tm);
|
||||||
|
|
||||||
|
/* Keep track of the surviving process in the update descriptor from now on. */
|
||||||
|
rpupd->rp = surviving_rp;
|
||||||
|
|
||||||
|
/* Unlink the two versions. */
|
||||||
|
old_rp->r_new_rp = NULL;
|
||||||
|
new_rp->r_old_rp = NULL;
|
||||||
|
|
||||||
|
/* Mark the version that has to survive as no longer updating and
|
||||||
|
* reply when asked to.
|
||||||
|
*/
|
||||||
|
surviving_rp->r_flags &= ~(RS_UPDATING|RS_PREPARE_DONE|RS_INIT_DONE|RS_INIT_PENDING);
|
||||||
|
if(reply_flag == RS_REPLY) {
|
||||||
|
message m;
|
||||||
|
m.m_type = result;
|
||||||
|
reply(surviving_rp->r_pub->endpoint, surviving_rp, &m);
|
||||||
|
}
|
||||||
|
else if(reply_flag == RS_CANCEL) {
|
||||||
|
if(!(surviving_rp->r_flags & RS_TERMINATED)) {
|
||||||
|
request_prepare_update_service(surviving_rp, SEF_LU_STATE_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup or detach the version that has to die out. */
|
||||||
|
get_service_instances(exiting_rp, &rps, &nr_rps);
|
||||||
|
for(i=0;i<nr_rps;i++) {
|
||||||
|
if(rps[i] == old_rp && (rpupd->lu_flags & SEF_LU_DETACHED)) {
|
||||||
|
message m;
|
||||||
|
m.m_type = EDEADEPT;
|
||||||
|
rps[i]->r_flags |= RS_CLEANUP_DETACH;
|
||||||
|
cleanup_service(rps[i]);
|
||||||
|
reply(rps[i]->r_pub->endpoint, rps[i], &m);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cleanup_service(rps[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s ended the %s\n", srv_to_string(surviving_rp),
|
||||||
|
srv_upd_to_string(rpupd));
|
||||||
|
}
|
||||||
|
|
|
@ -10,21 +10,19 @@
|
||||||
#include <minix/sched.h>
|
#include <minix/sched.h>
|
||||||
#include "kernel/proc.h"
|
#include "kernel/proc.h"
|
||||||
|
|
||||||
|
#define PRINT_SEP() printf("---------------------------------------------------------------------------------\n")
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* init_service *
|
* init_service *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int init_service(rp, type)
|
int init_service(struct rproc *rp, int type, int flags)
|
||||||
struct rproc *rp; /* pointer to process slot */
|
|
||||||
int type; /* type of initialization */
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
message m;
|
message m;
|
||||||
struct rprocpub *rpub;
|
|
||||||
endpoint_t old_endpoint;
|
endpoint_t old_endpoint;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
|
||||||
|
|
||||||
rp->r_flags |= RS_INITIALIZING; /* now initializing */
|
rp->r_flags |= RS_INITIALIZING; /* now initializing */
|
||||||
|
getticks(&rp->r_alive_tm);
|
||||||
rp->r_check_tm = rp->r_alive_tm + 1; /* expect reply within period */
|
rp->r_check_tm = rp->r_alive_tm + 1; /* expect reply within period */
|
||||||
|
|
||||||
/* In case of RS initialization, we are done. */
|
/* In case of RS initialization, we are done. */
|
||||||
|
@ -35,19 +33,29 @@ int type; /* type of initialization */
|
||||||
/* Determine the old endpoint if this is a new instance. */
|
/* Determine the old endpoint if this is a new instance. */
|
||||||
old_endpoint = NONE;
|
old_endpoint = NONE;
|
||||||
if(rp->r_old_rp) {
|
if(rp->r_old_rp) {
|
||||||
old_endpoint = rp->r_old_rp->r_pub->endpoint;
|
old_endpoint = rp->r_upd.state_endpoint;
|
||||||
}
|
}
|
||||||
else if(rp->r_prev_rp) {
|
else if(rp->r_prev_rp) {
|
||||||
old_endpoint = rp->r_prev_rp->r_pub->endpoint;
|
old_endpoint = rp->r_prev_rp->r_pub->endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check flags. */
|
||||||
|
if(rp->r_pub->sys_flags & SF_USE_SCRIPT) {
|
||||||
|
flags |= SEF_INIT_SCRIPT_RESTART;
|
||||||
|
}
|
||||||
|
|
||||||
/* Send initialization message. */
|
/* Send initialization message. */
|
||||||
memset(&m, 0, sizeof(message));
|
|
||||||
m.m_type = RS_INIT;
|
m.m_type = RS_INIT;
|
||||||
m.m_rs_init.type = type;
|
m.m_rs_init.type = (short) type;
|
||||||
|
m.m_rs_init.flags = flags;
|
||||||
m.m_rs_init.rproctab_gid = rinit.rproctab_gid;
|
m.m_rs_init.rproctab_gid = rinit.rproctab_gid;
|
||||||
m.m_rs_init.old_endpoint = old_endpoint;
|
m.m_rs_init.old_endpoint = old_endpoint;
|
||||||
r = asynsend(rpub->endpoint, &m);
|
m.m_rs_init.restarts = (short) rp->r_restarts+1;
|
||||||
|
m.m_rs_init.buff_addr = rp->r_map_prealloc_addr;
|
||||||
|
m.m_rs_init.buff_len = rp->r_map_prealloc_len;
|
||||||
|
rp->r_map_prealloc_addr = 0;
|
||||||
|
rp->r_map_prealloc_len = 0;
|
||||||
|
r = rs_asynsend(rp, &m, 0);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -113,15 +121,14 @@ int is_init; /* set when initializing a call mask */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* srv_to_string *
|
* srv_to_string_gen *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
char* srv_to_string(rp)
|
char* srv_to_string_gen(struct rproc *rp, int is_verbose)
|
||||||
struct rproc *rp; /* pointer to process slot */
|
|
||||||
{
|
{
|
||||||
struct rprocpub *rpub;
|
struct rprocpub *rpub;
|
||||||
int slot_nr;
|
int slot_nr;
|
||||||
char *srv_string;
|
char *srv_string;
|
||||||
static char srv_string_pool[3][RS_MAX_LABEL_LEN + (DEBUG ? 256 : 64)];
|
static char srv_string_pool[3][RS_MAX_LABEL_LEN + 256];
|
||||||
static int srv_string_pool_index = 0;
|
static int srv_string_pool_index = 0;
|
||||||
|
|
||||||
rpub = rp->r_pub;
|
rpub = rp->r_pub;
|
||||||
|
@ -130,26 +137,94 @@ struct rproc *rp; /* pointer to process slot */
|
||||||
srv_string_pool_index = (srv_string_pool_index + 1) % 3;
|
srv_string_pool_index = (srv_string_pool_index + 1) % 3;
|
||||||
|
|
||||||
#define srv_str(cmd) ((cmd) == NULL || (cmd)[0] == '\0' ? "_" : (cmd))
|
#define srv_str(cmd) ((cmd) == NULL || (cmd)[0] == '\0' ? "_" : (cmd))
|
||||||
#define srv_ep_str(rp) (itoa((rp)->r_pub->endpoint))
|
|
||||||
#define srv_active_str(rp) ((rp)->r_flags & RS_ACTIVE ? "*" : " ")
|
#define srv_active_str(rp) ((rp)->r_flags & RS_ACTIVE ? "*" : " ")
|
||||||
#define srv_version_str(rp) ((rp)->r_new_rp || (rp)->r_next_rp ? "-" : \
|
#define srv_version_str(rp) ((rp)->r_new_rp || (rp)->r_next_rp ? "-" : \
|
||||||
((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
|
((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
|
||||||
|
|
||||||
#if DEBUG
|
if(is_verbose) {
|
||||||
sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d, cmd %s, script %s, proc %s, major %d, flags 0x%03x, sys_flags 0x%02x)",
|
sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d, cmd %s, script %s, proc %s, major %d, flags 0x%03x, sys_flags 0x%02x)",
|
||||||
rpub->label, srv_active_str(rp), srv_version_str(rp),
|
rpub->label, srv_active_str(rp), srv_version_str(rp),
|
||||||
slot_nr, rpub->endpoint, rp->r_pid, srv_str(rp->r_cmd),
|
slot_nr, rpub->endpoint, rp->r_pid, srv_str(rp->r_cmd),
|
||||||
srv_str(rp->r_script), srv_str(rpub->proc_name), rpub->dev_nr,
|
srv_str(rp->r_script), srv_str(rpub->proc_name), rpub->dev_nr,
|
||||||
rp->r_flags, rpub->sys_flags);
|
rp->r_flags, rpub->sys_flags);
|
||||||
#else
|
}
|
||||||
sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d)",
|
else {
|
||||||
rpub->label, srv_active_str(rp), srv_version_str(rp),
|
sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d)",
|
||||||
slot_nr, rpub->endpoint, rp->r_pid);
|
rpub->label, srv_active_str(rp), srv_version_str(rp),
|
||||||
#endif
|
slot_nr, rpub->endpoint, rp->r_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef srv_str
|
||||||
|
#undef srv_active_str
|
||||||
|
#undef srv_version_str
|
||||||
|
|
||||||
return srv_string;
|
return srv_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* srv_upd_to_string *
|
||||||
|
*===========================================================================*/
|
||||||
|
char* srv_upd_to_string(struct rprocupd *rpupd)
|
||||||
|
{
|
||||||
|
static char srv_upd_string[256];
|
||||||
|
struct rprocpub *rpub, *next_rpub, *prev_rpub;
|
||||||
|
rpub = rpupd->rp ? rpupd->rp->r_pub : NULL;
|
||||||
|
next_rpub = rpupd->next_rpupd && rpupd->next_rpupd->rp ? rpupd->next_rpupd->rp->r_pub : NULL;
|
||||||
|
prev_rpub = rpupd->prev_rpupd && rpupd->prev_rpupd->rp ? rpupd->prev_rpupd->rp->r_pub : NULL;
|
||||||
|
|
||||||
|
#define srv_ep(RPUB) (RPUB ? (RPUB)->endpoint : -1)
|
||||||
|
#define srv_upd_luflag_c(F) (rpupd->lu_flags & F ? '1' : '0')
|
||||||
|
#define srv_upd_iflag_c(F) (rpupd->init_flags & F ? '1' : '0')
|
||||||
|
|
||||||
|
sprintf(srv_upd_string, "update (lu_flags(SAMPUNDRV)=%c%c%c%c%c%c%c%c%c, init_flags=(FCTD)=%c%c%c%c, state %d (%s), tm %lu, maxtime %lu, endpoint %d, state_data_gid %d, prev_ep %d, next_ep %d)",
|
||||||
|
srv_upd_luflag_c(SEF_LU_SELF), srv_upd_luflag_c(SEF_LU_ASR),
|
||||||
|
srv_upd_luflag_c(SEF_LU_MULTI), srv_upd_luflag_c(SEF_LU_PREPARE_ONLY),
|
||||||
|
srv_upd_luflag_c(SEF_LU_UNSAFE), srv_upd_luflag_c(SEF_LU_NOMMAP),
|
||||||
|
srv_upd_luflag_c(SEF_LU_DETACHED), srv_upd_luflag_c(SEF_LU_INCLUDES_RS),
|
||||||
|
srv_upd_luflag_c(SEF_LU_INCLUDES_VM), srv_upd_iflag_c(SEF_INIT_FAIL),
|
||||||
|
srv_upd_iflag_c(SEF_INIT_CRASH), srv_upd_iflag_c(SEF_INIT_TIMEOUT),
|
||||||
|
srv_upd_iflag_c(SEF_INIT_DEFCB), rpupd->prepare_state,
|
||||||
|
rpupd->prepare_state_data.eval_addr ? rpupd->prepare_state_data.eval_addr : "", rpupd->prepare_tm,
|
||||||
|
rpupd->prepare_maxtime, srv_ep(rpub), rpupd->prepare_state_data_gid,
|
||||||
|
srv_ep(prev_rpub), srv_ep(next_rpub));
|
||||||
|
|
||||||
|
return srv_upd_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rs_asynsend *
|
||||||
|
*===========================================================================*/
|
||||||
|
int rs_asynsend(struct rproc *rp, message *m_ptr, int no_reply)
|
||||||
|
{
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
|
||||||
|
if(no_reply) {
|
||||||
|
r = asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = asynsend(rpub->endpoint, m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs_verbose)
|
||||||
|
printf("RS: %s being asynsent to with message type %d, noreply=%d, result=%d\n",
|
||||||
|
srv_to_string(rp), m_ptr->m_type, no_reply, r);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rs_receive_ticks *
|
||||||
|
*===========================================================================*/
|
||||||
|
int rs_receive_ticks(endpoint_t src, message *m_ptr,
|
||||||
|
int *status_ptr, int ticks)
|
||||||
|
{
|
||||||
|
printf("RS: rs_receive_ticks not implemented\n");
|
||||||
|
return ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* reply *
|
* reply *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -166,7 +241,7 @@ message *m_ptr; /* reply message */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rs_verbose && rp)
|
if(rs_verbose && rp)
|
||||||
printf("RS: %s being replied to\n", srv_to_string(rp));
|
printf("RS: %s being replied to with message type %d\n", srv_to_string(rp), m_ptr->m_type);
|
||||||
|
|
||||||
r = ipc_sendnb(who, m_ptr); /* send the message */
|
r = ipc_sendnb(who, m_ptr); /* send the message */
|
||||||
if (r != OK)
|
if (r != OK)
|
||||||
|
@ -265,3 +340,125 @@ int update_sig_mgrs(struct rproc *rp, endpoint_t sig_mgr,
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rs_is_idle *
|
||||||
|
*===========================================================================*/
|
||||||
|
int rs_is_idle()
|
||||||
|
{
|
||||||
|
int slot_nr;
|
||||||
|
struct rproc *rp;
|
||||||
|
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
||||||
|
rp = &rproc[slot_nr];
|
||||||
|
if (!(rp->r_flags & RS_IN_USE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!RS_SRV_IS_IDLE(rp)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* rs_idle_period *
|
||||||
|
*===========================================================================*/
|
||||||
|
void rs_idle_period()
|
||||||
|
{
|
||||||
|
struct rproc *rp;
|
||||||
|
struct rprocpub *rpub;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Not much to do when RS is not idle. */
|
||||||
|
if(!rs_is_idle()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup dead services. */
|
||||||
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
||||||
|
if((rp->r_flags & (RS_IN_USE|RS_DEAD)) == (RS_IN_USE|RS_DEAD)) {
|
||||||
|
cleanup_service(rp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create missing replicas when necessary. */
|
||||||
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
||||||
|
rpub = rp->r_pub;
|
||||||
|
if((rp->r_flags & RS_ACTIVE) && (rpub->sys_flags & SF_USE_REPL) && rp->r_next_rp == NULL) {
|
||||||
|
if(rpub->endpoint == VM_PROC_NR && (rp->r_old_rp || rp->r_new_rp)) {
|
||||||
|
/* Only one replica at the time for VM. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
|
||||||
|
printf("RS: warning: unable to clone %s (error %d)\n",
|
||||||
|
srv_to_string(rp), r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* print_services_status *
|
||||||
|
*===========================================================================*/
|
||||||
|
void print_services_status()
|
||||||
|
{
|
||||||
|
int slot_nr;
|
||||||
|
struct rproc *rp;
|
||||||
|
int num_services = 0;
|
||||||
|
int num_service_instances = 0;
|
||||||
|
int is_verbose = 1;
|
||||||
|
|
||||||
|
PRINT_SEP();
|
||||||
|
printf("Printing information about all the system service instances:\n");
|
||||||
|
PRINT_SEP();
|
||||||
|
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
||||||
|
rp = &rproc[slot_nr];
|
||||||
|
if (!(rp->r_flags & RS_IN_USE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rp->r_flags & RS_ACTIVE) {
|
||||||
|
num_services++;
|
||||||
|
}
|
||||||
|
num_service_instances++;
|
||||||
|
printf("%s\n", srv_to_string_gen(rp, is_verbose));
|
||||||
|
}
|
||||||
|
PRINT_SEP();
|
||||||
|
printf("Found %d service instances, of which %d are active services\n",
|
||||||
|
num_service_instances, num_services);
|
||||||
|
PRINT_SEP();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* print_update_status *
|
||||||
|
*===========================================================================*/
|
||||||
|
void print_update_status()
|
||||||
|
{
|
||||||
|
struct rprocupd *prev_rpupd, *rpupd;
|
||||||
|
int is_updating = RUPDATE_IS_UPDATING();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#define rupdate_flag_c(F) (rupdate.flags & F ? '1' : '0')
|
||||||
|
|
||||||
|
if(!is_updating && !RUPDATE_IS_UPD_SCHEDULED()) {
|
||||||
|
PRINT_SEP();
|
||||||
|
printf("No update is in progress or scheduled\n");
|
||||||
|
PRINT_SEP();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_SEP();
|
||||||
|
i = 1;
|
||||||
|
printf("A %s-component update is %s, flags(UIRV)=%c%c%c%c:\n", RUPDATE_IS_UPD_MULTI() ? "multi" : "single",
|
||||||
|
is_updating ? "in progress" : "scheduled",
|
||||||
|
rupdate_flag_c(RS_UPDATING), rupdate_flag_c(RS_INITIALIZING),
|
||||||
|
rupdate.rs_rpupd ? '1' : '0', rupdate.vm_rpupd ? '1' : '0');
|
||||||
|
PRINT_SEP();
|
||||||
|
RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
|
||||||
|
printf("%d. %s %s %s\n", i++, srv_to_string(rpupd->rp),
|
||||||
|
is_updating ? "updating with" : "scheduled for",
|
||||||
|
srv_upd_to_string(rpupd));
|
||||||
|
);
|
||||||
|
PRINT_SEP();
|
||||||
|
|
||||||
|
#undef rupdate_flag_c
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,20 +276,11 @@ int do_rs_memctl(message *m_ptr)
|
||||||
switch(req)
|
switch(req)
|
||||||
{
|
{
|
||||||
case VM_RS_MEM_PIN:
|
case VM_RS_MEM_PIN:
|
||||||
|
/* Only actually pin RS memory if VM can recover from crashes (saves memory). */
|
||||||
/* Do not perform VM_RS_MEM_PIN yet - it costs the full
|
if (num_vm_instances <= 1)
|
||||||
* size of the RS stack (64MB by default) in memory,
|
return OK;
|
||||||
* and it's needed for functionality that isn't complete /
|
|
||||||
* merged in current Minix (surviving VM crashes).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
r = map_pin_memory(vmp);
|
r = map_pin_memory(vmp);
|
||||||
return r;
|
return r;
|
||||||
#else
|
|
||||||
return OK;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case VM_RS_MEM_MAKE_VM:
|
case VM_RS_MEM_MAKE_VM:
|
||||||
r = rs_memctl_make_vm_instance(vmp);
|
r = rs_memctl_make_vm_instance(vmp);
|
||||||
return r;
|
return r;
|
||||||
|
|
Loading…
Reference in a new issue