minix/drivers/hello/hello.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

212 lines
5 KiB
C

#include <minix/drivers.h>
#include <minix/driver.h>
#include <stdio.h>
#include <stdlib.h>
#include <minix/ds.h>
#include "hello.h"
/*
* Function prototypes for the hello driver.
*/
FORWARD _PROTOTYPE( char * hello_name, (void) );
FORWARD _PROTOTYPE( int hello_open, (struct driver *d, message *m) );
FORWARD _PROTOTYPE( int hello_close, (struct driver *d, message *m) );
FORWARD _PROTOTYPE( struct device * hello_prepare, (int device) );
FORWARD _PROTOTYPE( int hello_transfer, (int procnr, int opcode,
u64_t position, iovec_t *iov,
unsigned nr_req) );
FORWARD _PROTOTYPE( void hello_geometry, (struct partition *entry) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init, (int type, sef_init_info_t *info) );
FORWARD _PROTOTYPE( int sef_cb_lu_state_save, (int) );
FORWARD _PROTOTYPE( int lu_state_restore, (void) );
/* Entry points to the hello driver. */
PRIVATE struct driver hello_tab =
{
hello_name,
hello_open,
hello_close,
nop_ioctl,
hello_prepare,
hello_transfer,
nop_cleanup,
hello_geometry,
nop_alarm,
nop_cancel,
nop_select,
nop_ioctl,
do_nop,
};
/** Represents the /dev/hello device. */
PRIVATE struct device hello_device;
/** State variable to count the number of times the device has been opened. */
PRIVATE int open_counter;
PRIVATE char * hello_name(void)
{
printf("hello_name()\n");
return "hello";
}
PRIVATE int hello_open(d, m)
struct driver *d;
message *m;
{
printf("hello_open(). Called %d time(s).\n", ++open_counter);
return OK;
}
PRIVATE int hello_close(d, m)
struct driver *d;
message *m;
{
printf("hello_close()\n");
return OK;
}
PRIVATE struct device * hello_prepare(dev)
int dev;
{
hello_device.dv_base.lo = 0;
hello_device.dv_base.hi = 0;
hello_device.dv_size.lo = strlen(HELLO_MESSAGE);
hello_device.dv_size.hi = 0;
return &hello_device;
}
PRIVATE int hello_transfer(proc_nr, opcode, position, iov, nr_req)
int proc_nr;
int opcode;
u64_t position;
iovec_t *iov;
unsigned nr_req;
{
int bytes, ret;
printf("hello_transfer()\n");
bytes = strlen(HELLO_MESSAGE) - position.lo < iov->iov_size ?
strlen(HELLO_MESSAGE) - position.lo : iov->iov_size;
if (bytes <= 0)
{
return OK;
}
switch (opcode)
{
case DEV_GATHER_S:
ret = sys_safecopyto(proc_nr, iov->iov_addr, 0,
(vir_bytes) (HELLO_MESSAGE + position.lo),
bytes, D);
iov->iov_size -= bytes;
break;
default:
return EINVAL;
}
return ret;
}
PRIVATE void hello_geometry(entry)
struct partition *entry;
{
printf("hello_geometry()\n");
entry->cylinders = 0;
entry->heads = 0;
entry->sectors = 0;
}
PRIVATE int sef_cb_lu_state_save(int state) {
/* Save the state. */
ds_publish_u32("open_counter", open_counter, DSF_OVERWRITE);
return OK;
}
PRIVATE int lu_state_restore() {
/* Restore the state. */
u32_t value;
ds_retrieve_u32("open_counter", &value);
ds_delete_u32("open_counter");
open_counter = (int) value;
return OK;
}
PRIVATE void sef_local_startup()
{
/*
* Register init callbacks. Use the same function for all event types
*/
sef_setcb_init_fresh(sef_cb_init);
sef_setcb_init_lu(sef_cb_init);
sef_setcb_init_restart(sef_cb_init);
/*
* Register live update callbacks.
*/
/* - Agree to update immediately when LU is requested in a valid state. */
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
/* - Support live update starting from any standard state. */
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
/* - Register a custom routine to save the state. */
sef_setcb_lu_state_save(sef_cb_lu_state_save);
/* Let SEF perform startup. */
sef_startup();
}
PRIVATE int sef_cb_init(int type, sef_init_info_t *info)
{
/* Initialize the hello driver. */
int do_announce_driver = TRUE;
open_counter = 0;
switch(type) {
case SEF_INIT_FRESH:
printf("%s", HELLO_MESSAGE);
break;
case SEF_INIT_LU:
/* Restore the state. */
lu_state_restore();
do_announce_driver = FALSE;
printf("%sHey, I'm a new version!\n", HELLO_MESSAGE);
break;
case SEF_INIT_RESTART:
printf("%sHey, I've just been restarted!\n", HELLO_MESSAGE);
break;
}
/* Announce we are up when necessary. */
if (do_announce_driver) {
driver_announce();
}
/* Initialization completed successfully. */
return OK;
}
PUBLIC int main(int argc, char **argv)
{
/*
* Perform initialization.
*/
sef_local_startup();
/*
* Run the main loop.
*/
driver_task(&hello_tab, DRIVER_STD);
return OK;
}