From 154cd16d99f6558a410567bbb70a4cfd00043cd1 Mon Sep 17 00:00:00 2001 From: AK Date: Mon, 14 Sep 2026 14:08:08 -0400 Subject: [PATCH] Unit test fix --- test/Makefile | 16 +++++---- test/mock.c | 55 ++++++++++++++--------------- test/mock.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 130 insertions(+), 38 deletions(-) diff --git a/test/Makefile b/test/Makefile index 61947e95..18196186 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,7 +22,8 @@ CINCLUDES := \ -I. \ -I.. \ $(KERN_INCLUDES) \ - -include $(KDIR)/include/linux/kconfig.h + -include $(KDIR)/include/linux/kconfig.h \ + -include mock.h CCINCLUDES := \ -I. \ -I.. \ @@ -36,11 +37,12 @@ DEFS += -D__STRIP__ endif WARNS := -Wall -Wundef -Wno-trigraphs -Wno-sign-compare -Wuninitialized \ - -Wno-strict-aliasing -Wunused-but-set-variable -Werror -CFLAGS := $(WARNS) -Wstrict-prototypes -MD -no-pie -g $(CINCLUDES) $(DEFS) \ - -fsanitize=address -fno-omit-frame-pointer -CCFLAGS := -std=c++11 $(WARNS) -MD -g $(CCINCLUDES) $(DEFS) \ - -fsanitize=address -fno-omit-frame-pointer + -Wno-strict-aliasing -Wunused-but-set-variable -Wno-unused-variable \ + -Wno-pointer-sign -Werror +CFLAGS := $(WARNS) -Wstrict-prototypes -MD -no-pie -g -fcf-protection \ + -fsanitize=address -fno-omit-frame-pointer $(CINCLUDES) $(DEFS) +CCFLAGS := -std=c++11 $(WARNS) -MD -g -fcf-protection \ + -fsanitize=address -fno-omit-frame-pointer $(CCINCLUDES) $(DEFS) TEST_SRCS := unit_homa_incoming.c \ unit_homa_interest.c \ @@ -126,7 +128,7 @@ rhashtable.o: rhashtable.c $(CC) -c $(CFLAGS) -O2 -fno-sanitize=address $< -o $@ unit: $(OBJS) - $(CXX) $(CFLAGS) $^ -o $@ + $(CXX) $(CFLAGS) $^ -o $@ -lasan test: unit ./unit diff --git a/test/mock.c b/test/mock.c index eca8207c..e4534eb8 100644 --- a/test/mock.c +++ b/test/mock.c @@ -339,6 +339,14 @@ kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES]; #endif int __preempt_count; int cpu_number = 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) +/* Storage for the kernel's per-cpu "hot" fields (task, preempt count, + * cpu number, etc.); real per-cpu semantics don't matter for unit tests, + * which are single-threaded, but the symbol must exist to satisfy the + * linker for inline kernel functions that reference it directly. + */ +struct pcpu_hot pcpu_hot; +#endif char sock_flow_table[RPS_SOCK_FLOW_TABLE_SIZE(1024)]; struct net_hotdata net_hotdata = { .rps_cpu_mask = 0x1f, @@ -1129,27 +1137,17 @@ int kthread_stop(struct task_struct *k) return 0; } -#ifdef CONFIG_DEBUG_LIST -bool __list_add_valid(struct list_head *new, struct list_head *prev, - struct list_head *next) -{ - return true; -} -#endif - +/* __list_add_valid/__list_del_entry_valid are now provided by the + * kernel's own linux/list.h (unconditionally, regardless of + * CONFIG_DEBUG_LIST) - only the _or_report reporting hooks still need + * a definition here. + */ bool __list_add_valid_or_report(struct list_head *new, struct list_head *prev, struct list_head *next) { return true; } -#ifdef CONFIG_DEBUG_LIST -bool __list_del_entry_valid(struct list_head *entry) -{ - return true; -} -#endif - bool __list_del_entry_valid_or_report(struct list_head *entry) { return true; @@ -1183,7 +1181,7 @@ void lock_sock_nested(struct sock *sk, int subclass) sk->sk_lock.owned = 1; } -ssize_t __modver_version_show(const struct module_attribute *a, +ssize_t __modver_version_show(struct module_attribute *a, struct module_kobject *b, char *c) { return 0; @@ -1226,20 +1224,21 @@ int netif_receive_skb(struct sk_buff *skb) void __netif_schedule(struct Qdisc *q) {} -void preempt_count_add(int val) +void mock_preempt_count_add(int val) { - int i; - - for (i = 0; i < val; i++) - preempt_disable(); + /* Just adjust the mock backing-store counter directly; don't + * route through mock_preempt_disable(), since preempt_count_add() + * is used by callers (e.g. local_bh_disable()) that don't pair up + * 1-for-1 with preempt_disable()/preempt_enable(), so looping + * through the disable/enable leak-detector here would produce + * false "preempt_disables still active" failures. + */ + __preempt_count += val; } -void preempt_count_sub(int val) +void mock_preempt_count_sub(int val) { - int i; - - for (i = 0; i < val; i++) - preempt_enable(); + __preempt_count -= val; } long prepare_to_wait_event(struct wait_queue_head *wq_head, @@ -1452,9 +1451,9 @@ bool rcuref_get_slowpath(rcuref_t *ref) return true; } -bool rcuref_put_slowpath(rcuref_t *ref, unsigned int cnt) +bool rcuref_put_slowpath(rcuref_t *ref) { - return cnt == RCUREF_NOREF; + return true; } void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t) {} diff --git a/test/mock.h b/test/mock.h index 19f7f458..fdd23228 100644 --- a/test/mock.h +++ b/test/mock.h @@ -4,6 +4,89 @@ #ifndef _HOMA_MOCK_H #define _HOMA_MOCK_H +/* This file must be the very first #include for every compiled .c file + * (forced via -include mock.h in the test Makefile, before homa_impl.h and + * before any real kernel header). -> + * and -> , dragged in transitively by many + * kernel headers homa_impl.h includes (skbuff.h, kthread.h, completion.h, + * sched/signal.h, proc_fs.h, etc.), use preempt_disable()/preempt_enable()/ + * smp_processor_id()/raw_smp_processor_id()/WARN_ON_ONCE() in inline + * functions; those inline functions bake in whichever macro definition is + * active when the header is first parsed. Getting the mocked versions + * active before any of that runs requires mock.h itself to be included + * first, standalone. homa_impl.h's own later #include "mock.h" is then a + * no-op (include guard), but these overrides are already in effect. + */ +#include + +#undef WARN +#define WARN(...) + +#undef WARN_ON +#define WARN_ON(condition) ({ \ + int __ret_warn_on = !!(condition); \ + unlikely(__ret_warn_on); \ +}) + +#undef WARN_ON_ONCE +#define WARN_ON_ONCE(condition) WARN_ON(condition) + +#undef WARN_ONCE +#define WARN_ONCE(cond, ...) ({ bool __c = (cond); (void)__c; __c; }) + +/* Pulling in the real / here first (before + * the undef/define below) sets their include guards so later transitive + * re-inclusion is a no-op and can't clobber these overrides. This must + * come after the WARN overrides above, since preempt.h drags in + * (via linkage.h), whose inline functions use + * WARN_ON_ONCE() and must see the mocked (no-op) version. + */ +#include +#include + +/* Forward declarations needed because the overrides below are used by + * headers included further down in this file, before mock.c's own + * declarations (later in this file) would otherwise be visible. + */ +void mock_preempt_disable(void); +void mock_preempt_enable(void); +int mock_processor_id(void); + +#undef preempt_disable +#define preempt_disable() mock_preempt_disable() + +#undef preempt_enable +#define preempt_enable() mock_preempt_enable() + +#undef smp_processor_id +#define smp_processor_id() mock_processor_id() + +#undef raw_smp_processor_id +#define raw_smp_processor_id() mock_processor_id() + +/* (tcp_v4_check/tcp_v6_check), (this_cpu_ptr, + * via ), (icmp_send), + * (rt6_get_cookie, via ) and + * (net_generic) all declare real inline functions/objects whose names this + * file redirects below via object-style macros; those macros corrupt the + * real declarations if the real headers are parsed afterward (their + * include guards would otherwise make a later re-inclusion elsewhere a + * silent no-op with the corrupted macro baked in). Pulling them in here + * first, before any of the redirects below, avoids that. homa.h is + * included here too so the HOMA_BPAGE_SIZE/HOMA_MIN_DEFAULT_PORT/etc. + * overrides below apply after the real values are already defined, instead + * of being silently clobbered by a later #include of homa.h from + * homa_impl.h. + */ +#include +#include +#include +#include +#include +#include +#include "homa.h" +#include "homa_wire.h" + #include /* Replace various Linux variables and functions with mocked ones. */ @@ -104,6 +187,12 @@ #undef preempt_enable #define preempt_enable() mock_preempt_enable() +#undef preempt_count_add +#define preempt_count_add(val) mock_preempt_count_add(val) + +#undef preempt_count_sub +#define preempt_count_sub(val) mock_preempt_count_sub(val) + #define put_page mock_put_page #define rcu_read_lock mock_rcu_read_lock @@ -119,6 +208,8 @@ #undef register_net_sysctl #define register_net_sysctl mock_register_net_sysctl +#define rt6_get_cookie(...) 999 + #define signal_pending(...) mock_signal_pending /* Must redefine skb_frag_foreach_page because page pointers are different @@ -135,9 +226,6 @@ copied += p_len, p++, p_off = 0, \ p_len = f_len - copied) \ -#undef smp_processor_id -#define smp_processor_id() mock_processor_id() - #define sock_hold(sock) mock_sock_hold(sock) #define sock_put(sock) mock_sock_put(sock) @@ -182,6 +270,7 @@ extern int mock_copy_to_frags_errors; extern int mock_copy_to_user_dont_copy; extern int mock_copy_to_user_errors; extern int mock_cpu_idle; +extern int cpu_number; extern struct net_device mock_devices[]; extern enum skb_drop_reason @@ -275,6 +364,8 @@ int mock_page_refs(struct page *page); int mock_page_to_nid(struct page *page); void mock_preempt_disable(void); void mock_preempt_enable(void); +void mock_preempt_count_add(int val); +void mock_preempt_count_sub(int val); int mock_processor_id(void); void mock_put_page(struct page *page); struct sk_buff *