Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME " test: " fmt
9
10#include <linux/cleanup.h>
11#include <linux/errno.h>
12#include <linux/init.h>
13#include <linux/liveupdate.h>
14#include <linux/module.h>
15#include "../../kernel/liveupdate/luo_internal.h"
16
17static const struct liveupdate_flb_ops test_flb_ops;
18#define DEFINE_TEST_FLB(i) { \
19 .ops = &test_flb_ops, \
20 .compatible = LIVEUPDATE_TEST_FLB_COMPATIBLE(i), \
21}
22
23/* Number of Test FLBs to register with every file handler */
24#define TEST_NFLBS 3
25static struct liveupdate_flb test_flbs[TEST_NFLBS] = {
26 DEFINE_TEST_FLB(0),
27 DEFINE_TEST_FLB(1),
28 DEFINE_TEST_FLB(2),
29};
30
31#define TEST_FLB_MAGIC_BASE 0xFEEDF00DCAFEBEE0ULL
32
33static int test_flb_preserve(struct liveupdate_flb_op_args *argp)
34{
35 ptrdiff_t index = argp->flb - test_flbs;
36
37 pr_info("%s: preserve was triggered\n", argp->flb->compatible);
38 argp->data = TEST_FLB_MAGIC_BASE + index;
39
40 return 0;
41}
42
43static void test_flb_unpreserve(struct liveupdate_flb_op_args *argp)
44{
45 pr_info("%s: unpreserve was triggered\n", argp->flb->compatible);
46}
47
48static int test_flb_retrieve(struct liveupdate_flb_op_args *argp)
49{
50 ptrdiff_t index = argp->flb - test_flbs;
51 u64 expected_data = TEST_FLB_MAGIC_BASE + index;
52
53 if (argp->data == expected_data) {
54 pr_info("%s: found flb data from the previous boot\n",
55 argp->flb->compatible);
56 argp->obj = (void *)argp->data;
57 } else {
58 pr_err("%s: ERROR - incorrect data handle: %llx, expected %llx\n",
59 argp->flb->compatible, argp->data, expected_data);
60 return -EINVAL;
61 }
62
63 return 0;
64}
65
66static void test_flb_finish(struct liveupdate_flb_op_args *argp)
67{
68 ptrdiff_t index = argp->flb - test_flbs;
69 void *expected_obj = (void *)(TEST_FLB_MAGIC_BASE + index);
70
71 if (argp->obj == expected_obj) {
72 pr_info("%s: finish was triggered\n", argp->flb->compatible);
73 } else {
74 pr_err("%s: ERROR - finish called with invalid object\n",
75 argp->flb->compatible);
76 }
77}
78
79static const struct liveupdate_flb_ops test_flb_ops = {
80 .preserve = test_flb_preserve,
81 .unpreserve = test_flb_unpreserve,
82 .retrieve = test_flb_retrieve,
83 .finish = test_flb_finish,
84 .owner = THIS_MODULE,
85};
86
87static void liveupdate_test_init(void)
88{
89 static DEFINE_MUTEX(init_lock);
90 static bool initialized;
91 int i;
92
93 guard(mutex)(&init_lock);
94
95 if (initialized)
96 return;
97
98 for (i = 0; i < TEST_NFLBS; i++) {
99 struct liveupdate_flb *flb = &test_flbs[i];
100 void *obj;
101 int err;
102
103 err = liveupdate_flb_get_incoming(flb, &obj);
104 if (err && err != -ENODATA && err != -ENOENT) {
105 pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
106 flb->compatible, ERR_PTR(err));
107 }
108 }
109 initialized = true;
110}
111
112void liveupdate_test_register(struct liveupdate_file_handler *fh)
113{
114 int err, i;
115
116 liveupdate_test_init();
117
118 for (i = 0; i < TEST_NFLBS; i++) {
119 struct liveupdate_flb *flb = &test_flbs[i];
120
121 err = liveupdate_register_flb(fh, flb);
122 if (err) {
123 pr_err("Failed to register %s %pe\n",
124 flb->compatible, ERR_PTR(err));
125 }
126 }
127
128 err = liveupdate_register_flb(fh, &test_flbs[0]);
129 if (!err || err != -EEXIST) {
130 pr_err("Failed: %s should be already registered, but got err: %pe\n",
131 test_flbs[0].compatible, ERR_PTR(err));
132 }
133
134 pr_info("Registered %d FLBs with file handler: [%s]\n",
135 TEST_NFLBS, fh->compatible);
136}
137
138void liveupdate_test_unregister(struct liveupdate_file_handler *fh)
139{
140 int err, i;
141
142 for (i = 0; i < TEST_NFLBS; i++) {
143 struct liveupdate_flb *flb = &test_flbs[i];
144
145 err = liveupdate_unregister_flb(fh, flb);
146 if (err) {
147 pr_err("Failed to unregister %s %pe\n",
148 flb->compatible, ERR_PTR(err));
149 }
150 }
151
152 pr_info("Unregistered %d FLBs from file handler: [%s]\n",
153 TEST_NFLBS, fh->compatible);
154}
155
156MODULE_LICENSE("GPL");
157MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
158MODULE_DESCRIPTION("In-kernel test for LUO mechanism");