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

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

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

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

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

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

300 lines
10 KiB
C

#include "syslib.h"
#include <assert.h>
#include <minix/sysutil.h>
/* SEF Live update variables. */
PRIVATE int sef_lu_state = SEF_LU_STATE_NULL;
/* SEF Live update callbacks. */
PRIVATE struct sef_cbs {
sef_cb_lu_prepare_t sef_cb_lu_prepare;
sef_cb_lu_state_isvalid_t sef_cb_lu_state_isvalid;
sef_cb_lu_state_changed_t sef_cb_lu_state_changed;
sef_cb_lu_state_dump_t sef_cb_lu_state_dump;
sef_cb_lu_state_save_t sef_cb_lu_state_save;
} sef_cbs = {
SEF_CB_LU_PREPARE_DEFAULT,
SEF_CB_LU_STATE_ISVALID_DEFAULT,
SEF_CB_LU_STATE_CHANGED_DEFAULT,
SEF_CB_LU_STATE_DUMP_DEFAULT,
SEF_CB_LU_STATE_SAVE_DEFAULT,
};
/* SEF Live update prototypes for sef_receive(). */
PUBLIC _PROTOTYPE( void do_sef_lu_before_receive, (void) );
PUBLIC _PROTOTYPE( int do_sef_lu_request, (message *m_ptr) );
/* SEF Live update helpers. */
PRIVATE _PROTOTYPE( void sef_lu_ready, (int result) );
/* Debug. */
EXTERN _PROTOTYPE( char* sef_debug_header, (void) );
PRIVATE int sef_lu_debug_cycle = 0;
/*===========================================================================*
* do_sef_lu_before_receive *
*===========================================================================*/
PUBLIC void do_sef_lu_before_receive()
{
/* Handle SEF Live update before receive events. */
int r;
/* Nothing to do if we are not preparing for a live update. */
if(sef_lu_state == SEF_LU_STATE_NULL) {
return;
}
/* Debug. */
#if SEF_LU_DEBUG
sef_lu_debug_cycle++;
sef_lu_debug_begin();
sef_lu_dprint("%s, cycle=%d. Dumping state variables:\n",
sef_debug_header(), sef_lu_debug_cycle);
sef_cbs.sef_cb_lu_state_dump(sef_lu_state);
sef_lu_debug_end();
#endif
/* Let the callback code handle the event.
* For SEF_LU_STATE_WORK_FREE, we're always ready, tell immediately.
*/
r = OK;
if(sef_lu_state != SEF_LU_STATE_WORK_FREE) {
r = sef_cbs.sef_cb_lu_prepare(sef_lu_state);
}
if(r == OK) {
sef_lu_ready(OK);
}
}
/*===========================================================================*
* do_sef_lu_request *
*===========================================================================*/
PUBLIC int do_sef_lu_request(message *m_ptr)
{
/* Handle a SEF Live update request. */
int state, old_state, is_valid_state;
sef_lu_debug_cycle = 0;
old_state = sef_lu_state;
state = m_ptr->RS_LU_STATE;
/* Deal with prepare cancel requests first. */
is_valid_state = (state == SEF_LU_STATE_NULL);
/* Otherwise only accept live update requests with a valid state. */
is_valid_state = is_valid_state || sef_cbs.sef_cb_lu_state_isvalid(state);
if(!is_valid_state) {
if(sef_cbs.sef_cb_lu_state_isvalid == SEF_CB_LU_STATE_ISVALID_NULL) {
sef_lu_ready(ENOSYS);
}
else {
sef_lu_ready(EINVAL);
}
}
else {
/* Set the new live update state. */
sef_lu_state = state;
/* If the live update state changed, let the callback code
* handle the rest.
*/
if(old_state != sef_lu_state) {
sef_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
}
}
/* Return OK not to let anybody else intercept the request. */
return(OK);
}
/*===========================================================================*
* sef_lu_ready *
*===========================================================================*/
PRIVATE void sef_lu_ready(int result)
{
message m;
int old_state, rs_result, r;
#if SEF_LU_DEBUG
sef_lu_debug_begin();
sef_lu_dprint("%s, cycle=%d. Ready to update with result: %d%s\n",
sef_debug_header(), sef_lu_debug_cycle,
result, (result == OK ? "(OK)" : ""));
sef_lu_debug_end();
#endif
/* If result is OK, let the callback code save
* any state that must be carried over to the new version.
*/
if(result == OK) {
r = sef_cbs.sef_cb_lu_state_save(sef_lu_state);
if(r != OK) {
/* Abort update if callback returned error. */
result = r;
}
}
/* Inform RS that we're ready with the given result. */
m.m_type = RS_LU_PREPARE;
m.RS_LU_STATE = sef_lu_state;
m.RS_LU_RESULT = result;
r = sendrec(RS_PROC_NR, &m);
if ( r != OK) {
panic("sendrec failed: %d", r);
}
#if SEF_LU_DEBUG
rs_result = m.m_type == RS_LU_PREPARE ? EINTR : m.m_type;
sef_lu_debug_begin();
sef_lu_dprint("%s, cycle=%d. The %s aborted the update with result %d!\n",
sef_debug_header(), sef_lu_debug_cycle,
(result == OK ? "server" : "client"),
(result == OK ? rs_result : result)); /* EINTR if update was canceled. */
sef_lu_debug_end();
#endif
/* Something went wrong. Update was aborted and we didn't get updated.
* Restore things back to normal and continue executing.
*/
old_state = sef_lu_state;
sef_lu_state = SEF_LU_STATE_NULL;
if(old_state != sef_lu_state) {
sef_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
}
}
/*===========================================================================*
* sef_setcb_lu_prepare *
*===========================================================================*/
PUBLIC void sef_setcb_lu_prepare(sef_cb_lu_prepare_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_lu_prepare = cb;
}
/*===========================================================================*
* sef_setcb_lu_state_isvalid *
*===========================================================================*/
PUBLIC void sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_lu_state_isvalid = cb;
}
/*===========================================================================*
* sef_setcb_lu_state_changed *
*===========================================================================*/
PUBLIC void sef_setcb_lu_state_changed(sef_cb_lu_state_changed_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_lu_state_changed = cb;
}
/*===========================================================================*
* sef_setcb_lu_state_dump *
*===========================================================================*/
PUBLIC void sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_lu_state_dump = cb;
}
/*===========================================================================*
* sef_setcb_lu_state_save *
*===========================================================================*/
PUBLIC void sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_lu_state_save = cb;
}
/*===========================================================================*
* sef_cb_lu_prepare_null *
*===========================================================================*/
PUBLIC int sef_cb_lu_prepare_null(int UNUSED(state))
{
return ENOTREADY;
}
/*===========================================================================*
* sef_cb_lu_state_isvalid_null *
*===========================================================================*/
PUBLIC int sef_cb_lu_state_isvalid_null(int UNUSED(state))
{
return FALSE;
}
/*===========================================================================*
* sef_cb_lu_state_changed_null *
*===========================================================================*/
PUBLIC void sef_cb_lu_state_changed_null(int UNUSED(old_state),
int UNUSED(state))
{
}
/*===========================================================================*
* sef_cb_lu_state_dump_null *
*===========================================================================*/
PUBLIC void sef_cb_lu_state_dump_null(int UNUSED(state))
{
sef_lu_dprint("NULL\n");
}
/*===========================================================================*
* sef_cb_lu_state_save_null *
*===========================================================================*/
PUBLIC int sef_cb_lu_state_save_null(int UNUSED(result))
{
return OK;
}
/*===========================================================================*
* sef_cb_lu_prepare_always_ready *
*===========================================================================*/
PUBLIC int sef_cb_lu_prepare_always_ready(int UNUSED(state))
{
return OK;
}
/*===========================================================================*
* sef_cb_lu_prepare_never_ready *
*===========================================================================*/
PUBLIC int sef_cb_lu_prepare_never_ready(int UNUSED(state))
{
#if SEF_LU_DEBUG
sef_lu_debug_begin();
sef_lu_dprint("%s, cycle=%d. Simulating a service never ready to update...\n",
sef_debug_header(), sef_lu_debug_cycle);
sef_lu_debug_end();
#endif
return ENOTREADY;
}
/*===========================================================================*
* sef_cb_lu_prepare_crash *
*===========================================================================*/
PUBLIC int sef_cb_lu_prepare_crash(int UNUSED(state))
{
panic("Simulating a crash at update prepare time...");
return OK;
}
/*===========================================================================*
* sef_cb_lu_state_isvalid_standard *
*===========================================================================*/
PUBLIC int sef_cb_lu_state_isvalid_standard(int state)
{
return SEF_LU_STATE_IS_STANDARD(state);
}
/*===========================================================================*
* sef_cb_lu_state_isvalid_workfree *
*===========================================================================*/
PUBLIC int sef_cb_lu_state_isvalid_workfree(int state)
{
return (state == SEF_LU_STATE_WORK_FREE);
}