[Fault-injection-developer] [RFC] [PATCH] code segment patch
Status: Alpha
Brought to you by:
rustyl
From: Zhuang, L. <lou...@in...> - 2002-12-25 00:32:38
|
Dear all, I ask for your comments again. ;-) following patch is the code segment implementation with a mock code segment sample. you can try it by following steps: 1. 'bk pull http://fault-injection.bkbits.net/linux-2.5' 2. install the kernel and modules (NOTE, you need new modutils by Rusty Russell) 3. modprobe fi_mock_cs 4. modprobe fi_mock_interceptor 5. mount -tsysfs none /sys 6. add a trigger (echo "add test MMIO 1000 c 0 0 0 0 0 0 0 1 4 0" > /sys/fault-injection/triggers/ctl ) 7. attach trigger with code_segment (echo "test" > /sys/fault-injection/code-segments/mock/trigger) 8. trigger the mock interception (echo "1" > /sys/fault-injection/triggers/test/trip) - Louis # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.918 -> 1.922 # drivers/char/fi/pf/pf.c 1.17 -> 1.18 # arch/i386/Kconfig 1.25 -> 1.26 # drivers/char/fi/Makefile 1.6 -> 1.7 # drivers/char/fi/fi_core.c 1.19 -> 1.22 # include/linux/fi.h 1.5 -> 1.6 # drivers/char/fi/fi_mock_interceptor.c 1.2 -> 1.4 # (new) -> 1.2 drivers/char/fi/fi_mock_cs.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/24 lo...@ha... 1.919 # * add code segment subsystem # * add fi_mock_code_segment # * clean some extern declarations in .c # -------------------------------------------- # 02/12/24 lo...@ha... 1.920 # add mock_code_segment file # -------------------------------------------- # 02/12/24 lo...@ha... 1.921 # drivers/char/fi/fi_core.c # * fix a bug # * add code segment support # drivers/char/fi/fi_mock_cs.c # reduce name length # -------------------------------------------- # 02/12/24 lo...@ha... 1.922 # * refactor del_trigger (using find_trigger_by_name) # * refactor fi_execute_trigger (breaking down small functions) # -------------------------------------------- # diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Tue Dec 24 16:57:18 2002 +++ b/arch/i386/Kconfig Tue Dec 24 16:57:18 2002 @@ -1596,6 +1596,17 @@ If in doubt say N. +config FI_MOCK_CODE_SEGMENT + tristate "Fault Injection Mock Code Segment (EXPERIMENTAL)" + depends on FI + help + This is a mock or fake code segment created for the sole purpose of + exercising the fault injection core code. The omly reason a person + would want to build this component is to learn to write code segment + himself/herself. + + If in doubt say N + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff -Nru a/drivers/char/fi/Makefile b/drivers/char/fi/Makefile --- a/drivers/char/fi/Makefile Tue Dec 24 16:57:18 2002 +++ b/drivers/char/fi/Makefile Tue Dec 24 16:57:18 2002 @@ -9,5 +9,5 @@ obj-$(CONFIG_FI) += fi_core.o obj-$(CONFIG_FI_TEST) += fi_test.o obj-$(CONFIG_FI_MOCK_INTERCEPTOR) += fi_mock_interceptor.o - +obj-$(CONFIG_FI_MOCK_CODE_SEGMENT) += fi_mock_cs.o export-objs := fi_core.o diff -Nru a/drivers/char/fi/fi_core.c b/drivers/char/fi/fi_core.c --- a/drivers/char/fi/fi_core.c Tue Dec 24 16:57:18 2002 +++ b/drivers/char/fi/fi_core.c Tue Dec 24 16:57:18 2002 @@ -67,6 +67,21 @@ static struct trigger_attribute trigger_attr_count; static struct trigger_attribute trigger_attr_type; +static inline struct trigger *find_trigger_by_name(const char *name) +{ + struct list_head * entry; + struct trigger * t; + + list_for_each(entry,&trigger_subsys.list) { + t = to_trigger(entry); + if (!strncmp(t->kobj.name, name, KOBJ_NAME_LEN)) { + dbg("comparing %s to %s", t->kobj.name, name); + return t; + } + } + return NULL; +} + static inline void create_trigger_files(struct trigger *t) { sysfs_create_file(&t->kobj, &trigger_attr_wp.attr); @@ -163,24 +178,51 @@ static inline ssize_t del_trigger(struct trigger *t) { - struct list_head * entry; struct trigger * n; - list_for_each(entry,&trigger_subsys.list) { - n = to_trigger(entry); - if (!strncmp(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN)) { - dbg("comparing %s to %s", n->kobj.name, t->kobj.name); - unarm_trigger(n); - remove_trigger_files(n); - kobject_unregister(&n->kobj); - return 0; - } + n = find_trigger_by_name(t->kobj.name); + if (n) { + unarm_trigger(n); + remove_trigger_files(n); + kobject_unregister(&n->kobj); + return 0; } err("trigger %s does not exist", t->kobj.name); return -EINVAL; } +static struct code_segment_attribute code_segment_attr_trigger; + +static inline void create_code_segment_files(struct code_segment *cs) +{ + sysfs_create_file(&cs->kobj, &code_segment_attr_trigger.attr); +} + +static inline void remove_code_segment_files(struct code_segment *cs) +{ + sysfs_remove_file(&cs->kobj, &code_segment_attr_trigger.attr); +} + +static inline void arm_code_segment(struct code_segment *cs, struct trigger *t) +{ + kobject_get(&t->kobj); + kobject_get(&cs->kobj); + cs->tri = t; + t->cs = cs; +} + +static inline void unarm_code_segment(struct code_segment *cs) +{ + struct trigger *t; + + t = cs->tri; + t->cs = NULL; + cs->tri = NULL; + kobject_put(&cs->kobj); + kobject_put(&t->kobj); +} + /* * =========================================================== * <>-- Toplevel Containing Subsystem (fi_subsys) --<> @@ -544,6 +586,125 @@ .parent = &fi_subsys, }; +/* + * =============================================================== + * <>-- Code Segment Containing Subsystem (code_segment_subsys) --<> + * --------------------------------------------------------------- + */ +static ssize_t code_segment_attr_show(struct kobject * kobj, + struct attribute * attr, + char * page, size_t count, + loff_t off) +{ + struct code_segment * cs = container_of(kobj,struct code_segment,kobj); + struct code_segment_attribute * a = + container_of(attr,struct code_segment_attribute,attr); + + dbg("about to call show function for %s", a->attr.name); + return a->show ? a->show(cs,page,count,off) : 0; +} + +static ssize_t code_segment_attr_store(struct kobject * kobj, + struct attribute * attr, + const char * page, + size_t count, + loff_t off) +{ + struct code_segment * cs = container_of(kobj,struct code_segment,kobj); + struct code_segment_attribute * a = + container_of(attr,struct code_segment_attribute,attr); + + dbg("about to call store function for %s", a->attr.name); + return a->store ? a->store(cs,page,count,off) : 0; +}; + +static struct sysfs_ops code_segment_sysfs_ops = { + .show = code_segment_attr_show, + .store = code_segment_attr_store, +}; + +static struct subsystem code_segment_subsys = { + .kobj = { .name = "code_segments" }, + .sysfs_ops = &code_segment_sysfs_ops, + .parent = &fi_subsys, +}; + +static ssize_t code_segment_trigger_show(struct code_segment *cs, + char * page, size_t count, + loff_t off) +{ + if (off) return 0; + if (cs->tri) return snprintf(page,count,"%s\n",cs->tri->kobj.name); + return snprintf(page,count,"%s\n","(not attached yet)"); +} + +static ssize_t code_segment_trigger_store(struct code_segment *cs, + const char * page, size_t count, + loff_t off) +{ + struct trigger *t; + char tri_name[KOBJ_NAME_LEN]; + sscanf(page, "%s", tri_name); + dbg("Try to find %s trigger", tri_name); + t = find_trigger_by_name(tri_name); + if(t) { + arm_code_segment(cs, t); + } else { + unarm_code_segment(cs); + } + return count; +} + +static struct code_segment_attribute code_segment_attr_trigger = { + .attr = { .name = "trigger", .mode = 0644 }, + .show = code_segment_trigger_show, + .store= code_segment_trigger_store +}; + +/* + * =============================================================== + * <>-- Others ;) --<> + * --------------------------------------------------------------- + */ + +static inline int is_in_random(int hertz) +{ + int tmp; + if (hertz==0 || hertz==1) return 1; + get_random_bytes(&tmp, sizeof(tmp)); + return (tmp < 0xFFFFFFFF/hertz); +} + +static inline int is_in_range(int data, int min, int max, int bitmask) +{ + int tmp; + if (min==0 && max==0) return 1; + tmp = data & (~bitmask); + if ( min<=tmp && tmp<max) return 1; + return 0; +} + +static inline int is_ready(struct trigger *t, unsigned int val) +{ + if ( is_in_random(t->hertz) + && is_in_range(val, t->min, t->max, t->bitmask)) { + return 1; + } + return 0; +} + +static inline int is_in_count(int count, int skip, int stop) +{ + if (skip >= count) return 0; + if (stop!=0 && (stop+skip) <count) return 0; + return 1; +} + +static inline int protect_bits(int new, int orig, int bitmask) +{ + return (new&(~bitmask)) | (orig&bitmask); +} + void fi_execute_trigger(struct trigger *t, struct interceptor *i, __u32 val, int len, int type, void *data) { @@ -551,38 +712,25 @@ if (!t) { err("Unable to execute null trigger"); - goto exit; + return; } - get_random_bytes(&tmp, sizeof(tmp)); - if (t->hertz==0) {t->hertz=1;};//divid is not 0! - if (tmp >= 0xFFFFFFFF/t->hertz){ - dbg("rnd=%d, HERZ=%d", tmp, t->hertz); - goto exit; - } - - tmp = val & (~t->bitmask); - if (t->min>tmp || tmp>=t->max){ - dbg("min=%d, max=%d, val=%d", t->min, t->max, val); - if(!(t->min==0 && t->max==0)) - goto exit; - } + if(!is_ready(t,val)) return; /* increase count only when all conditions have passed */ atomic_inc(&t->count); - if (t->skip >= atomic_read(&t->count)){ - dbg("count=%d, skip=%d", atomic_read(&t->count), t->skip); - goto exit; - } - - if ( t->stop!=0 && (t->stop < (atomic_read(&t->count)-t->skip)) ) { - dbg("count=%d, stop=%d", atomic_read(&t->count), t->stop); - goto exit; - } + if(!is_in_count(atomic_read(&t->count), t->skip, t->stop)) return; dbg("count=%d, skip=%d, min=%d, max=%d, val=%d", atomic_read(&t->count), t->skip, t->min, t->max, val); + + if (t->cs) { + t->cs->execute_trigger(t, i, val, len, type, data); + return; + } + + //legacy trigger logic code tmp = val; switch (t->opcode){ case TRIGGER_OPCODE_NOTHING: @@ -620,9 +768,8 @@ } exit_for: - val = (val & (t->protection)) | (tmp & (~t->protection)); + val = protect_bits(tmp, val, t->protection); - exit: i->corrupt(val, data); return; } @@ -648,6 +795,27 @@ kobject_unregister(&i->kobj); } +int fi_register_code_segment(struct code_segment *cs) +{ + if (!is_initialized) + fi_init(); + + dbg("registering code segment %s", cs->kobj.name); + cs->kobj.subsys = &code_segment_subsys; + if (kobject_register(&cs->kobj)) { + err("Unable to register kobject"); + return -EINVAL; + } + create_code_segment_files(cs); + return 0; +} + +void fi_unregister_code_segment(struct code_segment *cs) +{ + remove_code_segment_files(cs); + kobject_unregister(&cs->kobj); +} + static int __init fi_init(void) { down(&fi_sem); @@ -659,6 +827,7 @@ dbg("initializing fault injection core"); subsystem_register(&fi_subsys); subsys_create_file(&fi_subsys,&fi_subsys_attr_debug); + subsystem_register(&code_segment_subsys); subsystem_register(&interceptor_subsys); subsystem_register(&trigger_subsys); subsys_create_file(&trigger_subsys,&trigger_subsys_attr_ctl); @@ -674,6 +843,7 @@ subsys_remove_file(&trigger_subsys,&trigger_subsys_attr_ctl); subsystem_unregister(&trigger_subsys); subsystem_unregister(&interceptor_subsys); + subsystem_register(&code_segment_subsys); subsys_remove_file(&fi_subsys,&fi_subsys_attr_debug); subsystem_unregister(&fi_subsys); } @@ -684,6 +854,8 @@ EXPORT_SYMBOL_GPL(fi_register_interceptor); EXPORT_SYMBOL_GPL(fi_unregister_interceptor); +EXPORT_SYMBOL_GPL(fi_register_code_segment); +EXPORT_SYMBOL_GPL(fi_unregister_code_segment); EXPORT_SYMBOL_GPL(fi_execute_trigger); EXPORT_SYMBOL_GPL(fi_debug); diff -Nru a/drivers/char/fi/fi_mock_cs.c b/drivers/char/fi/fi_mock_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/fi/fi_mock_cs.c Tue Dec 24 16:57:18 2002 @@ -0,0 +1,42 @@ +/* Copyright (C) 2002 Louis Zhuang <lou...@in...> */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/kobject.h> +#include <linux/fi.h> +#include <linux/fi_internal.h> + +#define DRIVER_AUTHOR "Louis Zhuang <lou...@in...>" +#define DRIVER_DESC "Fault Injection Mock Code Segment" + +void mock_execute(struct trigger *t, struct interceptor *i, + __u32 val, int len, int type, void *data) +{ + info("tri=%s, intcpt=%s, val=%i, len=%i, type=%i, data=%p", + t->kobj.name, i->kobj.name, val, len, type, + data); +} + +static struct code_segment mock_code_segment = { + .execute_trigger = mock_execute, + .kobj = {.name="mock"} +}; + +static int __init mock_init(void) +{ + if (fi_register_code_segment(&mock_code_segment)) { + err("Failed to register Mock Code Segment\n"); + return -EINVAL; + } + return 0; +} + +static void __exit mock_exit(void) +{ + fi_unregister_code_segment(&mock_code_segment); +} +module_init(mock_init); +module_exit(mock_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru a/drivers/char/fi/fi_mock_interceptor.c b/drivers/char/fi/fi_mock_interceptor.c --- a/drivers/char/fi/fi_mock_interceptor.c Tue Dec 24 16:57:18 2002 +++ b/drivers/char/fi/fi_mock_interceptor.c Tue Dec 24 16:57:18 2002 @@ -44,10 +44,6 @@ #define trace(format, arg...) \ printk(KERN_INFO "%s(" format ")\n", __FUNCTION__ , ## arg) -extern int fi_register_interceptor(struct interceptor *); -extern int fi_unregister_interceptor(struct interceptor *); -extern void fi_execute_trigger(struct trigger*,struct interceptor*, - __u32,int,int,void*); static struct interceptor mock_interceptor; @@ -120,7 +116,7 @@ mock_interceptor.type = mock_type; kobject_init(&mock_interceptor.kobj); - if (!fi_register_interceptor(&mock_interceptor)) { + if (fi_register_interceptor(&mock_interceptor)) { dbg("Failed to register Mock Interceptor"); /* FIXME!! For some reason kobject_register */ diff -Nru a/drivers/char/fi/pf/pf.c b/drivers/char/fi/pf/pf.c --- a/drivers/char/fi/pf/pf.c Tue Dec 24 16:57:18 2002 +++ b/drivers/char/fi/pf/pf.c Tue Dec 24 16:57:18 2002 @@ -269,8 +269,6 @@ .corrupt = &corrupt }; -extern int fi_register_interceptor(struct interceptor *); -extern int fi_unregister_interceptor(struct interceptor *); static int __init pf_init(void) { return fi_register_interceptor(&pf_interceptor); diff -Nru a/include/linux/fi.h b/include/linux/fi.h --- a/include/linux/fi.h Tue Dec 24 16:57:18 2002 +++ b/include/linux/fi.h Tue Dec 24 16:57:18 2002 @@ -60,6 +60,19 @@ INTERCEPTOR_TYPE_PIO=2, } interceptor_type_t; +struct trigger; +struct interceptor; +struct code_segment { + void (*execute_trigger) (struct trigger *t, + struct interceptor *i, + __u32 val, + int len, + int type, + void *data); + struct trigger *tri; + struct kobject kobj; +}; + struct trigger { struct watchpoint wp; __u32 bitmask; @@ -71,6 +84,7 @@ int hertz; int registered; trigger_opcode_t opcode; + struct code_segment *cs; int operand; atomic_t count; interceptor_type_t type; @@ -88,10 +102,10 @@ struct kobject kobj; }; -struct interceptor_attribute { +struct code_segment_attribute { struct attribute attr; - ssize_t (*show) (struct interceptor *,char *,size_t,loff_t); - ssize_t (*store)(struct interceptor *,const char *,size_t, loff_t); + ssize_t (*show) (struct code_segment *,char *,size_t,loff_t); + ssize_t (*store) (struct code_segment *,const char *,size_t,loff_t); }; struct trigger_attribute { @@ -99,6 +113,20 @@ ssize_t (*show) (struct trigger *,char *,size_t,loff_t); ssize_t (*store)(struct trigger *,const char *,size_t,loff_t); }; + +struct interceptor_attribute { + struct attribute attr; + ssize_t (*show) (struct interceptor *,char *,size_t,loff_t); + ssize_t (*store)(struct interceptor *,const char *,size_t, loff_t); +}; + + +extern int fi_register_interceptor(struct interceptor *); +extern void fi_unregister_interceptor(struct interceptor *i); +extern int fi_register_code_segment(struct code_segment *); +extern void fi_unregister_code_segment(struct code_segment *); +extern void fi_execute_trigger(struct trigger *t, struct interceptor *i, + __u32 val, int len, int type, void *data); #endif /* __KERNEL__ */ #endif /* _FAULT_INJECTION_H */ |