From 0e78c0166c4c5a4d3ef787d58d41af23958c0edc Mon Sep 17 00:00:00 2001 From: Cristiano Giuffrida Date: Sat, 1 Mar 2014 23:52:17 +0100 Subject: [PATCH] Switch to stateful restart. The following services have been updated to support stateful restarts: - Drivers: tty - Filesystems: isofs, mfs, pfs, libvtreefs-based file servers - System servers: tty, ds, pm, vfs, vm Change-Id: Ie84baa3ba1774047b3ae519808fe4116928edabb --- minix/drivers/tty/tty/tty.c | 1 - minix/fs/isofs/main.c | 1 - minix/fs/mfs/main.c | 1 - minix/fs/pfs/pfs.c | 1 - minix/lib/libsys/sef.c | 5 +- minix/lib/libvtreefs/vtreefs.c | 1 - minix/servers/ds/main.c | 1 - minix/servers/pm/main.c | 1 - minix/servers/vfs/main.c | 1 - minix/servers/vm/main.c | 207 ++++++++++++++++++++++++++++++--- 10 files changed, 192 insertions(+), 28 deletions(-) diff --git a/minix/drivers/tty/tty/tty.c b/minix/drivers/tty/tty/tty.c index 841035acd..edfc3ad74 100644 --- a/minix/drivers/tty/tty/tty.c +++ b/minix/drivers/tty/tty/tty.c @@ -296,7 +296,6 @@ static void sef_local_startup() { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); /* No live update support for now. */ diff --git a/minix/fs/isofs/main.c b/minix/fs/isofs/main.c index 2dd3267b6..f301ac51e 100644 --- a/minix/fs/isofs/main.c +++ b/minix/fs/isofs/main.c @@ -44,7 +44,6 @@ static void sef_local_startup(void) { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); /* No live update support for now. */ diff --git a/minix/fs/mfs/main.c b/minix/fs/mfs/main.c index da34ba9e2..d6cda6ae4 100644 --- a/minix/fs/mfs/main.c +++ b/minix/fs/mfs/main.c @@ -32,7 +32,6 @@ static void sef_local_startup() { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); /* No live update support for now. */ diff --git a/minix/fs/pfs/pfs.c b/minix/fs/pfs/pfs.c index 050edd153..b9d751e33 100644 --- a/minix/fs/pfs/pfs.c +++ b/minix/fs/pfs/pfs.c @@ -408,7 +408,6 @@ pfs_startup(void) /* Register initialization callbacks. */ sef_setcb_init_fresh(pfs_init); - sef_setcb_init_restart(sef_cb_init_fail); /* No live update support for now. */ diff --git a/minix/lib/libsys/sef.c b/minix/lib/libsys/sef.c index 9d385f9ca..b575804d8 100644 --- a/minix/lib/libsys/sef.c +++ b/minix/lib/libsys/sef.c @@ -21,6 +21,7 @@ int sef_self_receiving; /* Extern variables. */ EXTERN int sef_lu_state; EXTERN int __sef_st_before_receive_enabled; +EXTERN __attribute__((weak)) int __vm_init_fresh; /* Debug. */ #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG @@ -109,8 +110,8 @@ void sef_startup() panic("RS unable to complete init: %d", r); } } - else if(sef_self_endpoint == VM_PROC_NR) { - /* VM handles initialization by RS later */ + else if(sef_self_endpoint == VM_PROC_NR && __vm_init_fresh) { + /* VM handles fresh initialization by RS later */ } else { message m; diff --git a/minix/lib/libvtreefs/vtreefs.c b/minix/lib/libvtreefs/vtreefs.c index dc5fbe80a..36064439c 100644 --- a/minix/lib/libvtreefs/vtreefs.c +++ b/minix/lib/libvtreefs/vtreefs.c @@ -53,7 +53,6 @@ sef_local_startup(void) { sef_setcb_init_fresh(init_server); - sef_setcb_init_restart(init_server); sef_setcb_signal_handler(got_signal); diff --git a/minix/servers/ds/main.c b/minix/servers/ds/main.c index 594732897..b61f2c8b6 100644 --- a/minix/servers/ds/main.c +++ b/minix/servers/ds/main.c @@ -94,7 +94,6 @@ static void sef_local_startup() { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); /* Register state transfer callbacks. */ sef_llvm_ds_st_init(); diff --git a/minix/servers/pm/main.c b/minix/servers/pm/main.c index 3e5004baf..82bc1b951 100644 --- a/minix/servers/pm/main.c +++ b/minix/servers/pm/main.c @@ -114,7 +114,6 @@ static void sef_local_startup() { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); /* No live update support for now. */ diff --git a/minix/servers/vfs/main.c b/minix/servers/vfs/main.c index 6b7eb8a68..354565ce3 100644 --- a/minix/servers/vfs/main.c +++ b/minix/servers/vfs/main.c @@ -290,7 +290,6 @@ static void sef_local_startup() { /* Register init callbacks. */ sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); /* No live update support for now. */ diff --git a/minix/servers/vm/main.c b/minix/servers/vm/main.c index 6f314fcc1..29ead3174 100644 --- a/minix/servers/vm/main.c +++ b/minix/servers/vm/main.c @@ -60,13 +60,34 @@ struct { ((c) - VM_RQ_BASE) : -1) static int map_service(struct rprocpub *rpub); -static int do_rs_init(message *m); + +static struct rprocpub rprocpub[NR_SYS_PROCS]; +int __vm_init_fresh; /* SEF functions and variables. */ +static void sef_local_startup(void); +static int sef_cb_init_lu_restart(int type, sef_init_info_t *info); +static int sef_cb_init_fresh(int type, sef_init_info_t *info); static void sef_cb_signal_handler(int signo); void init_vm(void); +int do_sef_init_request(message *); + +/*===========================================================================* + * is_first_time * + *===========================================================================*/ +static int is_first_time(void) +{ + struct proc rs_proc; + int r; + + if ((r = sys_getproc(&rs_proc, RS_PROC_NR)) != OK) + panic("VM: couldn't get RS process data: %d", r); + + return RTS_ISSET(&rs_proc, RTS_BOOTINHIBIT); +} + /*===========================================================================* * main * *===========================================================================*/ @@ -76,15 +97,15 @@ int main(void) int result, who_e, rcv_sts; int caller_slot; - /* Initialize system so that all processes are runnable */ - init_vm(); + /* Initialize system so that all processes are runnable the first time. */ + if (is_first_time()) { + init_vm(); + __vm_init_fresh=1; + } - /* Register init callbacks. */ - sef_setcb_init_restart(sef_cb_init_fail); - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); + /* SEF local startup. */ + sef_local_startup(); + __vm_init_fresh=0; SANITYCHECK(SCL_TOP); @@ -127,7 +148,9 @@ int main(void) /* Calls that use the transid */ result = do_procctl(&msg, transid); } else if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) { - result = do_rs_init(&msg); + result = do_sef_init_request(&msg); + if(result != OK) panic("do_sef_init_request failed!\n"); + result = SUSPEND; /* do not reply to RS */ } else if (msg.m_type == VM_PAGEFAULT) { if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) { printf("VM: process %d faked VM_PAGEFAULT " @@ -171,13 +194,26 @@ int main(void) return(OK); } -static int do_rs_init(message *m) +static void sef_local_startup(void) +{ + /* Register init callbacks. */ + sef_setcb_init_fresh(sef_cb_init_fresh); + sef_setcb_init_lu(sef_cb_init_lu_restart); + sef_setcb_init_restart(sef_cb_init_lu_restart); + + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + + /* Let SEF perform startup. */ + sef_startup(); +} + +static int sef_cb_init_fresh(int type, sef_init_info_t *info) { int s, i; - static struct rprocpub rprocpub[NR_BOOT_PROCS]; /* Map all the services in the boot image. */ - if((s = sys_safecopyfrom(RS_PROC_NR, m->m_rs_init.rproctab_gid, 0, + if((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) { panic("vm: sys_safecopyfrom (rs) failed: %d", s); } @@ -190,11 +226,7 @@ static int do_rs_init(message *m) } } - /* RS expects this response that it then again wants to reply to: */ - m->m_rs_init.result = OK; - ipc_sendrec(RS_PROC_NR, m); - - return(SUSPEND); + return(OK); } static struct vmproc *init_proc(endpoint_t ep_nr) @@ -528,6 +560,145 @@ void init_vm(void) } } +/*===========================================================================* + * sef_cb_init_vm_multi_lu * + *===========================================================================*/ +static int sef_cb_init_vm_multi_lu(int type, sef_init_info_t *info) +{ + message m; + int i, r; + ipc_filter_el_t ipc_filter[IPCF_MAX_ELEMENTS]; + int num_elements; + + if(type != SEF_INIT_LU || !(info->flags & SEF_LU_MULTI)) { + return OK; + } + + /* If this is a multi-component update, we need to perform the update + * for services that need to be updated. In addition, make sure VM + * can only receive messages from RS, tasks, and other services being + * updated until RS specifically sends a special update cancel message. + * This is necessary to limit the number of VM state changes to support + * rollback. Allow only safe message types for safe updates. + */ + memset(ipc_filter, 0, sizeof(ipc_filter)); + num_elements = 0; + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements++].m_source = RS_PROC_NR; + if(info->flags & SEF_LU_UNSAFE) { + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements++].m_source = ANY_TSK; + } + if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, + (vir_bytes) rprocpub, NR_SYS_PROCS*sizeof(struct rprocpub))) != OK) { + panic("sys_safecopyfrom failed: %d", r); + } + m.m_source = VM_PROC_NR; + for(i=0;i < NR_SYS_PROCS;i++) { + if(rprocpub[i].in_use && rprocpub[i].old_endpoint != NONE) { + if(num_elements <= IPCF_MAX_ELEMENTS-3) { + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements].m_source = rprocpub[i].old_endpoint; + if(!(info->flags & SEF_LU_UNSAFE)) { + ipc_filter[num_elements].flags |= IPCF_MATCH_M_TYPE; + ipc_filter[num_elements].m_type = VM_BRK; + } + num_elements++; + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements].m_source = rprocpub[i].new_endpoint; + if(!(info->flags & SEF_LU_UNSAFE)) { + ipc_filter[num_elements].flags |= IPCF_MATCH_M_TYPE; + ipc_filter[num_elements].m_type = VM_BRK; + } + num_elements++; + /* Make sure we can talk to any RS instance. */ + if(rprocpub[i].old_endpoint == RS_PROC_NR) { + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements++].m_source = rprocpub[i].new_endpoint; + } + else if(rprocpub[i].new_endpoint == RS_PROC_NR) { + ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; + ipc_filter[num_elements++].m_source = rprocpub[i].old_endpoint; + } + } + else { + printf("sef_cb_init_vm_multi_lu: skipping ipc filter elements for %d and %d\n", + rprocpub[i].old_endpoint, rprocpub[i].new_endpoint); + } + if(rprocpub[i].sys_flags & SF_VM_UPDATE) { + m.m_lsys_vm_update.src = rprocpub[i].new_endpoint; + m.m_lsys_vm_update.dst = rprocpub[i].old_endpoint; + m.m_lsys_vm_update.flags = rprocpub[i].sys_flags; + r = do_rs_update(&m); + if(r != OK && r != SUSPEND) { + printf("sef_cb_init_vm_multi_lu: do_rs_update failed: %d", r); + } + } + } + } + + r = sys_statectl(SYS_STATE_ADD_IPC_WL_FILTER, ipc_filter, num_elements*sizeof(ipc_filter_el_t)); + if(r != OK) { + printf("sef_cb_init_vm_multi_lu: sys_statectl failed: %d", r); + } + + return OK; +} + +/*===========================================================================* + * sef_cb_init_lu_restart * + *===========================================================================*/ +static int sef_cb_init_lu_restart(int type, sef_init_info_t *info) +{ +/* Restart the vm server. */ + int r; + endpoint_t old_e; + int old_p; + struct vmproc *old_vmp, *new_vmp; + + /* Perform default state transfer first. Assume VM doesn't brk(). */ + if(type == SEF_INIT_LU) { + sef_setcb_init_restart(SEF_CB_INIT_RESTART_DEFAULT); + r = SEF_CB_INIT_LU_DEFAULT(type, info); + } + else { + r = SEF_CB_INIT_RESTART_DEFAULT(type, info); + } + if(r != OK) { + return r; + } + + /* Lookup slots for old process. */ + old_e = info->old_endpoint; + if(vm_isokendpt(old_e, &old_p) != OK) { + printf("sef_cb_init_lu_restart: bad old endpoint %d\n", old_e); + return EINVAL; + } + old_vmp = &vmproc[old_p]; + new_vmp = &vmproc[VM_PROC_NR]; + + /* Swap proc slots and dynamic data. */ + if((r = swap_proc_slot(old_vmp, new_vmp)) != OK) { + printf("sef_cb_init_lu_restart: swap_proc_slot failed\n"); + return r; + } + if((r = swap_proc_dyn_data(old_vmp, new_vmp, 0)) != OK) { + printf("sef_cb_init_lu_restart: swap_proc_dyn_data failed\n"); + return r; + } + + /* Rebind page tables. */ + pt_bind(&new_vmp->vm_pt, new_vmp); + pt_bind(&old_vmp->vm_pt, old_vmp); + pt_clearmapcache(); + + /* Adjust process references. */ + adjust_proc_refs(); + + /* Handle multi-component live update when necessary. */ + return sef_cb_init_vm_multi_lu(type, info); +} + /*===========================================================================* * sef_cb_signal_handler * *===========================================================================*/