934 lines · 23.1 KB · C
RawDownload
/* 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.