--- zzzz-none-000/linux-3.10.107/kernel/timer.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/kernel/timer.c 2021-11-10 11:53:56.000000000 +0000 @@ -42,6 +42,11 @@ #include #include #include +#if defined(CONFIG_AVM_ENHANCED) +#include +#include +#include +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ #include #include @@ -51,6 +56,9 @@ #define CREATE_TRACE_POINTS #include +#if defined(CONFIG_AVM_SIMPLE_PROFILING) +#include +#endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; @@ -81,6 +89,11 @@ unsigned long timer_jiffies; unsigned long next_timer; unsigned long active_timers; +#if defined(CONFIG_AVM_ENHANCED) + void *last_fn; + void *next_fn; + unsigned long last_expire; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ struct tvec_root tv1; struct tvec tv2; struct tvec tv3; @@ -473,7 +486,7 @@ * is tracked in the object tracker. */ if (timer->entry.next == NULL && - timer->entry.prev == TIMER_ENTRY_STATIC) { + timer->entry.prev == TIMER_ENTRY_STATIC) { debug_object_init(timer, &timer_debug_descr); debug_object_activate(timer, &timer_debug_descr); return 0; @@ -574,7 +587,7 @@ const char *name, struct lock_class_key *key); void init_timer_on_stack_key(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key) + const char *name, struct lock_class_key *key) { debug_object_init_on_stack(timer, &timer_debug_descr); do_init_timer(timer, flags, name, key); @@ -646,7 +659,7 @@ * other timer functions. */ void init_timer_key(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key) + const char *name, struct lock_class_key *key) { debug_init(timer); do_init_timer(timer, flags, name, key); @@ -674,7 +687,7 @@ } static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, - bool clear_pending) + bool clear_pending) { if (!timer_pending(timer)) return 0; @@ -1127,7 +1140,13 @@ lock_map_acquire(&lockdep_map); trace_timer_expire_entry(timer); +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_log(avm_profile_data_type_timer_begin, (unsigned int)fn, (unsigned int)data); +#endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ fn(data); +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_log(avm_profile_data_type_timer_end, (unsigned int)fn, (unsigned int)data); +#endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ trace_timer_expire_exit(timer); lock_map_release(&lockdep_map); @@ -1198,6 +1217,10 @@ call_timer_fn(timer, fn, data); spin_lock_irq(&base->lock); } +#if defined(CONFIG_AVM_ENHANCED) + base->last_fn = fn; + base->last_expire = jiffies; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ } } base->running_timer = NULL; @@ -1230,6 +1253,9 @@ /* Look at the cascade bucket(s)? */ if (!index || slot < index) goto cascade; +#if defined(CONFIG_AVM_ENHANCED) + base->next_fn = nte->function; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ return expires; } slot = (slot + 1) & TVR_MASK; @@ -1268,6 +1294,9 @@ /* Look at the cascade bucket(s)? */ if (!index || slot < index) break; +#if defined(CONFIG_AVM_ENHANCED) + base->next_fn = nte->function; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ return expires; } slot = (slot + 1) & TVN_MASK; @@ -1277,6 +1306,9 @@ timer_jiffies += TVN_SIZE - index; timer_jiffies >>= TVN_BITS; } +#if defined(CONFIG_AVM_ENHANCED) + base->next_fn = NULL; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ return expires; } @@ -1285,7 +1317,7 @@ * event: */ static unsigned long cmp_next_hrtimer_event(unsigned long now, - unsigned long expires) + unsigned long expires) { ktime_t hr_delta = hrtimer_get_next_event(); struct timespec tsdelta; @@ -1661,7 +1693,7 @@ BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK); err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, - (void *)(long)smp_processor_id()); + (void *)(long)smp_processor_id()); init_timer_stats(); BUG_ON(err != NOTIFY_OK); @@ -1719,3 +1751,133 @@ do_usleep_range(min, max); } EXPORT_SYMBOL(usleep_range); + +#if defined(CONFIG_AVM_ENHANCED) +static int nmi_timer_notify(struct notifier_block *self, unsigned long dummy, void *param); +static int module_check_notifier(struct notifier_block *nb, unsigned long val, void *data); +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static struct notifier_block nmi_timer_nb = { + .notifier_call = nmi_timer_notify, + .priority = INT_MAX - 1, +}; +static struct notifier_block module_check_nb = { + .notifier_call = module_check_notifier, + .priority = INT_MAX, +}; +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static void small_timer_statistic(void) { + struct tvec_base *base; + unsigned long flags, ts; + int cpu; + + ts = jiffies; + for_each_online_cpu(cpu) { + base = per_cpu(tvec_bases, cpu); + if(spin_trylock_irqsave(&base->lock, flags)) { + unsigned long next_timer = __next_timer_interrupt(base); + printk(KERN_ERR"CPU%u: active_timers: %lu\n" + " last: %pS before %d ms\n" + " running: %pS\n" + " next: %pS in %d ms\n", + cpu, base->active_timers, + base->last_fn, jiffies_to_msecs(ts - base->last_expire), + base->running_timer ? base->running_timer->function : NULL, + base->next_fn, jiffies_to_msecs(next_timer - ts)); + spin_unlock_irqrestore(&base->lock, flags); + } else { + printk(KERN_ERR"%s: can't get lock on cpu%u\n", __func__, cpu); + } + } +} +#define is_in_range(pos, start, size) ((pos) >= (start) && ((pos) < (start + size))) +#define set_varray(idx, type) varray[idx].vec = (struct tvec *)&base->type, \ + varray[idx].slot_size = ARRAY_SIZE(base->type.vec) + +/** + */ +static int check_pending_timer_on_module_exit_on_base(int cpu, struct tvec_base *base, unsigned long module_addr, + unsigned long module_size) { + int slot, array; + unsigned long flags; + struct timer_list *nte; + int timer_pending = 0; + struct _varray { + struct tvec *vec; + unsigned int slot_size; + } varray[5]; + + set_varray(0, tv1); + set_varray(1, tv2); + set_varray(2, tv3); + set_varray(3, tv4); + set_varray(4, tv5); + + if(!spin_trylock_irqsave(&base->lock, flags)) { + printk(KERN_ERR"%s: can't get lock on cpu%u\n", __func__, cpu); + return 0; + } + /* Look tv1-tv5. */ + for (array = 0; array < ARRAY_SIZE(varray); array++) { + struct tvec *varp = varray[array].vec; + + for(slot = 0; slot < varray[array].slot_size; slot++) { + list_for_each_entry(nte, varp->vec + slot, entry) { +#if 0 + pr_err("%s: %u: tv%u: slot=%u expires in %d ms %pS %s\n", __func__, __LINE__, + array+1, slot, jiffies_to_msecs(nte->expires - jiffies), nte->function, + tbase_get_deferrable(nte->base) ? "deferable" : ""); +#endif + if(is_in_range((unsigned long)nte->function, module_addr, module_size)) { + avm_DebugSignalLog(0, "great error: timer with caller %pS pending (expired in %d ms)." + "Can't unload module!\n", + nte->function, jiffies_to_msecs(nte->expires - jiffies)); + timer_pending |= 1; + } + } + } + } + spin_unlock_irqrestore(&base->lock, flags); + return timer_pending; +} +/** + */ +static int check_pending_timer_on_module_exit(unsigned long module_addr, unsigned long module_size) { + struct tvec_base *base; + int cpu, timer_pending = 0; + for_each_online_cpu(cpu) { + base = per_cpu(tvec_bases, cpu); + timer_pending |= check_pending_timer_on_module_exit_on_base(cpu, base, module_addr, module_size); + } + return timer_pending; +} +/** + */ +static int module_check_notifier(struct notifier_block *nb, unsigned long val, void *data) { + struct module *mod = data; + + if (val != MODULE_STATE_GOING) + return NOTIFY_DONE; + +// pr_err("%s: %u: addr=%p size=%u\n", __func__, __LINE__, mod->module_core, mod->core_size); + return check_pending_timer_on_module_exit((unsigned long)mod->module_core, mod->core_size) ? + NOTIFY_BAD : NOTIFY_DONE; +} +/** + */ +static int nmi_timer_notify(struct notifier_block *self __maybe_unused, unsigned long dummy __maybe_unused, + void *param __maybe_unused) { + small_timer_statistic(); + return NOTIFY_OK; +} +/** + */ +static int __init small_timer_statistic_init(void) { + /*--- printk(KERN_ERR"%s: init\n", __func__); ---*/ + register_nmi_notifier(&nmi_timer_nb); + register_module_notifier(&module_check_nb); + return 0; +} +late_initcall(small_timer_statistic_init); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/