This is simple test and playground useful kstate subsystem development. It contains some structure with different kind of data which migrated across kexec to the new kernel using kstate. Signed-off-by: Andrey Ryabinin --- MAINTAINERS | 1 + include/linux/kstate.h | 2 + kernel/liveupdate/Kconfig | 8 +++ lib/Makefile | 2 + lib/test_kstate.c | 116 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 lib/test_kstate.c diff --git a/MAINTAINERS b/MAINTAINERS index 2cd9e49abee5..e96da6d97e75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13723,6 +13723,7 @@ M: Andrey Ryabinin S: Maintained F: include/linux/kstate.h F: kernel/livupdate/kstate.c +F: lib/test_kstate.c KTD253 BACKLIGHT DRIVER M: Linus Walleij diff --git a/include/linux/kstate.h b/include/linux/kstate.h index 5a95960e5b03..0ced0da37c8f 100644 --- a/include/linux/kstate.h +++ b/include/linux/kstate.h @@ -95,6 +95,8 @@ struct kstate_field { enum kstate_ids { KSTATE_FOLIO_ID = 1, KSTATE_KHO_FDT_ID, + KSTATE_TEST_ID, + KSTATE_TEST_ID_V2, KSTATE_LAST_ID = -1, }; diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig index b6ea861006bf..af9a25bdcd6e 100644 --- a/kernel/liveupdate/Kconfig +++ b/kernel/liveupdate/Kconfig @@ -69,6 +69,14 @@ config KSTATE state, save it into the memory and restore the state after kexec in new kernel. +config KSTATE_TEST + bool "KSTATE test code" + help + Build a simple test/playground code that is useful for kstate + subsystem development. It contains some structure with different + kind of data which migrated across kexec to the new kernel + using KSTATE. + config KEXEC_HANDOVER bool "kexec handover" depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE diff --git a/lib/Makefile b/lib/Makefile index 392ff808c9b9..46616577caf3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -316,6 +316,8 @@ obj-$(CONFIG_PARMAN) += parman.o obj-y += group_cpus.o +obj-$(CONFIG_KSTATE_TEST) += test_kstate.o + # GCC library routines obj-$(CONFIG_GENERIC_LIB_ASHLDI3) += ashldi3.o obj-$(CONFIG_GENERIC_LIB_ASHRDI3) += ashrdi3.o diff --git a/lib/test_kstate.c b/lib/test_kstate.c new file mode 100644 index 000000000000..70534e8c718f --- /dev/null +++ b/lib/test_kstate.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +#define pr_fmt(fmt) "kstate test: " fmt +#include +#include +#include +#include +#include + +static unsigned long ulong_val; +struct kstate_test_data { + int i; + unsigned long *p_ulong; + char s[10]; + struct folio *folio; +}; + +#define KSTATE_TEST_DATA_ID 123 + +struct kstate_description test_state_v2 = { + .name = "test_v2", + .version_id = 1, + .id = KSTATE_TEST_ID_V2, + .fields = (const struct kstate_field[]) { + KSTATE_BASE_TYPE(i, struct kstate_test_data, int), + KSTATE_END_OF_LIST() + }, +}; + +struct kstate_description test_state = { + .name = "test", + .version_id = 2, + .id = KSTATE_TEST_ID, + .fields = (const struct kstate_field[]) { + KSTATE_BASE_TYPE(s, struct kstate_test_data, char [10]), + KSTATE_POINTER(p_ulong, struct kstate_test_data), + KSTATE_FOLIO(folio, struct kstate_test_data), + KSTATE_BASE_TYPE_DEPRECATED(k, u16, 1), + KSTATE_END_OF_LIST() + }, + .subsections = (const struct kstate_description *[]){ + &test_state_v2, + NULL + }, +}; + +static struct kstate_test_data test_data; + +static int init_test_data(void) +{ + struct folio *folio; + int i; + + test_data.i = 10; + ulong_val = 20; + memcpy(test_data.s, "abcdefghk", sizeof(test_data.s)); + folio = folio_alloc(GFP_KERNEL, 0); + if (!folio) + return -ENOMEM; + + for (i = 0; i < folio_size(folio)/sizeof(u32); i += 4) + *((u32 *)folio_address(folio) + i) = 0xdeadbeef; + test_data.folio = folio; + return 0; +} + +static void validate_test_data(void) +{ + int i; + + if (WARN_ON(test_data.i != 10)) + return; + if (WARN_ON(*test_data.p_ulong != 20)) + return; + if (WARN_ON(strcmp(test_data.s, "abcdefghk") != 0)) + return; + + for (i = 0; i < folio_size(test_data.folio)/4; i += 4) { + u32 val = *((u32 *)folio_address(test_data.folio) + i); + + if (WARN_ON_ONCE(val != 0xdeadbeef)) + return; + } +} + +static int __init test_kstate_init(void) +{ + int ret = 0; + + test_data.p_ulong = &ulong_val; + + ret = kstate_register(&test_state, &test_data, KSTATE_TEST_DATA_ID); + if (ret) { + pr_err("register failed %d\n", ret); + goto out; + } + + if (!is_kho_boot()) { + ret = init_test_data(); + if (ret) + goto out; + } else { + pr_info("restoring data\n"); + ret = kstate_restore(&test_state, &test_data, KSTATE_TEST_DATA_ID); + if (ret) { + pr_err("restore failed %d\n", ret); + goto out; + } + + } + + validate_test_data(); + +out: + return ret; +} +late_initcall(test_kstate_init); -- 2.49.1