From 41ba8c04cc12221cc2b2ad8f8a03b89d5bbe9faf Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Mon, 8 Dec 2014 10:32:14 +0000 Subject: [PATCH] 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 --- distrib/sets/lists/minix/mi | 1 + minix/fs/procfs/service.c | 179 ++++++++++++++++++++++++++++++++---- minix/tests/Makefile | 2 +- minix/tests/run | 2 +- minix/tests/testrelpol.sh | 165 +++++++++++++++++++++++++++++++++ 5 files changed, 328 insertions(+), 21 deletions(-) create mode 100755 minix/tests/testrelpol.sh diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 51917725a..bf2d36920 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -6309,6 +6309,7 @@ ./usr/tests/minix-posix/testisofs minix-sys ./usr/tests/minix-posix/testkyua 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/testsh2 minix-sys ./usr/tests/minix-posix/testvm minix-sys diff --git a/minix/fs/procfs/service.c b/minix/fs/procfs/service.c index 2982b10db..a0d14b087 100644 --- a/minix/fs/procfs/service.c +++ b/minix/fs/procfs/service.c @@ -6,39 +6,154 @@ #include "rs/const.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 rproc rproc[NR_SYS_PROCS]; +static struct policies policies[NR_SYS_PROCS]; static struct inode *service_node; -/* - * Initialize the service directory. - */ -void -service_init(void) +/* Updates the policies state from RS. Always returns an ASCIIZ string. */ +static const char * +service_get_policies(struct policies * pol, index_t slot) { - struct inode *root, *node; - struct inode_stat stat; +#if 1 /* The following should be retrieved from RS and formated instead. */ + 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)); - stat.mode = DIR_ALL_MODE; - stat.uid = SUPER_USER; - stat.gid = SUPER_USER; + memset(pol[slot].formatted, 0, MAX_POL_FORMAT_SZ); + for(pos = 0; pos < (sizeof(def_pol) / sizeof(def_pol[0])); pos++) { + if (0 == strcmp(ref_label, def_pol[pos].label)) { + (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, - NR_SYS_PROCS, NULL); - - if (service_node == NULL) - panic("unable to create service node"); + return pol[slot].formatted; } /* * Update the contents of the service directory, by first updating the RS * tables and then updating the directory contents. */ -void +static void service_update(void) { 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, * update the tables. We do this lazily, to reduce overhead. @@ -141,5 +279,8 @@ service_read(struct inode * node) rp = &rproc[slot]; /* 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)); } diff --git a/minix/tests/Makefile b/minix/tests/Makefile index a0e16b9c6..ae7a9e38a 100644 --- a/minix/tests/Makefile +++ b/minix/tests/Makefile @@ -71,7 +71,7 @@ PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t40g t60a t60b \ t67a t67b t68a t68b tvnd 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. # This way, we can link it in when linking the final binary diff --git a/minix/tests/run b/minix/tests/run index 6d939e179..fd24433c4 100755 --- a/minix/tests/run +++ b/minix/tests/run @@ -23,7 +23,7 @@ badones= # list of tests that failed setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \ test69 test76 test73 test74 test77 test78" # 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 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ diff --git a/minix/tests/testrelpol.sh b/minix/tests/testrelpol.sh new file mode 100755 index 000000000..e9b12fee8 --- /dev/null +++ b/minix/tests/testrelpol.sh @@ -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} " +# +# 2. define the following shell function: +# pol_() {} +# - 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