Sample code for hazptr. This should go away or get more polished when hazptr support is added into rcutorture. Signed-off-by: Boqun Feng <boqun.feng@xxxxxxxxx> --- samples/Kconfig | 6 +++ samples/Makefile | 1 + samples/hazptr/hazptr_test.c | 87 ++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 samples/hazptr/hazptr_test.c diff --git a/samples/Kconfig b/samples/Kconfig index b288d9991d27..9b42cde35dca 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -293,6 +293,12 @@ config SAMPLE_CGROUP source "samples/rust/Kconfig" +config SAMPLE_HAZPTR + bool "Build hazptr sample code" + help + Build samples that shows hazard pointer usage. Currently only + builtin usage is supported. + endif # SAMPLES config HAVE_SAMPLE_FTRACE_DIRECT diff --git a/samples/Makefile b/samples/Makefile index b85fa64390c5..0be21edc8a30 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -39,3 +39,4 @@ obj-$(CONFIG_SAMPLE_KMEMLEAK) += kmemleak/ obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight/ obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/ obj-$(CONFIG_SAMPLES_RUST) += rust/ +obj-$(CONFIG_SAMPLE_HAZPTR) += hazptr/ diff --git a/samples/hazptr/hazptr_test.c b/samples/hazptr/hazptr_test.c new file mode 100644 index 000000000000..3cf0cdc8a83a --- /dev/null +++ b/samples/hazptr/hazptr_test.c @@ -0,0 +1,87 @@ +#include <linux/module.h> +#include <linux/kthread.h> +#include <linux/hazptr.h> + +struct foo { + int i; + struct callback_head head; +}; + +static void simple_func(struct callback_head *head) +{ + struct foo *ptr = container_of(head, struct foo, head); + + printk("callback called %px, i is %d\n", ptr, ptr->i); + kfree(ptr); +} + +static void simple(void) +{ + struct hazptr_context ctx; + struct foo *dummy, *tmp, *other; + hazptr_t *hptr; + hazptr_t *hptr2; + + dummy = kzalloc(sizeof(*dummy), GFP_KERNEL); + dummy->i = 42; + + other = kzalloc(sizeof(*dummy), GFP_KERNEL); + other->i = 43; + + if (!dummy || !other) { + printk("allocation failed, skip test\n"); + return; + } + + init_hazptr_context(&ctx); + hptr = hazptr_alloc(&ctx); + BUG_ON(!hptr); + + // Get a second hptr. + hptr2 = hazptr_alloc(&ctx); + BUG_ON(!hptr2); + + // No one is modifying 'dummy', protection must succeed. + BUG_ON(!hazptr_tryprotect(hptr, dummy, head)); + + // Simulate changing a global pointer. + tmp = dummy; + WRITE_ONCE(dummy, other); + + // Callback will run after no active readers. + printk("callback added, %px\n", tmp); + + call_hazptr(&tmp->head, simple_func); + + // No one is modifying 'dummy', protection must succeed. + tmp = hazptr_protect(hptr2, dummy, head); + + printk("reader2 got %px, i is %d\n", tmp, tmp->i); + + // The above callback should run after this. + hazptr_clear(hptr); + printk("first reader is out\n"); + + for (int i = 0; i < 10; i++) + schedule(); // yield a few times. + + // Simulate freeing a global pointer. + tmp = dummy; + WRITE_ONCE(dummy, NULL); + printk("callback added, %px\n", tmp); + call_hazptr(&tmp->head, simple_func); + + cleanup_hazptr_context(&ctx); + printk("no reader here\n"); + + for (int i = 0; i < 10; i++) + schedule(); // yield a few times. +} + +static int hazptr_test(void) +{ + simple(); + printk("test ends\n"); + return 0; +} +module_init(hazptr_test); -- 2.45.2