mirror of https://github.com/torvalds/linux.git
Runtime verifier updates for v6.19:
- Adapt the ftracetest script to be run from a different folder This uses the already existing OPT_TEST_DIR but extends it further to run independent tests, then add an --rv flag to allow using the script for testing RV (mostly) independently on ftrace. - Add basic RV selftests in selftests/verification for more validations Add more validations for available/enabled monitors and reactors. This could have caught the bug introducing kernel panic solved above. Tests use ftracetest. - Convert react() function in reactor to use va_list directly Use a central helper to handle the variadic arguments. Clean up macros and mark functions as static. - Add lockdep annotations to reactors to have lockdep complain of errors If the reactors are called from improper context. Useful to develop new reactors. This highlights a warning in the panic reactor that is related to the printk subsystem and not to RV. - Convert core RV code to use lock guards and __free helpers This completely removes goto statements. - Fix compilation if !CONFIG_RV_REACTORS Fix the warning by keeping LTL monitor variable as always static. -----BEGIN PGP SIGNATURE----- iIoEABYKADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCaTBoVxQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qtWpAQDxPQAJQvBZ41l9q9Cis7PqGGezT4Nv g6Fh/ydMOlJCsQD/R0Xd5JxPmBI8FLCwCfqHo7wYKUhP8GfL/ORPEWhU2gI= =EEot -----END PGP SIGNATURE----- Merge tag 'trace-rv-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull runtime verifier updates from Steven Rostedt: - Adapt the ftracetest script to be run from a different folder This uses the already existing OPT_TEST_DIR but extends it further to run independent tests, then add an --rv flag to allow using the script for testing RV (mostly) independently on ftrace. - Add basic RV selftests in selftests/verification for more validations Add more validations for available/enabled monitors and reactors. This could have caught the bug introducing kernel panic solved above. Tests use ftracetest. - Convert react() function in reactor to use va_list directly Use a central helper to handle the variadic arguments. Clean up macros and mark functions as static. - Add lockdep annotations to reactors to have lockdep complain of errors If the reactors are called from improper context. Useful to develop new reactors. This highlights a warning in the panic reactor that is related to the printk subsystem and not to RV. - Convert core RV code to use lock guards and __free helpers This completely removes goto statements. - Fix compilation if !CONFIG_RV_REACTORS Fix the warning by keeping LTL monitor variable as always static. * tag 'trace-rv-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rv: Fix compilation if !CONFIG_RV_REACTORS rv: Convert to use __free rv: Convert to use lock guard rv: Add explicit lockdep context for reactors rv: Make rv_reacting_on() static rv: Pass va_list to reactors selftests/verification: Add initial RV tests selftest/ftrace: Generalise ftracetest to use with RV
This commit is contained in:
commit
0b1b4a3d8e
|
|
@ -22700,6 +22700,7 @@ F: Documentation/trace/rv/
|
||||||
F: include/linux/rv.h
|
F: include/linux/rv.h
|
||||||
F: include/rv/
|
F: include/rv/
|
||||||
F: kernel/trace/rv/
|
F: kernel/trace/rv/
|
||||||
|
F: tools/testing/selftests/verification/
|
||||||
F: tools/verification/
|
F: tools/verification/
|
||||||
|
|
||||||
RUST
|
RUST
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ union rv_task_monitor {
|
||||||
struct rv_reactor {
|
struct rv_reactor {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *description;
|
const char *description;
|
||||||
__printf(1, 2) void (*react)(const char *msg, ...);
|
__printf(1, 0) void (*react)(const char *msg, va_list args);
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -102,7 +102,7 @@ struct rv_monitor {
|
||||||
void (*reset)(void);
|
void (*reset)(void);
|
||||||
#ifdef CONFIG_RV_REACTORS
|
#ifdef CONFIG_RV_REACTORS
|
||||||
struct rv_reactor *reactor;
|
struct rv_reactor *reactor;
|
||||||
__printf(1, 2) void (*react)(const char *msg, ...);
|
__printf(1, 0) void (*react)(const char *msg, va_list args);
|
||||||
#endif
|
#endif
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct rv_monitor *parent;
|
struct rv_monitor *parent;
|
||||||
|
|
@ -116,13 +116,14 @@ int rv_get_task_monitor_slot(void);
|
||||||
void rv_put_task_monitor_slot(int slot);
|
void rv_put_task_monitor_slot(int slot);
|
||||||
|
|
||||||
#ifdef CONFIG_RV_REACTORS
|
#ifdef CONFIG_RV_REACTORS
|
||||||
bool rv_reacting_on(void);
|
|
||||||
int rv_unregister_reactor(struct rv_reactor *reactor);
|
int rv_unregister_reactor(struct rv_reactor *reactor);
|
||||||
int rv_register_reactor(struct rv_reactor *reactor);
|
int rv_register_reactor(struct rv_reactor *reactor);
|
||||||
|
__printf(2, 3)
|
||||||
|
void rv_react(struct rv_monitor *monitor, const char *msg, ...);
|
||||||
#else
|
#else
|
||||||
static inline bool rv_reacting_on(void)
|
__printf(2, 3)
|
||||||
|
static inline void rv_react(struct rv_monitor *monitor, const char *msg, ...)
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_RV_REACTORS */
|
#endif /* CONFIG_RV_REACTORS */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,34 +16,19 @@
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
#ifdef CONFIG_RV_REACTORS
|
|
||||||
|
|
||||||
#define DECLARE_RV_REACTING_HELPERS(name, type) \
|
|
||||||
static void cond_react_##name(type curr_state, type event) \
|
|
||||||
{ \
|
|
||||||
if (!rv_reacting_on() || !rv_##name.react) \
|
|
||||||
return; \
|
|
||||||
rv_##name.react("rv: monitor %s does not allow event %s on state %s\n", \
|
|
||||||
#name, \
|
|
||||||
model_get_event_name_##name(event), \
|
|
||||||
model_get_state_name_##name(curr_state)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_RV_REACTOR */
|
|
||||||
|
|
||||||
#define DECLARE_RV_REACTING_HELPERS(name, type) \
|
|
||||||
static void cond_react_##name(type curr_state, type event) \
|
|
||||||
{ \
|
|
||||||
return; \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic helpers for all types of deterministic automata monitors.
|
* Generic helpers for all types of deterministic automata monitors.
|
||||||
*/
|
*/
|
||||||
#define DECLARE_DA_MON_GENERIC_HELPERS(name, type) \
|
#define DECLARE_DA_MON_GENERIC_HELPERS(name, type) \
|
||||||
\
|
\
|
||||||
DECLARE_RV_REACTING_HELPERS(name, type) \
|
static void react_##name(type curr_state, type event) \
|
||||||
|
{ \
|
||||||
|
rv_react(&rv_##name, \
|
||||||
|
"rv: monitor %s does not allow event %s on state %s\n", \
|
||||||
|
#name, \
|
||||||
|
model_get_event_name_##name(event), \
|
||||||
|
model_get_state_name_##name(curr_state)); \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
/* \
|
/* \
|
||||||
* da_monitor_reset_##name - reset a monitor and setting it to init state \
|
* da_monitor_reset_##name - reset a monitor and setting it to init state \
|
||||||
|
|
@ -126,7 +111,7 @@ da_event_##name(struct da_monitor *da_mon, enum events_##name event) \
|
||||||
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) { \
|
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) { \
|
||||||
next_state = model_get_next_state_##name(curr_state, event); \
|
next_state = model_get_next_state_##name(curr_state, event); \
|
||||||
if (next_state == INVALID_STATE) { \
|
if (next_state == INVALID_STATE) { \
|
||||||
cond_react_##name(curr_state, event); \
|
react_##name(curr_state, event); \
|
||||||
trace_error_##name(model_get_state_name_##name(curr_state), \
|
trace_error_##name(model_get_state_name_##name(curr_state), \
|
||||||
model_get_event_name_##name(event)); \
|
model_get_event_name_##name(event)); \
|
||||||
return false; \
|
return false; \
|
||||||
|
|
@ -165,7 +150,7 @@ static inline bool da_event_##name(struct da_monitor *da_mon, struct task_struct
|
||||||
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) { \
|
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) { \
|
||||||
next_state = model_get_next_state_##name(curr_state, event); \
|
next_state = model_get_next_state_##name(curr_state, event); \
|
||||||
if (next_state == INVALID_STATE) { \
|
if (next_state == INVALID_STATE) { \
|
||||||
cond_react_##name(curr_state, event); \
|
react_##name(curr_state, event); \
|
||||||
trace_error_##name(tsk->pid, \
|
trace_error_##name(tsk->pid, \
|
||||||
model_get_state_name_##name(curr_state), \
|
model_get_state_name_##name(curr_state), \
|
||||||
model_get_event_name_##name(event)); \
|
model_get_event_name_##name(event)); \
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,9 @@
|
||||||
#error "Please include $(MODEL_NAME).h generated by rvgen"
|
#error "Please include $(MODEL_NAME).h generated by rvgen"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_RV_REACTORS
|
|
||||||
#define RV_MONITOR_NAME CONCATENATE(rv_, MONITOR_NAME)
|
#define RV_MONITOR_NAME CONCATENATE(rv_, MONITOR_NAME)
|
||||||
static struct rv_monitor RV_MONITOR_NAME;
|
static struct rv_monitor RV_MONITOR_NAME;
|
||||||
|
|
||||||
static void rv_cond_react(struct task_struct *task)
|
|
||||||
{
|
|
||||||
if (!rv_reacting_on() || !RV_MONITOR_NAME.react)
|
|
||||||
return;
|
|
||||||
RV_MONITOR_NAME.react("rv: "__stringify(MONITOR_NAME)": %s[%d]: violation detected\n",
|
|
||||||
task->comm, task->pid);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void rv_cond_react(struct task_struct *task)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ltl_monitor_slot = RV_PER_TASK_MONITOR_INIT;
|
static int ltl_monitor_slot = RV_PER_TASK_MONITOR_INIT;
|
||||||
|
|
||||||
static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon);
|
static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon);
|
||||||
|
|
@ -98,7 +84,8 @@ static void ltl_monitor_destroy(void)
|
||||||
static void ltl_illegal_state(struct task_struct *task, struct ltl_monitor *mon)
|
static void ltl_illegal_state(struct task_struct *task, struct ltl_monitor *mon)
|
||||||
{
|
{
|
||||||
CONCATENATE(trace_error_, MONITOR_NAME)(task);
|
CONCATENATE(trace_error_, MONITOR_NAME)(task);
|
||||||
rv_cond_react(task);
|
rv_react(&RV_MONITOR_NAME, "rv: "__stringify(MONITOR_NAME)": %s[%d]: violation detected\n",
|
||||||
|
task->comm, task->pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ltl_attempt_start(struct task_struct *task, struct ltl_monitor *mon)
|
static void ltl_attempt_start(struct task_struct *task, struct ltl_monitor *mon)
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,9 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/rv.h>
|
#include <linux/rv.h>
|
||||||
|
|
||||||
__printf(1, 2) static void rv_panic_reaction(const char *msg, ...)
|
__printf(1, 0) static void rv_panic_reaction(const char *msg, va_list args)
|
||||||
{
|
{
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, msg);
|
|
||||||
vpanic(msg, args);
|
vpanic(msg, args);
|
||||||
va_end(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rv_reactor rv_panic = {
|
static struct rv_reactor rv_panic = {
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,9 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/rv.h>
|
#include <linux/rv.h>
|
||||||
|
|
||||||
__printf(1, 2) static void rv_printk_reaction(const char *msg, ...)
|
__printf(1, 0) static void rv_printk_reaction(const char *msg, va_list args)
|
||||||
{
|
{
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, msg);
|
|
||||||
vprintk_deferred(msg, args);
|
vprintk_deferred(msg, args);
|
||||||
va_end(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rv_reactor rv_printk = {
|
static struct rv_reactor rv_printk = {
|
||||||
|
|
|
||||||
|
|
@ -375,15 +375,13 @@ static ssize_t monitor_enable_write_data(struct file *filp, const char __user *u
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
retval = rv_enable_monitor(mon);
|
retval = rv_enable_monitor(mon);
|
||||||
else
|
else
|
||||||
retval = rv_disable_monitor(mon);
|
retval = rv_disable_monitor(mon);
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
|
|
||||||
return retval ? : count;
|
return retval ? : count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,35 +420,27 @@ static const struct file_operations interface_desc_fops = {
|
||||||
static int create_monitor_dir(struct rv_monitor *mon, struct rv_monitor *parent)
|
static int create_monitor_dir(struct rv_monitor *mon, struct rv_monitor *parent)
|
||||||
{
|
{
|
||||||
struct dentry *root = parent ? parent->root_d : get_monitors_root();
|
struct dentry *root = parent ? parent->root_d : get_monitors_root();
|
||||||
const char *name = mon->name;
|
struct dentry *dir __free(rv_remove) = rv_create_dir(mon->name, root);
|
||||||
struct dentry *tmp;
|
struct dentry *tmp;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
mon->root_d = rv_create_dir(name, root);
|
if (!dir)
|
||||||
if (!mon->root_d)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
tmp = rv_create_file("enable", RV_MODE_WRITE, mon->root_d, mon, &interface_enable_fops);
|
tmp = rv_create_file("enable", RV_MODE_WRITE, dir, mon, &interface_enable_fops);
|
||||||
if (!tmp) {
|
if (!tmp)
|
||||||
retval = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_remove_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = rv_create_file("desc", RV_MODE_READ, mon->root_d, mon, &interface_desc_fops);
|
tmp = rv_create_file("desc", RV_MODE_READ, dir, mon, &interface_desc_fops);
|
||||||
if (!tmp) {
|
if (!tmp)
|
||||||
retval = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_remove_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = reactor_populate_monitor(mon);
|
retval = reactor_populate_monitor(mon, dir);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_remove_root;
|
return retval;
|
||||||
|
|
||||||
|
mon->root_d = no_free_ptr(dir);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_remove_root:
|
|
||||||
rv_remove(mon->root_d);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -568,7 +558,7 @@ static void disable_all_monitors(void)
|
||||||
struct rv_monitor *mon;
|
struct rv_monitor *mon;
|
||||||
int enabled = 0;
|
int enabled = 0;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
list_for_each_entry(mon, &rv_monitors_list, list)
|
list_for_each_entry(mon, &rv_monitors_list, list)
|
||||||
enabled += __rv_disable_monitor(mon, false);
|
enabled += __rv_disable_monitor(mon, false);
|
||||||
|
|
@ -581,8 +571,6 @@ static void disable_all_monitors(void)
|
||||||
*/
|
*/
|
||||||
tracepoint_synchronize_unregister();
|
tracepoint_synchronize_unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int enabled_monitors_open(struct inode *inode, struct file *file)
|
static int enabled_monitors_open(struct inode *inode, struct file *file)
|
||||||
|
|
@ -623,7 +611,7 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
|
||||||
if (!len)
|
if (!len)
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
|
|
||||||
|
|
@ -644,13 +632,11 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
|
||||||
else
|
else
|
||||||
retval = rv_disable_monitor(mon);
|
retval = rv_disable_monitor(mon);
|
||||||
|
|
||||||
if (!retval)
|
if (retval)
|
||||||
retval = count;
|
return retval;
|
||||||
|
return count;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -737,7 +723,7 @@ static ssize_t monitoring_on_write_data(struct file *filp, const char __user *us
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
turn_monitoring_on_with_reset();
|
turn_monitoring_on_with_reset();
|
||||||
|
|
@ -750,8 +736,6 @@ static ssize_t monitoring_on_write_data(struct file *filp, const char __user *us
|
||||||
*/
|
*/
|
||||||
tracepoint_synchronize_unregister();
|
tracepoint_synchronize_unregister();
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -784,28 +768,26 @@ int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
list_for_each_entry(r, &rv_monitors_list, list) {
|
list_for_each_entry(r, &rv_monitors_list, list) {
|
||||||
if (strcmp(monitor->name, r->name) == 0) {
|
if (strcmp(monitor->name, r->name) == 0) {
|
||||||
pr_info("Monitor %s is already registered\n", monitor->name);
|
pr_info("Monitor %s is already registered\n", monitor->name);
|
||||||
retval = -EEXIST;
|
return -EEXIST;
|
||||||
goto out_unlock;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent && rv_is_nested_monitor(parent)) {
|
if (parent && rv_is_nested_monitor(parent)) {
|
||||||
pr_info("Parent monitor %s is already nested, cannot nest further\n",
|
pr_info("Parent monitor %s is already nested, cannot nest further\n",
|
||||||
parent->name);
|
parent->name);
|
||||||
retval = -EINVAL;
|
return -EINVAL;
|
||||||
goto out_unlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor->parent = parent;
|
monitor->parent = parent;
|
||||||
|
|
||||||
retval = create_monitor_dir(monitor, parent);
|
retval = create_monitor_dir(monitor, parent);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_unlock;
|
return retval;
|
||||||
|
|
||||||
/* keep children close to the parent for easier visualisation */
|
/* keep children close to the parent for easier visualisation */
|
||||||
if (parent)
|
if (parent)
|
||||||
|
|
@ -813,9 +795,7 @@ int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)
|
||||||
else
|
else
|
||||||
list_add_tail(&monitor->list, &rv_monitors_list);
|
list_add_tail(&monitor->list, &rv_monitors_list);
|
||||||
|
|
||||||
out_unlock:
|
return 0;
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -826,13 +806,12 @@ int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)
|
||||||
*/
|
*/
|
||||||
int rv_unregister_monitor(struct rv_monitor *monitor)
|
int rv_unregister_monitor(struct rv_monitor *monitor)
|
||||||
{
|
{
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
rv_disable_monitor(monitor);
|
rv_disable_monitor(monitor);
|
||||||
list_del(&monitor->list);
|
list_del(&monitor->list);
|
||||||
destroy_monitor_dir(monitor);
|
destroy_monitor_dir(monitor);
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,39 +819,36 @@ int __init rv_init_interface(void)
|
||||||
{
|
{
|
||||||
struct dentry *tmp;
|
struct dentry *tmp;
|
||||||
int retval;
|
int retval;
|
||||||
|
struct dentry *root_dir __free(rv_remove) = rv_create_dir("rv", NULL);
|
||||||
|
|
||||||
rv_root.root_dir = rv_create_dir("rv", NULL);
|
if (!root_dir)
|
||||||
if (!rv_root.root_dir)
|
return 1;
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
rv_root.monitors_dir = rv_create_dir("monitors", rv_root.root_dir);
|
rv_root.monitors_dir = rv_create_dir("monitors", root_dir);
|
||||||
if (!rv_root.monitors_dir)
|
if (!rv_root.monitors_dir)
|
||||||
goto out_err;
|
return 1;
|
||||||
|
|
||||||
tmp = rv_create_file("available_monitors", RV_MODE_READ, rv_root.root_dir, NULL,
|
tmp = rv_create_file("available_monitors", RV_MODE_READ, root_dir, NULL,
|
||||||
&available_monitors_ops);
|
&available_monitors_ops);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
goto out_err;
|
return 1;
|
||||||
|
|
||||||
tmp = rv_create_file("enabled_monitors", RV_MODE_WRITE, rv_root.root_dir, NULL,
|
tmp = rv_create_file("enabled_monitors", RV_MODE_WRITE, root_dir, NULL,
|
||||||
&enabled_monitors_ops);
|
&enabled_monitors_ops);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
goto out_err;
|
return 1;
|
||||||
|
|
||||||
tmp = rv_create_file("monitoring_on", RV_MODE_WRITE, rv_root.root_dir, NULL,
|
tmp = rv_create_file("monitoring_on", RV_MODE_WRITE, root_dir, NULL,
|
||||||
&monitoring_on_fops);
|
&monitoring_on_fops);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
goto out_err;
|
return 1;
|
||||||
retval = init_rv_reactors(rv_root.root_dir);
|
retval = init_rv_reactors(root_dir);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_err;
|
return 1;
|
||||||
|
|
||||||
turn_monitoring_on();
|
turn_monitoring_on();
|
||||||
|
|
||||||
return 0;
|
rv_root.root_dir = no_free_ptr(root_dir);
|
||||||
|
|
||||||
out_err:
|
return 0;
|
||||||
rv_remove(rv_root.root_dir);
|
|
||||||
printk(KERN_ERR "RV: Error while creating the RV interface\n");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ struct rv_interface {
|
||||||
#define rv_create_file tracefs_create_file
|
#define rv_create_file tracefs_create_file
|
||||||
#define rv_remove tracefs_remove
|
#define rv_remove tracefs_remove
|
||||||
|
|
||||||
|
DEFINE_FREE(rv_remove, struct dentry *, if (_T) rv_remove(_T));
|
||||||
|
|
||||||
#define MAX_RV_MONITOR_NAME_SIZE 32
|
#define MAX_RV_MONITOR_NAME_SIZE 32
|
||||||
#define MAX_RV_REACTOR_NAME_SIZE 32
|
#define MAX_RV_REACTOR_NAME_SIZE 32
|
||||||
|
|
||||||
|
|
@ -30,10 +32,10 @@ bool rv_is_container_monitor(struct rv_monitor *mon);
|
||||||
bool rv_is_nested_monitor(struct rv_monitor *mon);
|
bool rv_is_nested_monitor(struct rv_monitor *mon);
|
||||||
|
|
||||||
#ifdef CONFIG_RV_REACTORS
|
#ifdef CONFIG_RV_REACTORS
|
||||||
int reactor_populate_monitor(struct rv_monitor *mon);
|
int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root);
|
||||||
int init_rv_reactors(struct dentry *root_dir);
|
int init_rv_reactors(struct dentry *root_dir);
|
||||||
#else
|
#else
|
||||||
static inline int reactor_populate_monitor(struct rv_monitor *mon)
|
static inline int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
* printk
|
* printk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/lockdep.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "rv.h"
|
#include "rv.h"
|
||||||
|
|
@ -232,9 +233,7 @@ monitor_reactors_write(struct file *file, const char __user *user_buf,
|
||||||
seq_f = file->private_data;
|
seq_f = file->private_data;
|
||||||
mon = seq_f->private;
|
mon = seq_f->private;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
retval = -EINVAL;
|
|
||||||
|
|
||||||
list_for_each_entry(reactor, &rv_reactors_list, list) {
|
list_for_each_entry(reactor, &rv_reactors_list, list) {
|
||||||
if (strcmp(ptr, reactor->name) != 0)
|
if (strcmp(ptr, reactor->name) != 0)
|
||||||
|
|
@ -242,13 +241,10 @@ monitor_reactors_write(struct file *file, const char __user *user_buf,
|
||||||
|
|
||||||
monitor_swap_reactors(mon, reactor);
|
monitor_swap_reactors(mon, reactor);
|
||||||
|
|
||||||
retval = count;
|
return count;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
return -EINVAL;
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -309,18 +305,14 @@ static int __rv_register_reactor(struct rv_reactor *reactor)
|
||||||
*/
|
*/
|
||||||
int rv_register_reactor(struct rv_reactor *reactor)
|
int rv_register_reactor(struct rv_reactor *reactor)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if (strlen(reactor->name) >= MAX_RV_REACTOR_NAME_SIZE) {
|
if (strlen(reactor->name) >= MAX_RV_REACTOR_NAME_SIZE) {
|
||||||
pr_info("Reactor %s has a name longer than %d\n",
|
pr_info("Reactor %s has a name longer than %d\n",
|
||||||
reactor->name, MAX_RV_MONITOR_NAME_SIZE);
|
reactor->name, MAX_RV_MONITOR_NAME_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
retval = __rv_register_reactor(reactor);
|
return __rv_register_reactor(reactor);
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -331,9 +323,8 @@ int rv_register_reactor(struct rv_reactor *reactor)
|
||||||
*/
|
*/
|
||||||
int rv_unregister_reactor(struct rv_reactor *reactor)
|
int rv_unregister_reactor(struct rv_reactor *reactor)
|
||||||
{
|
{
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
list_del(&reactor->list);
|
list_del(&reactor->list);
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,7 +338,7 @@ static bool __read_mostly reacting_on;
|
||||||
*
|
*
|
||||||
* Returns 1 if on, 0 otherwise.
|
* Returns 1 if on, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
bool rv_reacting_on(void)
|
static bool rv_reacting_on(void)
|
||||||
{
|
{
|
||||||
/* Ensures that concurrent monitors read consistent reacting_on */
|
/* Ensures that concurrent monitors read consistent reacting_on */
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
|
|
@ -389,7 +380,7 @@ static ssize_t reacting_on_write_data(struct file *filp, const char __user *user
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
mutex_lock(&rv_interface_lock);
|
guard(mutex)(&rv_interface_lock);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
turn_reacting_on();
|
turn_reacting_on();
|
||||||
|
|
@ -402,8 +393,6 @@ static ssize_t reacting_on_write_data(struct file *filp, const char __user *user
|
||||||
*/
|
*/
|
||||||
tracepoint_synchronize_unregister();
|
tracepoint_synchronize_unregister();
|
||||||
|
|
||||||
mutex_unlock(&rv_interface_lock);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,14 +405,15 @@ static const struct file_operations reacting_on_fops = {
|
||||||
/**
|
/**
|
||||||
* reactor_populate_monitor - creates per monitor reactors file
|
* reactor_populate_monitor - creates per monitor reactors file
|
||||||
* @mon: The monitor.
|
* @mon: The monitor.
|
||||||
|
* @root: The directory of the monitor.
|
||||||
*
|
*
|
||||||
* Returns 0 if successful, error otherwise.
|
* Returns 0 if successful, error otherwise.
|
||||||
*/
|
*/
|
||||||
int reactor_populate_monitor(struct rv_monitor *mon)
|
int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root)
|
||||||
{
|
{
|
||||||
struct dentry *tmp;
|
struct dentry *tmp;
|
||||||
|
|
||||||
tmp = rv_create_file("reactors", RV_MODE_WRITE, mon->root_d, mon, &monitor_reactors_ops);
|
tmp = rv_create_file("reactors", RV_MODE_WRITE, root, mon, &monitor_reactors_ops);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
@ -438,7 +428,7 @@ int reactor_populate_monitor(struct rv_monitor *mon)
|
||||||
/*
|
/*
|
||||||
* Nop reactor register
|
* Nop reactor register
|
||||||
*/
|
*/
|
||||||
__printf(1, 2) static void rv_nop_reaction(const char *msg, ...)
|
__printf(1, 0) static void rv_nop_reaction(const char *msg, va_list args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,30 +440,42 @@ static struct rv_reactor rv_nop = {
|
||||||
|
|
||||||
int init_rv_reactors(struct dentry *root_dir)
|
int init_rv_reactors(struct dentry *root_dir)
|
||||||
{
|
{
|
||||||
struct dentry *available, *reacting;
|
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
available = rv_create_file("available_reactors", RV_MODE_READ, root_dir, NULL,
|
struct dentry *available __free(rv_remove) =
|
||||||
&available_reactors_ops);
|
rv_create_file("available_reactors", RV_MODE_READ, root_dir,
|
||||||
if (!available)
|
NULL, &available_reactors_ops);
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
reacting = rv_create_file("reacting_on", RV_MODE_WRITE, root_dir, NULL, &reacting_on_fops);
|
struct dentry *reacting __free(rv_remove) =
|
||||||
if (!reacting)
|
rv_create_file("reacting_on", RV_MODE_WRITE, root_dir, NULL, &reacting_on_fops);
|
||||||
goto rm_available;
|
|
||||||
|
if (!reacting || !available)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
retval = __rv_register_reactor(&rv_nop);
|
retval = __rv_register_reactor(&rv_nop);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto rm_reacting;
|
return retval;
|
||||||
|
|
||||||
turn_reacting_on();
|
turn_reacting_on();
|
||||||
|
|
||||||
|
retain_and_null_ptr(available);
|
||||||
|
retain_and_null_ptr(reacting);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
rm_reacting:
|
|
||||||
rv_remove(reacting);
|
void rv_react(struct rv_monitor *monitor, const char *msg, ...)
|
||||||
rm_available:
|
{
|
||||||
rv_remove(available);
|
static DEFINE_WAIT_OVERRIDE_MAP(rv_react_map, LD_WAIT_FREE);
|
||||||
out_err:
|
va_list args;
|
||||||
return -ENOMEM;
|
|
||||||
|
if (!rv_reacting_on() || !monitor->react)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(args, msg);
|
||||||
|
|
||||||
|
lock_map_acquire_try(&rv_react_map);
|
||||||
|
monitor->react(msg, args);
|
||||||
|
lock_map_release(&rv_react_map);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10969,7 +10969,8 @@ static __init int tracer_init_tracefs(void)
|
||||||
tracer_init_tracefs_work_func(NULL);
|
tracer_init_tracefs_work_func(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv_init_interface();
|
if (rv_init_interface())
|
||||||
|
pr_err("RV: Error while creating the RV interface\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ echo " --fail-unresolved Treat UNRESOLVED as a failure"
|
||||||
echo " -d|--debug Debug mode (trace all shell commands)"
|
echo " -d|--debug Debug mode (trace all shell commands)"
|
||||||
echo " -l|--logdir <dir> Save logs on the <dir>"
|
echo " -l|--logdir <dir> Save logs on the <dir>"
|
||||||
echo " If <dir> is -, all logs output in console only"
|
echo " If <dir> is -, all logs output in console only"
|
||||||
|
echo " --rv Run RV selftests instead of ftrace ones"
|
||||||
exit $1
|
exit $1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,6 +134,10 @@ parse_opts() { # opts
|
||||||
LINK_PTR=
|
LINK_PTR=
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--rv)
|
||||||
|
RV_TEST=1
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
*.tc)
|
*.tc)
|
||||||
if [ -f "$1" ]; then
|
if [ -f "$1" ]; then
|
||||||
OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
|
OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
|
||||||
|
|
@ -152,9 +157,13 @@ parse_opts() { # opts
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
if [ ! -z "$OPT_TEST_CASES" ]; then
|
if [ -n "$OPT_TEST_CASES" ]; then
|
||||||
TEST_CASES=$OPT_TEST_CASES
|
TEST_CASES=$OPT_TEST_CASES
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$OPT_TEST_DIR" -a -f "$OPT_TEST_DIR"/test.d/functions ]; then
|
||||||
|
TOP_DIR=$OPT_TEST_DIR
|
||||||
|
TEST_DIR=$TOP_DIR/test.d
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parameters
|
# Parameters
|
||||||
|
|
@ -190,10 +199,6 @@ fi
|
||||||
TOP_DIR=`absdir $0`
|
TOP_DIR=`absdir $0`
|
||||||
TEST_DIR=$TOP_DIR/test.d
|
TEST_DIR=$TOP_DIR/test.d
|
||||||
TEST_CASES=`find_testcases $TEST_DIR`
|
TEST_CASES=`find_testcases $TEST_DIR`
|
||||||
LOG_TOP_DIR=$TOP_DIR/logs
|
|
||||||
LOG_DATE=`date +%Y%m%d-%H%M%S`
|
|
||||||
LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/
|
|
||||||
LINK_PTR=$LOG_TOP_DIR/latest
|
|
||||||
KEEP_LOG=0
|
KEEP_LOG=0
|
||||||
KTAP=0
|
KTAP=0
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
|
|
@ -201,14 +206,23 @@ VERBOSE=0
|
||||||
UNSUPPORTED_RESULT=0
|
UNSUPPORTED_RESULT=0
|
||||||
UNRESOLVED_RESULT=0
|
UNRESOLVED_RESULT=0
|
||||||
STOP_FAILURE=0
|
STOP_FAILURE=0
|
||||||
|
RV_TEST=0
|
||||||
# Parse command-line options
|
# Parse command-line options
|
||||||
parse_opts $*
|
parse_opts $*
|
||||||
|
|
||||||
|
LOG_TOP_DIR=$TOP_DIR/logs
|
||||||
|
LOG_DATE=`date +%Y%m%d-%H%M%S`
|
||||||
|
LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/
|
||||||
|
LINK_PTR=$LOG_TOP_DIR/latest
|
||||||
|
|
||||||
[ $DEBUG -ne 0 ] && set -x
|
[ $DEBUG -ne 0 ] && set -x
|
||||||
|
|
||||||
# Verify parameters
|
if [ $RV_TEST -ne 0 ]; then
|
||||||
if [ -z "$TRACING_DIR" -o ! -d "$TRACING_DIR" ]; then
|
TRACING_DIR=$TRACING_DIR/rv
|
||||||
errexit "No ftrace directory found"
|
if [ ! -d "$TRACING_DIR" ]; then
|
||||||
|
err_ret=$err_skip
|
||||||
|
errexit "rv is not configured in this kernel"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Preparing logs
|
# Preparing logs
|
||||||
|
|
@ -419,7 +433,7 @@ trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
|
||||||
__run_test() { # testfile
|
__run_test() { # testfile
|
||||||
# setup PID and PPID, $$ is not updated.
|
# setup PID and PPID, $$ is not updated.
|
||||||
(cd $TRACING_DIR; read PID _ < /proc/self/stat; set -e; set -x;
|
(cd $TRACING_DIR; read PID _ < /proc/self/stat; set -e; set -x;
|
||||||
checkreq $1; initialize_ftrace; . $1)
|
checkreq $1; initialize_system; . $1)
|
||||||
[ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID
|
[ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,7 +510,7 @@ for t in $TEST_CASES; do
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
(cd $TRACING_DIR; finish_ftrace) # for cleanup
|
(cd $TRACING_DIR; finish_system) # for cleanup
|
||||||
|
|
||||||
prlog ""
|
prlog ""
|
||||||
prlog "# of passed: " `echo $PASSED_CASES | wc -w`
|
prlog "# of passed: " `echo $PASSED_CASES | wc -w`
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ unmount_tracefs() {
|
||||||
local mount_point="$1"
|
local mount_point="$1"
|
||||||
|
|
||||||
# Need to make sure the mount isn't busy so that we can umount it
|
# Need to make sure the mount isn't busy so that we can umount it
|
||||||
(cd $mount_point; finish_ftrace;)
|
(cd $mount_point; finish_system;)
|
||||||
|
|
||||||
cleanup
|
cleanup
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ clear_dynamic_events() { # reset all current dynamic events
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize_ftrace() { # Reset ftrace to initial-state
|
initialize_system() { # Reset ftrace to initial-state
|
||||||
# As the initial state, ftrace will be set to nop tracer,
|
# As the initial state, ftrace will be set to nop tracer,
|
||||||
# no events, no triggers, no filters, no function filters,
|
# no events, no triggers, no filters, no function filters,
|
||||||
# no probes, and tracing on.
|
# no probes, and tracing on.
|
||||||
|
|
@ -134,8 +134,8 @@ initialize_ftrace() { # Reset ftrace to initial-state
|
||||||
enable_tracing
|
enable_tracing
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_ftrace() {
|
finish_system() {
|
||||||
initialize_ftrace
|
initialize_system
|
||||||
# And recover it to default.
|
# And recover it to default.
|
||||||
[ -f options/pause-on-trace ] && echo 0 > options/pause-on-trace
|
[ -f options/pause-on-trace ] && echo 0 > options/pause-on-trace
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
logs
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
all:
|
||||||
|
|
||||||
|
TEST_PROGS := verificationtest-ktap
|
||||||
|
TEST_FILES := test.d settings
|
||||||
|
EXTRA_CLEAN := $(OUTPUT)/logs/*
|
||||||
|
|
||||||
|
include ../lib.mk
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
CONFIG_RV=y
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
timeout=0
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
check_requires() { # Check required files, monitors and reactors
|
||||||
|
for i in "$@" ; do
|
||||||
|
p=${i%:program}
|
||||||
|
m=${i%:monitor}
|
||||||
|
r=${i%:reactor}
|
||||||
|
if [ $p != $i ]; then
|
||||||
|
if ! which $p ; then
|
||||||
|
echo "Required program $p is not found."
|
||||||
|
exit_unresolved
|
||||||
|
fi
|
||||||
|
elif [ $m != $i ]; then
|
||||||
|
if ! grep -wq $m available_monitors ; then
|
||||||
|
echo "Required monitor $m is not configured."
|
||||||
|
exit_unsupported
|
||||||
|
fi
|
||||||
|
elif [ $r != $i ]; then
|
||||||
|
if ! grep -wq $r available_reactors ; then
|
||||||
|
echo "Required reactor $r is not configured."
|
||||||
|
exit_unsupported
|
||||||
|
fi
|
||||||
|
elif [ ! -e $i ]; then
|
||||||
|
echo "Required feature interface $i doesn't exist."
|
||||||
|
exit_unsupported
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize_system() { # Reset RV to initial-state
|
||||||
|
echo > enabled_monitors
|
||||||
|
for m in monitors/*; do
|
||||||
|
echo nop > $m/reactors || true
|
||||||
|
done
|
||||||
|
echo 1 > monitoring_on
|
||||||
|
echo 1 > reacting_on || true
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_system() {
|
||||||
|
initialize_system
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# description: Test monitor enable/disable
|
||||||
|
|
||||||
|
test_simple_monitor() {
|
||||||
|
local monitor="$1"
|
||||||
|
local prefix="$2" # nested monitors
|
||||||
|
|
||||||
|
echo 1 > "monitors/$prefix$monitor/enable"
|
||||||
|
grep -q "$monitor$" enabled_monitors
|
||||||
|
|
||||||
|
echo 0 > "monitors/$prefix$monitor/enable"
|
||||||
|
! grep -q "$monitor$" enabled_monitors
|
||||||
|
|
||||||
|
echo "$monitor" >> enabled_monitors
|
||||||
|
grep -q 1 "monitors/$prefix$monitor/enable"
|
||||||
|
|
||||||
|
echo "!$monitor" >> enabled_monitors
|
||||||
|
grep -q 0 "monitors/$prefix$monitor/enable"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_container_monitor() {
|
||||||
|
local monitor="$1"
|
||||||
|
local nested
|
||||||
|
|
||||||
|
echo 1 > "monitors/$monitor/enable"
|
||||||
|
grep -q "^$monitor$" enabled_monitors
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
grep -q "^$monitor:$nested$" enabled_monitors
|
||||||
|
done
|
||||||
|
test -n "$nested"
|
||||||
|
|
||||||
|
echo 0 > "monitors/$monitor/enable"
|
||||||
|
! grep -q "^$monitor$" enabled_monitors
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
! grep -q "^$monitor:$nested$" enabled_monitors
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$monitor" >> enabled_monitors
|
||||||
|
grep -q 1 "monitors/$monitor/enable"
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
grep -q "^$monitor:$nested$" enabled_monitors
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "!$monitor" >> enabled_monitors
|
||||||
|
grep -q 0 "monitors/$monitor/enable"
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
test_simple_monitor "$nested" "$monitor/"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
for monitor_dir in monitors/*; do
|
||||||
|
monitor=$(basename "$monitor_dir")
|
||||||
|
|
||||||
|
if find "$monitor_dir" -mindepth 1 -type d | grep -q .; then
|
||||||
|
test_container_monitor "$monitor"
|
||||||
|
else
|
||||||
|
test_simple_monitor "$monitor"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
! echo non_existent_monitor > enabled_monitors
|
||||||
|
! grep -q "^non_existent_monitor$" enabled_monitors
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# description: Test monitor reactor setting
|
||||||
|
# requires: available_reactors
|
||||||
|
|
||||||
|
test_monitor_reactor() {
|
||||||
|
local monitor="$1"
|
||||||
|
local prefix="$2" # nested monitors
|
||||||
|
|
||||||
|
while read -r reactor; do
|
||||||
|
[ "$reactor" = nop ] && continue
|
||||||
|
|
||||||
|
echo "$reactor" > "monitors/$prefix$monitor/reactors"
|
||||||
|
grep -q "\\[$reactor\\]" "monitors/$prefix$monitor/reactors"
|
||||||
|
done < available_reactors
|
||||||
|
|
||||||
|
echo nop > "monitors/$prefix$monitor/reactors"
|
||||||
|
grep -q "\\[nop\\]" "monitors/$prefix$monitor/reactors"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_container_monitor() {
|
||||||
|
local monitor="$1"
|
||||||
|
local nested
|
||||||
|
|
||||||
|
while read -r reactor; do
|
||||||
|
[ "$reactor" = nop ] && continue
|
||||||
|
|
||||||
|
echo "$reactor" > "monitors/$monitor/reactors"
|
||||||
|
grep -q "\\[$reactor\\]" "monitors/$monitor/reactors"
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
grep -q "\\[$reactor\\]" "monitors/$monitor/$nested/reactors"
|
||||||
|
done
|
||||||
|
done < available_reactors
|
||||||
|
test -n "$nested"
|
||||||
|
|
||||||
|
echo nop > "monitors/$monitor/reactors"
|
||||||
|
grep -q "\\[nop\\]" "monitors/$monitor/reactors"
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
grep -q "\\[nop\\]" "monitors/$monitor/$nested/reactors"
|
||||||
|
done
|
||||||
|
|
||||||
|
for nested_dir in "monitors/$monitor"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
test_monitor_reactor "$nested" "$monitor/"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
for monitor_dir in monitors/*; do
|
||||||
|
monitor=$(basename "$monitor_dir")
|
||||||
|
|
||||||
|
if find "$monitor_dir" -mindepth 1 -type d | grep -q .; then
|
||||||
|
test_container_monitor "$monitor"
|
||||||
|
else
|
||||||
|
test_monitor_reactor "$monitor"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
monitor=$(ls /sys/kernel/tracing/rv/monitors -1 | head -n 1)
|
||||||
|
test -f "monitors/$monitor/reactors"
|
||||||
|
! echo non_existent_reactor > "monitors/$monitor/reactors"
|
||||||
|
! grep -q "\\[non_existent_reactor\\]" "monitors/$monitor/reactors"
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# description: Check available monitors
|
||||||
|
|
||||||
|
for monitor_dir in monitors/*; do
|
||||||
|
monitor=$(basename "$monitor_dir")
|
||||||
|
|
||||||
|
grep -q "^$monitor$" available_monitors
|
||||||
|
grep -q . "$monitor_dir"/desc
|
||||||
|
|
||||||
|
for nested_dir in "$monitor_dir"/*; do
|
||||||
|
[ -d "$nested_dir" ] || continue
|
||||||
|
nested=$(basename "$nested_dir")
|
||||||
|
|
||||||
|
grep -q "^$monitor:$nested$" available_monitors
|
||||||
|
grep -q . "$nested_dir"/desc
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# description: Test wwnr monitor with printk reactor
|
||||||
|
# requires: available_reactors wwnr:monitor printk:reactor stress-ng:program
|
||||||
|
|
||||||
|
load() { # returns true if there was a reaction
|
||||||
|
local lines_before num
|
||||||
|
num=$((($(nproc) + 1) / 2))
|
||||||
|
lines_before=$(dmesg | wc -l)
|
||||||
|
stress-ng --cpu-sched "$num" --timer "$num" -t 5 -q
|
||||||
|
dmesg | tail -n $((lines_before + 1)) | grep -q "rv: monitor wwnr does not allow event"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo 1 > monitors/wwnr/enable
|
||||||
|
echo printk > monitors/wwnr/reactors
|
||||||
|
|
||||||
|
load
|
||||||
|
|
||||||
|
echo 0 > monitoring_on
|
||||||
|
! load
|
||||||
|
echo 1 > monitoring_on
|
||||||
|
|
||||||
|
load
|
||||||
|
|
||||||
|
echo 0 > reacting_on
|
||||||
|
! load
|
||||||
|
echo 1 > reacting_on
|
||||||
|
|
||||||
|
echo nop > monitors/wwnr/reactors
|
||||||
|
echo 0 > monitors/wwnr/enable
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# ftracetest-ktap: Wrapper to integrate ftracetest with the kselftest runner
|
||||||
|
#
|
||||||
|
# Copyright (C) Arm Ltd., 2023
|
||||||
|
|
||||||
|
../ftrace/ftracetest -K -v --rv ../verification
|
||||||
Loading…
Reference in New Issue