Restart policies: Add testing and ProcFS DB

- Expose in procfs the service status and supported recovery policies.
 - This adds a test (testrelpol.sh) to exercise the restart policies of
   the system services and drivers.

NOTE:
  The policy support information is temporarily hardcoded in ProcFS, but
  this has to be replaced by properly retrieving this information from
  RS, which should in turn be setup on a per service basis, at
  initialization time.

Change-Id: I0cb1516a450355b38d0c46b1a8b3d9e841a2c029
This commit is contained in:
Lionel Sambuc 2014-12-08 10:32:14 +00:00
parent ad8bffad67
commit 41ba8c04cc
5 changed files with 328 additions and 21 deletions

View file

@ -6309,6 +6309,7 @@
./usr/tests/minix-posix/testisofs minix-sys ./usr/tests/minix-posix/testisofs minix-sys
./usr/tests/minix-posix/testkyua minix-sys ./usr/tests/minix-posix/testkyua minix-sys
./usr/tests/minix-posix/testmfs minix-sys ./usr/tests/minix-posix/testmfs minix-sys
./usr/tests/minix-posix/testrelpol minix-sys
./usr/tests/minix-posix/testsh1 minix-sys ./usr/tests/minix-posix/testsh1 minix-sys
./usr/tests/minix-posix/testsh2 minix-sys ./usr/tests/minix-posix/testsh2 minix-sys
./usr/tests/minix-posix/testvm minix-sys ./usr/tests/minix-posix/testvm minix-sys

View file

@ -6,39 +6,154 @@
#include "rs/const.h" #include "rs/const.h"
#include "rs/type.h" #include "rs/type.h"
enum policy {
POL_NONE = 0x00, /* user | endpoint */
POL_RESET = 0x01, /* visible | change */
POL_RESTART = 0x02, /* transparent | preserved */
POL_LIVE_UPDATE = 0x04 /* transparent | preserved */
};
struct policies {
#define MAX_POL_FORMAT_SZ 20
char formatted[MAX_POL_FORMAT_SZ];
enum policy supported;
};
static struct rprocpub rprocpub[NR_SYS_PROCS]; static struct rprocpub rprocpub[NR_SYS_PROCS];
static struct rproc rproc[NR_SYS_PROCS]; static struct rproc rproc[NR_SYS_PROCS];
static struct policies policies[NR_SYS_PROCS];
static struct inode *service_node; static struct inode *service_node;
/* /* Updates the policies state from RS. Always returns an ASCIIZ string. */
* Initialize the service directory. static const char *
*/ service_get_policies(struct policies * pol, index_t slot)
void
service_init(void)
{ {
struct inode *root, *node; #if 1 /* The following should be retrieved from RS and formated instead. */
struct inode_stat stat; int pos;
char *ref_label;
static const struct {
const char *label;
const char *policy_str;
} def_pol[] = {
/* audio */
{ .label = "es1370", .policy_str = "reset" },
{ .label = "es1371", .policy_str = "reset" },
{ .label = "sb16", .policy_str = "reset" },
/* bus */
{ .label = "i2c", .policy_str = "restart" },
{ .label = "pci", .policy_str = "restart" },
{ .label = "ti1225", .policy_str = "restart" },
/* clock */
{ .label = "readclock.drv", .policy_str = "restart" },
/* eeprom */
{ .label = "cat24c256", .policy_str = "restart" },
/* examples */
{ .label = "hello", .policy_str = "restart" },
/* hid */
{ .label = "pckbd", .policy_str = "reset" },
/* iommu */
{ .label = "amddev", .policy_str = "" },
/* net */
{ .label = "atl2", .policy_str = "restart" },
{ .label = "dec21140A", .policy_str = "restart" },
{ .label = "dp8390", .policy_str = "restart" },
{ .label = "dpeth", .policy_str = "restart" },
{ .label = "e1000", .policy_str = "restart" },
{ .label = "fxp", .policy_str = "restart" },
{ .label = "lance", .policy_str = "restart" },
{ .label = "lan8710a", .policy_str = "restart" },
{ .label = "orinoco", .policy_str = "restart" },
{ .label = "rtl8139", .policy_str = "restart" },
{ .label = "rtl8169", .policy_str = "restart" },
{ .label = "uds", .policy_str = "reset" },
{ .label = "virtio_net", .policy_str = "restart" },
/* power */
{ .label = "acpi", .policy_str = "" },
{ .label = "tps65217", .policy_str = "" },
{ .label = "tps65590", .policy_str = "" },
/* printer */
{ .label = "printer", .policy_str = "restart" },
/* sensors */
{ .label = "bmp085", .policy_str = "" },
{ .label = "sht21", .policy_str = "restart" },
{ .label = "tsl2550", .policy_str = "restart" },
/* storage */
{ .label = "ahci", .policy_str = "reset" },
{ .label = "at_wini", .policy_str = "reset" },
{ .label = "fbd", .policy_str = "reset" },
{ .label = "filter", .policy_str = "reset" },
{ .label = "floppy", .policy_str = "reset" },
{ .label = "memory", .policy_str = "restart" },
{ .label = "mmc", .policy_str = "reset" },
{ .label = "virtio_blk", .policy_str = "reset" },
{ .label = "vnd", .policy_str = "reset" },
/* system */
{ .label = "gpio", .policy_str = "restart" },
{ .label = "log", .policy_str = "restart" },
{ .label = "random", .policy_str = "restart" },
/* tty */
{ .label = "pty", .policy_str = "restart" },
{ .label = "tty", .policy_str = "" },
/* usb */
{ .label = "usbd", .policy_str = "" },
{ .label = "usb_hub", .policy_str = "" },
{ .label = "usb_storage", .policy_str = "" },
/* video */
{ .label = "fb", .policy_str = "" },
{ .label = "tda19988", .policy_str = "" },
/* vmm_guest */
{ .label = "vbox", .policy_str = "" },
/* fs */
{ .label = "ext2", .policy_str = "" },
{ .label = "hgfs", .policy_str = "" },
{ .label = "isofs", .policy_str = "" },
{ .label = "mfs", .policy_str = "" },
{ .label = "pfs", .policy_str = "" },
{ .label = "procfs", .policy_str = "" },
{ .label = "vbfs", .policy_str = "" },
/* net */
{ .label = "inet", .policy_str = "reset" },
{ .label = "lwip", .policy_str = "" },
/* servers */
{ .label = "devman", .policy_str = "" },
{ .label = "ds", .policy_str = "" },
{ .label = "input", .policy_str = "reset" },
{ .label = "ipc", .policy_str = "restart" },
{ .label = "is", .policy_str = "restart" },
{ .label = "pm", .policy_str = "" },
{ .label = "rs", .policy_str = "" },
{ .label = "sched", .policy_str = "" },
{ .label = "vfs", .policy_str = "" },
{ .label = "vm", .policy_str = "" },
//{ .label = "", .policy_str = "" },
};
root = get_root_inode(); /* Find the related policy, based on the file name of the service. */
ref_label = strrchr(rprocpub[slot].proc_name, '/');
if (NULL == ref_label)
ref_label = rprocpub[slot].proc_name;
memset(&stat, 0, sizeof(stat)); memset(pol[slot].formatted, 0, MAX_POL_FORMAT_SZ);
stat.mode = DIR_ALL_MODE; for(pos = 0; pos < (sizeof(def_pol) / sizeof(def_pol[0])); pos++) {
stat.uid = SUPER_USER; if (0 == strcmp(ref_label, def_pol[pos].label)) {
stat.gid = SUPER_USER; (void)strncpy(pol[slot].formatted, def_pol[pos].policy_str, MAX_POL_FORMAT_SZ);
pol[slot].formatted[MAX_POL_FORMAT_SZ-1] = '\0';
break;
}
}
#else
/* Should do something sensible, based on flags from RS/SEF. */
#endif
service_node = add_inode(root, "service", NO_INDEX, &stat, return pol[slot].formatted;
NR_SYS_PROCS, NULL);
if (service_node == NULL)
panic("unable to create service node");
} }
/* /*
* Update the contents of the service directory, by first updating the RS * Update the contents of the service directory, by first updating the RS
* tables and then updating the directory contents. * tables and then updating the directory contents.
*/ */
void static void
service_update(void) service_update(void)
{ {
struct inode *node; struct inode *node;
@ -86,6 +201,29 @@ service_update(void)
} }
} }
/*
* Initialize the service directory.
*/
void
service_init(void)
{
struct inode *root, *node;
struct inode_stat stat;
root = get_root_inode();
memset(&stat, 0, sizeof(stat));
stat.mode = DIR_ALL_MODE;
stat.uid = SUPER_USER;
stat.gid = SUPER_USER;
service_node = add_inode(root, "service", NO_INDEX, &stat,
NR_SYS_PROCS, NULL);
if (service_node == NULL)
panic("unable to create service node");
}
/* /*
* A lookup request is being performed. If it is in the service directory, * A lookup request is being performed. If it is in the service directory,
* update the tables. We do this lazily, to reduce overhead. * update the tables. We do this lazily, to reduce overhead.
@ -141,5 +279,8 @@ service_read(struct inode * node)
rp = &rproc[slot]; rp = &rproc[slot];
/* TODO: add a large number of other fields! */ /* TODO: add a large number of other fields! */
buf_printf("%d %d\n", rpub->endpoint, rp->r_restarts); buf_printf("filename: %s\n", rpub->proc_name);
buf_printf("endpoint: %d\n", rpub->endpoint);
buf_printf("restarts: %d\n", rp->r_restarts);
buf_printf("policies: %s\n", service_get_policies(policies, slot));
} }

View file

@ -71,7 +71,7 @@ PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t40g t60a t60b \
t67a t67b t68a t68b tvnd t67a t67b t68a t68b tvnd
SCRIPTS+= run check-install testinterp.sh testsh1.sh testsh2.sh testmfs.sh \ SCRIPTS+= run check-install testinterp.sh testsh1.sh testsh2.sh testmfs.sh \
testisofs.sh testvnd.sh testkyua.sh testisofs.sh testvnd.sh testkyua.sh testrelpol.sh
# test57loop.S is not linked into the .bcl file. # test57loop.S is not linked into the .bcl file.
# This way, we can link it in when linking the final binary # This way, we can link it in when linking the final binary

View file

@ -23,7 +23,7 @@ badones= # list of tests that failed
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \ setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
test69 test76 test73 test74 test77 test78" test69 test76 test73 test74 test77 test78"
# Scripts that require to be run as root # Scripts that require to be run as root
rootscripts="testisofs testvnd" rootscripts="testisofs testvnd testrelpol"
alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \ alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \

165
minix/tests/testrelpol.sh Executable file
View file

@ -0,0 +1,165 @@
#!/bin/sh
# Idea:
# Iterate over all the /proc/service entries, and
# for each restatability policy call the policy test function if it is
# supported. No accounting of failed / successful test is done, as a
# failed test can currently provoque cascading effects, so instead we
# fail the test as a whole on the first failurei found.
#
# Supported policies have to be in the POLICIES variable, and define a test
# function.
#
# Known limitations:
# - Currently not all recovery policies are tested
# - Running this test under X11 hangs the X server
#
# To add a new policy, you have to do the following:
# 1. Add the policy into the active policies array by:
# POLICIES="${POLICIES} <policyname>"
#
# 2. define the following shell function:
# pol_<policyname>() {}
# - it will recieve the following parameters:
# + service filename as $1 : the full path to the proc entry
# + label as $2 : the service label
# - which prints 'ok' on success, 'not ok' on failure.
# Currently known policies:
# /* user | endpoint */
# POL_RESET, /* visible | change */
# POL_RESTART, /* transparent | preserved */
# POL_LIVE_UPDATE /* transparent | preserved */
#######################################################################
# Utility functions & global state initializations
#######################################################################
POLICIES=""
MAX_RETRY=7 # so that a single test takes at most 10 seconds
# get_value(key, filename)
get_value() {
if test -f $2
then
grep $1 $2 | cut -d: -f2
else
echo "Error: service $2 down"
fi
}
# wait_for_service(filename)
wait_for_service() {
local retry
retry=0
# Arbitrary timeout, found by counting the number of mice crossing
# the hallway.
sleep 2
while test ${retry} -lt ${MAX_RETRY}
do
sleep 1
retry=$((${retry} + 1))
test -f $1 && break
done
}
#######################################################################
# POLICY: restart
#######################################################################
POLICIES="${POLICIES} restart"
pol_restart() {
local label service
local endpoint_pre endpoint_post
local restarts_pre restarts_post
service=$1
label=$2
restarts_pre=$(get_value restarts ${service})
endpoint_pre=$(get_value endpoint ${service})
service refresh ${label}
wait_for_service ${service}
restarts_post=$(get_value restarts ${service})
endpoint_post=$(get_value endpoint ${service})
if [ ${restarts_post} -gt ${restarts_pre} \
-a ${endpoint_post} -eq ${endpoint_pre} ]
then
echo ok
else
echo not ok
fi
}
#######################################################################
# POLICY: reset
#######################################################################
POLICIES="${POLICIES} reset"
pol_reset() {
local label service
local endpoint_pre endpoint_post
service=$1
label=$2
endpoint_pre=$(get_value endpoint ${service})
service refresh ${label}
wait_for_service ${service}
endpoint_post=$(get_value endpoint ${service})
# This policy doesn't guarantee the endpoint to be kept, but there
# is a slight chance that it will actualy stay the same, and fail
# the test.
if [ ! ${endpoint_post} -eq ${endpoint_pre} ]
then
echo ok
else
echo not ok
fi
}
#######################################################################
# main()
#######################################################################
main() {
local labels service_policies X11
# If there is a running X server, skip the input driver
if ps -ef | grep -v grep | grep -q /usr/X11R7/bin/X
then
echo "This test can't be run while a Xserver is running"
echo "not ok # A Xserver is running"
exit 1
fi
labels=$(echo /proc/service/*)
for label in ${labels}
do
service_policies=$(grep policies ${label}|cut -d: -f2)
for pol in ${service_policies}
do
# Check if the supported policy is under test
if echo "${POLICIES}" | grep -q ${pol}
then
echo "# testing ${label} :: ${pol}"
result=$(pol_${pol} ${label} $(basename ${label}))
#pol_${pol} ${label} $(basename ${label})
#result="FAILED"
if [ "x${result}" != "xok" ]
then
echo "not ok # failed ${label}, ${pol}"
exit 1
fi
fi
done
done
echo ok
exit 0
}
main