/* SPDX-License-Identifier: GPL-2.0 *//* * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> * * Deterministic automata (DA) monitor functions, to be used together * with automata models in C generated by the rvgen tool. * * The rvgen tool is available at tools/verification/rvgen/ * * For further information, see: * Documentation/trace/rv/monitor_synthesis.rst */ #ifndef _RV_DA_MONITOR_H#define _RV_DA_MONITOR_H #include <rv/automata.h>#include <linux/rv.h>#include <rv/kunit.h>#include <linux/stringify.h>#include <linux/bug.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/hashtable.h> /* * Per-cpu variables require a unique name although static in some * configurations (e.g. alpha modules). */#define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME) static struct rv_monitor rv_this; /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes curr_state, event and next_state and returns true if the * environment constraints (e.g. timing) are satisfied, false otherwise. */#ifndef da_monitor_event_hook#define da_monitor_event_hook(...) true#endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes the da_monitor and performs further initialisation * (e.g. reset set up timers). */#ifndef da_monitor_init_hook#define da_monitor_init_hook(da_mon)#endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes the da_monitor and performs further reset (e.g. reset * all clocks). */#ifndef da_monitor_reset_hook#define da_monitor_reset_hook(da_mon)#endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that waits for the termination of all monitors background * activities (e.g. all timers). This hook can sleep. */#ifndef da_monitor_sync_hook#define da_monitor_sync_hook()#endif /* * Type for the target id, default to int but can be overridden. * A long type can work as hash table key (PER_OBJ) but will be downgraded to * int in the event tracepoint. * Unused for implicit monitors. */#ifndef da_id_type#define da_id_type int#endif static void react(enum states curr_state, enum events event){ rv_react(&rv_this, "rv: monitor %s does not allow event %s on state %s\n", __stringify(MONITOR_NAME), model_get_event_name(event), model_get_state_name(curr_state));} /* * da_monitor_reset_state - reset a monitor and setting it to init state */static inline void da_monitor_reset_state(struct da_monitor *da_mon){ WRITE_ONCE(da_mon->monitoring, 0); /* Pair with load in __ha_monitor_timer_callback */ smp_store_release(&da_mon->curr_state, model_get_initial_state());} /* * da_monitor_reset - reset a monitor and setting it to init state */static inline void da_monitor_reset(struct da_monitor *da_mon){ da_monitor_reset_hook(da_mon); da_monitor_reset_state(da_mon);} /* * da_monitor_start - start monitoring * * The monitor will ignore all events until monitoring is set to true. This * function needs to be called to tell the monitor to start monitoring. */static inline void da_monitor_start(struct da_monitor *da_mon){ da_mon->curr_state = model_get_initial_state(); da_monitor_init_hook(da_mon); /* Pairs with smp_load_acquire in da_monitoring(). */ smp_store_release(&da_mon->monitoring, 1);} /* * da_monitoring - returns true if the monitor is processing events */static inline bool da_monitoring(struct da_monitor *da_mon){ /* Pairs with smp_store_release in da_monitor_start(). */ return smp_load_acquire(&da_mon->monitoring);} /* * da_monitor_enabled - checks if the monitor is enabled */static inline bool da_monitor_enabled(void){ /* global switch */ if (unlikely(!rv_monitoring_on())) return 0; /* monitor enabled */ if (unlikely(!rv_this.enabled)) return 0; return 1;} /* * da_monitor_handling_event - checks if the monitor is ready to handle events */static inline bool da_monitor_handling_event(struct da_monitor *da_mon){ if (!da_monitor_enabled()) return 0; /* monitor is actually monitoring */ if (unlikely(!da_monitoring(da_mon))) return 0; return 1;} #if RV_MON_TYPE == RV_MON_GLOBAL/* * Functions to define, init and get a global monitor. */ /* * global monitor (a single variable) */static struct da_monitor DA_MON_NAME; /* * da_get_monitor - return the global monitor address */static struct da_monitor *da_get_monitor(void){ return &DA_MON_NAME;} /* * __da_monitor_reset_all - reset the single monitor */static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)){ reset(da_get_monitor());} /* * da_monitor_reset_all - reset the single monitor */static void da_monitor_reset_all(void){ __da_monitor_reset_all(da_monitor_reset);} /* * da_monitor_reset_state_all - reset the single monitor */static inline void da_monitor_reset_state_all(void){ __da_monitor_reset_all(da_monitor_reset_state);} /* * da_monitor_init - initialize a monitor */static inline int da_monitor_init(void){ da_monitor_reset_state_all(); return 0;} /* * da_monitor_destroy - destroy the monitor */static inline void da_monitor_destroy(void){ da_monitor_reset_all(); da_monitor_sync_hook();} #ifndef da_implicit_guard#define da_implicit_guard()#endif #elif RV_MON_TYPE == RV_MON_PER_CPU/* * Functions to define, init and get a per-cpu monitor. */ /* * per-cpu monitor variables */static DEFINE_PER_CPU(struct da_monitor, DA_MON_NAME); /* * da_get_monitor - return current CPU monitor address */static struct da_monitor *da_get_monitor(void){ return this_cpu_ptr(&DA_MON_NAME);} /* * __da_monitor_reset_all - reset all CPUs' monitor */static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)){ struct da_monitor *da_mon; int cpu; for_each_cpu(cpu, cpu_online_mask) { da_mon = per_cpu_ptr(&DA_MON_NAME, cpu); reset(da_mon); }} /* * da_monitor_reset_all - reset all CPUs' monitor */static void da_monitor_reset_all(void){ __da_monitor_reset_all(da_monitor_reset);} /* * da_monitor_reset_state_all - reset all CPUs' monitor */static inline void da_monitor_reset_state_all(void){ __da_monitor_reset_all(da_monitor_reset_state);} /* * da_monitor_init - initialize all CPUs' monitor */static inline int da_monitor_init(void){ da_monitor_reset_state_all(); return 0;} /* * da_monitor_destroy - destroy the monitor */static inline void da_monitor_destroy(void){ da_monitor_reset_all(); da_monitor_sync_hook();} #ifndef da_implicit_guard#define da_implicit_guard() guard(migrate)()#endif #elif RV_MON_TYPE == RV_MON_PER_TASK/* * Functions to define, init and get a per-task monitor. */ /* * The per-task monitor is stored a vector in the task struct. This variable * stores the position on the vector reserved for this monitor. */static int task_mon_slot = RV_PER_TASK_MONITOR_INIT; /* * da_get_monitor - return the monitor in the allocated slot for tsk */static inline struct da_monitor *da_get_monitor(struct task_struct *tsk){ return &tsk->rv[task_mon_slot].da_mon;} static inline void da_reset(struct task_struct *tsk){ da_monitor_reset(da_get_monitor(tsk));} /* * da_get_target - return the task associated to the monitor */static inline struct task_struct *da_get_target(struct da_monitor *da_mon){ return container_of(da_mon, struct task_struct, rv[task_mon_slot].da_mon);} /* * da_get_id - return the id associated to the monitor * * For per-task monitors, the id is the task's PID. */static inline da_id_type da_get_id(struct da_monitor *da_mon){ return da_get_target(da_mon)->pid;} static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)){ struct task_struct *g, *p; int cpu; scoped_guard(read_lock, &tasklist_lock) { for_each_process_thread(g, p) reset(da_get_monitor(p)); } for_each_present_cpu(cpu) reset(da_get_monitor(idle_task(cpu)));} static void da_monitor_reset_all(void){ __da_monitor_reset_all(da_monitor_reset);} static inline void da_monitor_reset_state_all(void){ __da_monitor_reset_all(da_monitor_reset_state);} /* * da_monitor_init - initialize the per-task monitor * * Try to allocate a slot in the task's vector of monitors. If there * is an available slot, use it and reset all task's monitor. */static int da_monitor_init(void){ int slot; slot = rv_get_task_monitor_slot(); if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT) return slot; task_mon_slot = slot; da_monitor_reset_state_all(); return 0;} /* * da_monitor_destroy - return the allocated slot * * Wait for all in-flight handlers before returning the slot to avoid * out-of-bound accesses. */static inline void da_monitor_destroy(void){ if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) { WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME)); return; } tracepoint_synchronize_unregister(); da_monitor_reset_all(); da_monitor_sync_hook(); rv_put_task_monitor_slot(task_mon_slot); task_mon_slot = RV_PER_TASK_MONITOR_INIT;} #elif RV_MON_TYPE == RV_MON_PER_OBJ/* * Functions to define, init and get a per-object monitor. */ struct da_monitor_storage { da_id_type id; monitor_target target; union rv_task_monitor rv; struct hlist_node node; struct rcu_head rcu;}; #ifndef DA_MONITOR_HT_BITS#define DA_MONITOR_HT_BITS 10#endifstatic DEFINE_HASHTABLE(da_monitor_ht, DA_MONITOR_HT_BITS); /* * da_create_empty_storage - pre-allocate an empty storage */static inline struct da_monitor_storage *da_create_empty_storage(da_id_type id){ struct da_monitor_storage *mon_storage; mon_storage = kmalloc_nolock(sizeof(struct da_monitor_storage), __GFP_ZERO, NUMA_NO_NODE); if (!mon_storage) return NULL; hash_add_rcu(da_monitor_ht, &mon_storage->node, id); mon_storage->id = id; return mon_storage;} /* * da_create_storage - create the per-object storage * * The caller is responsible to synchronise writers, either with locks or * implicitly. For instance, if da_create_storage is only called from a single * event for target (e.g. sched_switch), it's safe to call this without locks. */static inline struct da_monitor *da_create_storage(da_id_type id, monitor_target target, struct da_monitor *da_mon){ struct da_monitor_storage *mon_storage; if (da_mon) return da_mon; mon_storage = da_create_empty_storage(id); if (!mon_storage) return NULL; mon_storage->target = target; return &mon_storage->rv.da_mon;} /* * __da_get_mon_storage - get the monitor storage from the hash table */static inline struct da_monitor_storage *__da_get_mon_storage(da_id_type id){ struct da_monitor_storage *mon_storage; lockdep_assert_in_rcu_read_lock(); hash_for_each_possible_rcu(da_monitor_ht, mon_storage, node, id) { if (mon_storage->id == id) return mon_storage; } return NULL;} /* * da_get_monitor - return the monitor for target */static struct da_monitor *da_get_monitor(da_id_type id, monitor_target target){ struct da_monitor_storage *mon_storage; mon_storage = __da_get_mon_storage(id); return mon_storage ? &mon_storage->rv.da_mon : NULL;} /* * da_get_target - return the object associated to the monitor */static inline monitor_target da_get_target(struct da_monitor *da_mon){ return container_of(da_mon, struct da_monitor_storage, rv.da_mon)->target;} /* * da_get_id - return the id associated to the monitor */static inline da_id_type da_get_id(struct da_monitor *da_mon){Lines 1–500 of 934. Load more
/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> * * Deterministic automata (DA) monitor functions, to be used together * with automata models in C generated by the rvgen tool. * * The rvgen tool is available at tools/verification/rvgen/ * * For further information, see: * Documentation/trace/rv/monitor_synthesis.rst */ #ifndef _RV_DA_MONITOR_H #define _RV_DA_MONITOR_H #include <rv/automata.h> #include <linux/rv.h> #include <rv/kunit.h> #include <linux/stringify.h> #include <linux/bug.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/hashtable.h> /* * Per-cpu variables require a unique name although static in some * configurations (e.g. alpha modules). */ #define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME) static struct rv_monitor rv_this; /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes curr_state, event and next_state and returns true if the * environment constraints (e.g. timing) are satisfied, false otherwise. */ #ifndef da_monitor_event_hook #define da_monitor_event_hook(...) true #endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes the da_monitor and performs further initialisation * (e.g. reset set up timers). */ #ifndef da_monitor_init_hook #define da_monitor_init_hook(da_mon) #endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes the da_monitor and performs further reset (e.g. reset * all clocks). */ #ifndef da_monitor_reset_hook #define da_monitor_reset_hook(da_mon) #endif /* * Hook to allow the implementation of hybrid automata: define it with a * function that waits for the termination of all monitors background * activities (e.g. all timers). This hook can sleep. */ #ifndef da_monitor_sync_hook #define da_monitor_sync_hook() #endif /* * Type for the target id, default to int but can be overridden. * A long type can work as hash table key (PER_OBJ) but will be downgraded to * int in the event tracepoint. * Unused for implicit monitors. */ #ifndef da_id_type #define da_id_type int #endif static void react(enum states curr_state, enum events event) { rv_react(&rv_this, "rv: monitor %s does not allow event %s on state %s\n", __stringify(MONITOR_NAME), model_get_event_name(event), model_get_state_name(curr_state)); } /* * da_monitor_reset_state - reset a monitor and setting it to init state */ static inline void da_monitor_reset_state(struct da_monitor *da_mon) { WRITE_ONCE(da_mon->monitoring, 0); /* Pair with load in __ha_monitor_timer_callback */ smp_store_release(&da_mon->curr_state, model_get_initial_state()); } /* * da_monitor_reset - reset a monitor and setting it to init state */ static inline void da_monitor_reset(struct da_monitor *da_mon) { da_monitor_reset_hook(da_mon); da_monitor_reset_state(da_mon); } /* * da_monitor_start - start monitoring * * The monitor will ignore all events until monitoring is set to true. This * function needs to be called to tell the monitor to start monitoring. */ static inline void da_monitor_start(struct da_monitor *da_mon) { da_mon->curr_state = model_get_initial_state(); da_monitor_init_hook(da_mon); /* Pairs with smp_load_acquire in da_monitoring(). */ smp_store_release(&da_mon->monitoring, 1); } /* * da_monitoring - returns true if the monitor is processing events */ static inline bool da_monitoring(struct da_monitor *da_mon) { /* Pairs with smp_store_release in da_monitor_start(). */ return smp_load_acquire(&da_mon->monitoring); } /* * da_monitor_enabled - checks if the monitor is enabled */ static inline bool da_monitor_enabled(void) { /* global switch */ if (unlikely(!rv_monitoring_on())) return 0; /* monitor enabled */ if (unlikely(!rv_this.enabled)) return 0; return 1; } /* * da_monitor_handling_event - checks if the monitor is ready to handle events */ static inline bool da_monitor_handling_event(struct da_monitor *da_mon) { if (!da_monitor_enabled()) return 0; /* monitor is actually monitoring */ if (unlikely(!da_monitoring(da_mon))) return 0; return 1; } #if RV_MON_TYPE == RV_MON_GLOBAL /* * Functions to define, init and get a global monitor. */ /* * global monitor (a single variable) */ static struct da_monitor DA_MON_NAME; /* * da_get_monitor - return the global monitor address */ static struct da_monitor *da_get_monitor(void) { return &DA_MON_NAME; } /* * __da_monitor_reset_all - reset the single monitor */ static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)) { reset(da_get_monitor()); } /* * da_monitor_reset_all - reset the single monitor */ static void da_monitor_reset_all(void) { __da_monitor_reset_all(da_monitor_reset); } /* * da_monitor_reset_state_all - reset the single monitor */ static inline void da_monitor_reset_state_all(void) { __da_monitor_reset_all(da_monitor_reset_state); } /* * da_monitor_init - initialize a monitor */ static inline int da_monitor_init(void) { da_monitor_reset_state_all(); return 0; } /* * da_monitor_destroy - destroy the monitor */ static inline void da_monitor_destroy(void) { da_monitor_reset_all(); da_monitor_sync_hook(); } #ifndef da_implicit_guard #define da_implicit_guard() #endif #elif RV_MON_TYPE == RV_MON_PER_CPU /* * Functions to define, init and get a per-cpu monitor. */ /* * per-cpu monitor variables */ static DEFINE_PER_CPU(struct da_monitor, DA_MON_NAME); /* * da_get_monitor - return current CPU monitor address */ static struct da_monitor *da_get_monitor(void) { return this_cpu_ptr(&DA_MON_NAME); } /* * __da_monitor_reset_all - reset all CPUs' monitor */ static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)) { struct da_monitor *da_mon; int cpu; for_each_cpu(cpu, cpu_online_mask) { da_mon = per_cpu_ptr(&DA_MON_NAME, cpu); reset(da_mon); } } /* * da_monitor_reset_all - reset all CPUs' monitor */ static void da_monitor_reset_all(void) { __da_monitor_reset_all(da_monitor_reset); } /* * da_monitor_reset_state_all - reset all CPUs' monitor */ static inline void da_monitor_reset_state_all(void) { __da_monitor_reset_all(da_monitor_reset_state); } /* * da_monitor_init - initialize all CPUs' monitor */ static inline int da_monitor_init(void) { da_monitor_reset_state_all(); return 0; } /* * da_monitor_destroy - destroy the monitor */ static inline void da_monitor_destroy(void) { da_monitor_reset_all(); da_monitor_sync_hook(); } #ifndef da_implicit_guard #define da_implicit_guard() guard(migrate)() #endif #elif RV_MON_TYPE == RV_MON_PER_TASK /* * Functions to define, init and get a per-task monitor. */ /* * The per-task monitor is stored a vector in the task struct. This variable * stores the position on the vector reserved for this monitor. */ static int task_mon_slot = RV_PER_TASK_MONITOR_INIT; /* * da_get_monitor - return the monitor in the allocated slot for tsk */ static inline struct da_monitor *da_get_monitor(struct task_struct *tsk) { return &tsk->rv[task_mon_slot].da_mon; } static inline void da_reset(struct task_struct *tsk) { da_monitor_reset(da_get_monitor(tsk)); } /* * da_get_target - return the task associated to the monitor */ static inline struct task_struct *da_get_target(struct da_monitor *da_mon) { return container_of(da_mon, struct task_struct, rv[task_mon_slot].da_mon); } /* * da_get_id - return the id associated to the monitor * * For per-task monitors, the id is the task's PID. */ static inline da_id_type da_get_id(struct da_monitor *da_mon) { return da_get_target(da_mon)->pid; } static void __da_monitor_reset_all(void (*reset)(struct da_monitor *)) { struct task_struct *g, *p; int cpu; scoped_guard(read_lock, &tasklist_lock) { for_each_process_thread(g, p) reset(da_get_monitor(p)); } for_each_present_cpu(cpu) reset(da_get_monitor(idle_task(cpu))); } static void da_monitor_reset_all(void) { __da_monitor_reset_all(da_monitor_reset); } static inline void da_monitor_reset_state_all(void) { __da_monitor_reset_all(da_monitor_reset_state); } /* * da_monitor_init - initialize the per-task monitor * * Try to allocate a slot in the task's vector of monitors. If there * is an available slot, use it and reset all task's monitor. */ static int da_monitor_init(void) { int slot; slot = rv_get_task_monitor_slot(); if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT) return slot; task_mon_slot = slot; da_monitor_reset_state_all(); return 0; } /* * da_monitor_destroy - return the allocated slot * * Wait for all in-flight handlers before returning the slot to avoid * out-of-bound accesses. */ static inline void da_monitor_destroy(void) { if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) { WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME)); return; } tracepoint_synchronize_unregister(); da_monitor_reset_all(); da_monitor_sync_hook(); rv_put_task_monitor_slot(task_mon_slot); task_mon_slot = RV_PER_TASK_MONITOR_INIT; } #elif RV_MON_TYPE == RV_MON_PER_OBJ /* * Functions to define, init and get a per-object monitor. */ struct da_monitor_storage { da_id_type id; monitor_target target; union rv_task_monitor rv; struct hlist_node node; struct rcu_head rcu; }; #ifndef DA_MONITOR_HT_BITS #define DA_MONITOR_HT_BITS 10 #endif static DEFINE_HASHTABLE(da_monitor_ht, DA_MONITOR_HT_BITS); /* * da_create_empty_storage - pre-allocate an empty storage */ static inline struct da_monitor_storage *da_create_empty_storage(da_id_type id) { struct da_monitor_storage *mon_storage; mon_storage = kmalloc_nolock(sizeof(struct da_monitor_storage), __GFP_ZERO, NUMA_NO_NODE); if (!mon_storage) return NULL; hash_add_rcu(da_monitor_ht, &mon_storage->node, id); mon_storage->id = id; return mon_storage; } /* * da_create_storage - create the per-object storage * * The caller is responsible to synchronise writers, either with locks or * implicitly. For instance, if da_create_storage is only called from a single * event for target (e.g. sched_switch), it's safe to call this without locks. */ static inline struct da_monitor *da_create_storage(da_id_type id, monitor_target target, struct da_monitor *da_mon) { struct da_monitor_storage *mon_storage; if (da_mon) return da_mon; mon_storage = da_create_empty_storage(id); if (!mon_storage) return NULL; mon_storage->target = target; return &mon_storage->rv.da_mon; } /* * __da_get_mon_storage - get the monitor storage from the hash table */ static inline struct da_monitor_storage *__da_get_mon_storage(da_id_type id) { struct da_monitor_storage *mon_storage; lockdep_assert_in_rcu_read_lock(); hash_for_each_possible_rcu(da_monitor_ht, mon_storage, node, id) { if (mon_storage->id == id) return mon_storage; } return NULL; } /* * da_get_monitor - return the monitor for target */ static struct da_monitor *da_get_monitor(da_id_type id, monitor_target target) { struct da_monitor_storage *mon_storage; mon_storage = __da_get_mon_storage(id); return mon_storage ? &mon_storage->rv.da_mon : NULL; } /* * da_get_target - return the object associated to the monitor */ static inline monitor_target da_get_target(struct da_monitor *da_mon) { return container_of(da_mon, struct da_monitor_storage, rv.da_mon)->target; } /* * da_get_id - return the id associated to the monitor */ static inline da_id_type da_get_id(struct da_monitor *da_mon) {