summaryrefslogtreecommitdiff
path: root/lib/tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tests')
-rw-r--r--lib/tests/Makefile2
-rw-r--r--lib/tests/blackhole_dev_kunit.c2
-rw-r--r--lib/tests/cmdline_kunit.c118
-rw-r--r--lib/tests/fortify_kunit.c61
-rw-r--r--lib/tests/kunit_iov_iter.c241
-rw-r--r--lib/tests/liveupdate.c21
-rw-r--r--lib/tests/printf_kunit.c46
-rw-r--r--lib/tests/random32_kunit.c182
-rw-r--r--lib/tests/seq_buf_kunit.c34
-rw-r--r--lib/tests/shdi3_kunit.c175
-rw-r--r--lib/tests/slub_kunit.c182
-rw-r--r--lib/tests/string_helpers_kunit.c15
-rw-r--r--lib/tests/string_kunit.c274
-rw-r--r--lib/tests/test_kprobes.c29
-rw-r--r--lib/tests/test_ratelimit.c29
-rw-r--r--lib/tests/uuid_kunit.c56
16 files changed, 1351 insertions, 116 deletions
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 05f74edbc62b..3cac3b63a752 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_BASE64_KUNIT) += base64_kunit.o
obj-$(CONFIG_BITOPS_KUNIT) += bitops_kunit.o
obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
obj-$(CONFIG_BITS_TEST) += test_bits.o
+obj-$(CONFIG_SHDI3_KUNIT_TEST) += shdi3_kunit.o
obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o
obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
@@ -40,6 +41,7 @@ obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
obj-$(CONFIG_MIN_HEAP_KUNIT_TEST) += min_heap_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
+obj-$(CONFIG_PRANDOM_KUNIT_TEST) += random32_kunit.o
obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o
obj-$(CONFIG_RANDSTRUCT_KUNIT_TEST) += randstruct_kunit.o
obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o
diff --git a/lib/tests/blackhole_dev_kunit.c b/lib/tests/blackhole_dev_kunit.c
index 06834ab35f43..fa3e0533038d 100644
--- a/lib/tests/blackhole_dev_kunit.c
+++ b/lib/tests/blackhole_dev_kunit.c
@@ -46,7 +46,7 @@ static void test_blackholedev(struct kunit *test)
uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr));
skb_set_transport_header(skb, 0);
uh->source = uh->dest = htons(UDP_PORT);
- uh->len = htons(data_len);
+ udp_set_len_short(uh, data_len);
uh->check = 0;
/* (Network) IPv6 */
ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));
diff --git a/lib/tests/cmdline_kunit.c b/lib/tests/cmdline_kunit.c
index c1602f797637..3f61ff8d3178 100644
--- a/lib/tests/cmdline_kunit.c
+++ b/lib/tests/cmdline_kunit.c
@@ -6,6 +6,7 @@
#include <kunit/test.h>
#include <linux/kernel.h>
#include <linux/random.h>
+#include <linux/sizes.h>
#include <linux/string.h>
static const char *cmdline_test_strings[] = {
@@ -139,11 +140,128 @@ static void cmdline_test_range(struct kunit *test)
} while (++i < ARRAY_SIZE(cmdline_test_range_strings));
}
+static void cmdline_test_next_arg_quoted_value(struct kunit *test)
+{
+ char in[] = "foo=\"bar baz\" qux=1";
+ char *next, *param, *val;
+
+ next = next_arg(in, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "foo");
+ KUNIT_ASSERT_NOT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, val, "bar baz");
+ KUNIT_EXPECT_STREQ(test, next, "qux=1");
+
+ next = next_arg(next, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "qux");
+ KUNIT_ASSERT_NOT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, val, "1");
+ KUNIT_EXPECT_STREQ(test, next, "");
+}
+
+static void cmdline_test_next_arg_bare_quote_regression(struct kunit *test)
+{
+ char in[] = "foo=bar \"";
+ char *next, *param, *val;
+
+ next = next_arg(in, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "foo");
+ KUNIT_ASSERT_NOT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, val, "bar");
+ KUNIT_EXPECT_STREQ(test, next, "\"");
+
+ /* This hits the i == 0 quoted-token case fixed by 9847f21225c4. */
+ next = next_arg(next, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "");
+ KUNIT_EXPECT_PTR_EQ(test, val, NULL);
+ KUNIT_EXPECT_STREQ(test, next, "");
+}
+
+static void cmdline_test_next_arg_mixed_tokens(struct kunit *test)
+{
+ char in[] = "bbb= jjj kkk=\"a=b\"";
+ char *next, *param, *val;
+
+ next = next_arg(in, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "bbb");
+ KUNIT_ASSERT_NOT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, val, "");
+ KUNIT_EXPECT_STREQ(test, next, "jjj kkk=\"a=b\"");
+
+ next = next_arg(next, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "jjj");
+ KUNIT_EXPECT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, next, "kkk=\"a=b\"");
+
+ next = next_arg(next, &param, &val);
+ KUNIT_EXPECT_STREQ(test, param, "kkk");
+ KUNIT_ASSERT_NOT_NULL(test, val);
+ KUNIT_EXPECT_STREQ(test, val, "a=b");
+ KUNIT_EXPECT_STREQ(test, next, "");
+}
+
+struct cmdline_test_memparse_entry {
+ const char *input;
+ const char *unrecognized;
+ unsigned long long result;
+};
+
+static const struct cmdline_test_memparse_entry testdata[] = {
+ { "0", "", 0ULL },
+ { "1", "", 1ULL },
+ { "a", "a", 0ULL },
+ { "k", "k", 0ULL },
+ { "E", "E", 0ULL },
+ { "0xb", "", 11ULL },
+ { "0xz", "x", 0ULL },
+ { "1234", "", 1234ULL },
+ { "04567", "", 2423ULL },
+ { "0x9876", "", 39030LL },
+ { "05678", "8", 375ULL },
+ { "0xabcdefz", "z", 11259375ULL },
+ { "0cdba", "c", 0ULL },
+ { "4K", "", SZ_4K },
+ { "0x10k@0xaaaabbbb", "@", SZ_16K },
+ { "32M", "", SZ_32M },
+ { "067m:foo", ":", 55 * SZ_1M },
+ { "2G;bar=baz", ";", SZ_2G },
+ { "07gz", "z", 7ULL * SZ_1G },
+ { "3T+data", "+", 3 * SZ_1T },
+ { "04t,ro", ",", SZ_4T },
+ { "012p", "", 11258999068426240ULL },
+ { "7P,sync", ",", 7881299347898368ULL },
+ { "0x2e", "", 46ULL },
+ { "2E and more", " ", 2305843009213693952ULL },
+ { "18446744073709551615", "", ULLONG_MAX },
+ { "0xffffffffffffffff0", "", ULLONG_MAX },
+ { "1111111111111111111T", "", ULLONG_MAX },
+ { "222222222222222222222G", "", ULLONG_MAX },
+ { "3333333333333333333333M", "", ULLONG_MAX },
+};
+
+static void cmdline_test_memparse(struct kunit *test)
+{
+ const struct cmdline_test_memparse_entry *e;
+ unsigned long long ret;
+ char *retptr;
+
+ for (e = testdata; e < testdata + ARRAY_SIZE(testdata); e++) {
+ ret = memparse(e->input, &retptr);
+ KUNIT_EXPECT_EQ_MSG(test, ret, e->result,
+ " when parsing '%s'", e->input);
+ KUNIT_EXPECT_EQ_MSG(test, *retptr, *e->unrecognized,
+ " when parsing '%s'", e->input);
+ }
+}
+
static struct kunit_case cmdline_test_cases[] = {
KUNIT_CASE(cmdline_test_noint),
KUNIT_CASE(cmdline_test_lead_int),
KUNIT_CASE(cmdline_test_tail_int),
KUNIT_CASE(cmdline_test_range),
+ KUNIT_CASE(cmdline_test_next_arg_quoted_value),
+ KUNIT_CASE(cmdline_test_next_arg_bare_quote_regression),
+ KUNIT_CASE(cmdline_test_next_arg_mixed_tokens),
+ KUNIT_CASE(cmdline_test_memparse),
{}
};
diff --git a/lib/tests/fortify_kunit.c b/lib/tests/fortify_kunit.c
index fc9c76f026d6..413cdbf3dc0d 100644
--- a/lib/tests/fortify_kunit.c
+++ b/lib/tests/fortify_kunit.c
@@ -458,7 +458,7 @@ static void fortify_test_strnlen(struct kunit *test)
/* Make string unterminated, and recount. */
pad.buf[end] = 'A';
end = sizeof(pad.buf);
- /* Reading beyond with strncpy() will fail. */
+ /* Reading beyond will fail. */
KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 1), end);
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1);
KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 2), end);
@@ -531,64 +531,6 @@ static void fortify_test_strcpy(struct kunit *test)
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
}
-static void fortify_test_strncpy(struct kunit *test)
-{
- struct fortify_padding pad = { };
- char src[] = "Copy me fully into a small buffer and I will overflow!";
- size_t sizeof_buf = sizeof(pad.buf);
-
- OPTIMIZER_HIDE_VAR(sizeof_buf);
-
- /* Destination is %NUL-filled to start with. */
- KUNIT_EXPECT_EQ(test, pad.bytes_before, 0);
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0');
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* Legitimate strncpy() 1 less than of max size. */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf - 1)
- == pad.buf);
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
- /* Only last byte should be %NUL */
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0');
-
- /* Legitimate (though unterminated) max-size strncpy. */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf)
- == pad.buf);
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
- /* No trailing %NUL -- thanks strncpy API. */
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* But we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* Now verify that FORTIFY is working... */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 1)
- == pad.buf);
- /* Should catch the overflow. */
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1);
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* And we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* And further... */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 2)
- == pad.buf);
- /* Should catch the overflow. */
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2);
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* And we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-}
-
static void fortify_test_strscpy(struct kunit *test)
{
struct fortify_padding pad = { };
@@ -1100,7 +1042,6 @@ static struct kunit_case fortify_test_cases[] = {
KUNIT_CASE(fortify_test_strlen),
KUNIT_CASE(fortify_test_strnlen),
KUNIT_CASE(fortify_test_strcpy),
- KUNIT_CASE(fortify_test_strncpy),
KUNIT_CASE(fortify_test_strscpy),
KUNIT_CASE(fortify_test_strcat),
KUNIT_CASE(fortify_test_strncat),
diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c
index bb847e5010eb..32e42d8c7ca1 100644
--- a/lib/tests/kunit_iov_iter.c
+++ b/lib/tests/kunit_iov_iter.c
@@ -13,6 +13,9 @@
#include <linux/uio.h>
#include <linux/bvec.h>
#include <linux/folio_queue.h>
+#include <linux/scatterlist.h>
+#include <linux/minmax.h>
+#include <linux/mman.h>
#include <kunit/test.h>
MODULE_DESCRIPTION("iov_iter testing");
@@ -37,12 +40,12 @@ static const struct kvec_test_range kvec_test_ranges[] = {
static inline u8 pattern(unsigned long x)
{
- return x & 0xff;
+ return (u8)x + (u8)(x >> 8) + (u8)(x >> 16);
}
static void iov_kunit_unmap(void *data)
{
- vunmap(data);
+ vfree(data);
}
static void *__init iov_kunit_create_buffer(struct kunit *test,
@@ -50,20 +53,37 @@ static void *__init iov_kunit_create_buffer(struct kunit *test,
size_t npages)
{
struct page **pages;
- unsigned long got;
+ unsigned long got, last;
void *buffer;
+ unsigned int i;
- pages = kunit_kcalloc(test, npages, sizeof(struct page *), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages);
+ pages = kzalloc_objs(struct page *, npages);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages);
*ppages = pages;
- got = alloc_pages_bulk(GFP_KERNEL, npages, pages);
+ got = 0;
+ while (true) {
+ last = got;
+ got = alloc_pages_bulk(GFP_KERNEL, npages, pages);
+
+ if (last == got || got == npages)
+ break;
+ }
+
if (got != npages) {
release_pages(pages, got);
+ kvfree(pages);
KUNIT_ASSERT_EQ(test, got, npages);
}
+ /* Make sure that we don't get a physically contiguous buffer. */
+ for (i = 0; i < npages / 4; ++i)
+ swap(pages[i], pages[i + npages / 2]);
buffer = vmap(pages, npages, VM_MAP | VM_MAP_PUT_PAGES, PAGE_KERNEL);
+ if (buffer == NULL) {
+ release_pages(pages, got);
+ kvfree(pages);
+ }
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
kunit_add_action_or_reset(test, iov_kunit_unmap, buffer);
@@ -263,7 +283,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
struct page **spages, **bpages;
u8 *scratch, *buffer;
size_t bufsize, npages, size, copied;
- int i, b, patt;
+ int i, patt;
bufsize = 0x100000;
npages = bufsize / PAGE_SIZE;
@@ -286,10 +306,9 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
KUNIT_EXPECT_EQ(test, iter.nr_segs, 0);
/* Build the expected image in the scratch buffer. */
- b = 0;
patt = 0;
memset(scratch, 0, bufsize);
- for (pr = bvec_test_ranges; pr->from >= 0; pr++, b++) {
+ for (pr = bvec_test_ranges; pr->from >= 0; pr++) {
u8 *p = scratch + pr->page * PAGE_SIZE;
for (i = pr->from; i < pr->to; i++)
@@ -369,9 +388,6 @@ static void iov_kunit_destroy_folioq(void *data)
for (folioq = data; folioq; folioq = next) {
next = folioq->next;
- for (int i = 0; i < folioq_nr_slots(folioq); i++)
- if (folioq_folio(folioq, i))
- folio_put(folioq_folio(folioq, i));
kfree(folioq);
}
}
@@ -1009,6 +1025,202 @@ stop:
KUNIT_SUCCEED(test);
}
+struct iov_kunit_iter_to_sg_data {
+ struct sg_table *sgt;
+ u8 *buffer, *scratch;
+ u8 __user *ubuf;
+ struct page **pages;
+ size_t npages;
+};
+
+static void __init
+iov_kunit_iter_unpin_sgt(void *data)
+{
+ struct sg_table *sgt = data;
+
+ for (unsigned int i = 0; i < sgt->nents; ++i)
+ unpin_user_page(sg_page(&sgt->sgl[i]));
+}
+
+static void __init
+iov_kunit_iter_to_sg_init(struct kunit *test, size_t bufsize, bool user,
+ struct iov_kunit_iter_to_sg_data *data)
+{
+ struct page **spages;
+ struct scatterlist *sg;
+ unsigned long uaddr;
+ size_t i;
+
+ data->npages = bufsize / PAGE_SIZE;
+ sg = kunit_kmalloc_array(test, data->npages, sizeof(*sg), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sg);
+ sg_init_table(sg, data->npages);
+ data->sgt = kunit_kzalloc(test, sizeof(*data->sgt), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data->sgt);
+ data->sgt->orig_nents = 0;
+ data->sgt->sgl = sg;
+
+ data->buffer = NULL;
+ data->ubuf = NULL;
+ if (user) {
+ uaddr = kunit_vm_mmap(test, NULL, 0, bufsize,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, 0);
+ KUNIT_ASSERT_NE(test, uaddr, 0);
+ data->ubuf = (u8 __user *)uaddr;
+ for (i = 0; i < bufsize; ++i)
+ put_user(pattern(i), data->ubuf + i);
+ } else {
+ data->buffer = iov_kunit_create_buffer(test, &data->pages,
+ data->npages);
+ for (i = 0; i < bufsize; ++i)
+ data->buffer[i] = pattern(i);
+ }
+ data->scratch = iov_kunit_create_buffer(test, &spages, data->npages);
+ memset(data->scratch, 0, bufsize);
+}
+
+static void __init
+iov_kunit_iter_to_sg_check(struct kunit *test, struct iov_iter *iter,
+ size_t bufsize,
+ struct iov_kunit_iter_to_sg_data *data)
+{
+ static const size_t tail = 16 * PAGE_SIZE;
+ size_t i;
+
+ KUNIT_ASSERT_LT(test, tail, bufsize);
+
+ if (iov_iter_extract_will_pin(iter))
+ kunit_add_action_or_reset(test, iov_kunit_iter_unpin_sgt,
+ data->sgt);
+
+ i = extract_iter_to_sg(iter, bufsize, data->sgt, 0, 0);
+ KUNIT_ASSERT_EQ(test, i, 0);
+ KUNIT_ASSERT_EQ(test, data->sgt->nents, 0);
+
+ i = extract_iter_to_sg(iter, bufsize - tail, data->sgt, 1, 0);
+ KUNIT_ASSERT_LE(test, i, bufsize - tail);
+ KUNIT_ASSERT_EQ(test, data->sgt->nents, 1);
+
+ i += extract_iter_to_sg(iter, bufsize - tail - i, data->sgt,
+ data->npages - data->sgt->nents, 0);
+ KUNIT_ASSERT_EQ(test, i, bufsize - tail);
+ KUNIT_ASSERT_LE(test, data->sgt->nents, data->npages);
+
+ i += extract_iter_to_sg(iter, tail, data->sgt,
+ data->npages - data->sgt->nents, 0);
+ KUNIT_ASSERT_EQ(test, i, bufsize);
+ KUNIT_ASSERT_LE(test, data->sgt->nents, data->npages);
+
+ sg_mark_end(&data->sgt->sgl[data->sgt->nents - 1]);
+
+ i = sg_copy_to_buffer(data->sgt->sgl, data->sgt->nents,
+ data->scratch, bufsize);
+ KUNIT_ASSERT_EQ(test, i, bufsize);
+
+ for (i = 0; i < bufsize; ++i) {
+ KUNIT_EXPECT_EQ_MSG(test, data->scratch[i], pattern(i),
+ "at i=%zx", i);
+ if (data->scratch[i] != pattern(i))
+ break;
+ }
+
+ KUNIT_EXPECT_EQ(test, i, bufsize);
+}
+
+static void __init iov_kunit_iter_to_sg_kvec(struct kunit *test)
+{
+ struct iov_kunit_iter_to_sg_data data;
+ struct iov_iter iter;
+ struct kvec kvec;
+ size_t bufsize;
+
+ bufsize = 0x200000;
+ iov_kunit_iter_to_sg_init(test, bufsize, false, &data);
+
+ kvec.iov_base = data.buffer;
+ kvec.iov_len = bufsize;
+ iov_iter_kvec(&iter, READ, &kvec, 1, bufsize);
+
+ iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data);
+}
+
+static void __init iov_kunit_iter_to_sg_bvec(struct kunit *test)
+{
+ struct iov_kunit_iter_to_sg_data data;
+ struct page *p, *can_merge = NULL;
+ size_t i, k, bufsize;
+ struct bio_vec *bvec;
+ struct iov_iter iter;
+
+ bufsize = 0x200000;
+ iov_kunit_iter_to_sg_init(test, bufsize, false, &data);
+
+ bvec = kunit_kmalloc_array(test, data.npages, sizeof(*bvec),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bvec);
+ k = 0;
+ for (i = 0; i < data.npages; ++i) {
+ p = data.pages[i];
+ if (p == can_merge)
+ bvec[k-1].bv_len += PAGE_SIZE;
+ else
+ bvec_set_page(&bvec[k++], p, PAGE_SIZE, 0);
+ can_merge = p + 1;
+ }
+ iov_iter_bvec(&iter, READ, bvec, k, bufsize);
+
+ iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data);
+}
+
+static void __init iov_kunit_iter_to_sg_folioq(struct kunit *test)
+{
+ struct iov_kunit_iter_to_sg_data data;
+ struct folio_queue *folioq;
+ struct iov_iter iter;
+ size_t bufsize;
+
+ bufsize = 0x200000;
+ iov_kunit_iter_to_sg_init(test, bufsize, false, &data);
+
+ folioq = iov_kunit_create_folioq(test);
+ iov_kunit_load_folioq(test, &iter, READ, folioq, data.pages,
+ data.npages);
+
+ iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data);
+}
+
+static void __init iov_kunit_iter_to_sg_xarray(struct kunit *test)
+{
+ struct iov_kunit_iter_to_sg_data data;
+ struct xarray *xarray;
+ struct iov_iter iter;
+ size_t bufsize;
+
+ bufsize = 0x200000;
+ iov_kunit_iter_to_sg_init(test, bufsize, false, &data);
+
+ xarray = iov_kunit_create_xarray(test);
+ iov_kunit_load_xarray(test, &iter, READ, xarray, data.pages,
+ data.npages);
+
+ iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data);
+}
+
+static void __init iov_kunit_iter_to_sg_ubuf(struct kunit *test)
+{
+ struct iov_kunit_iter_to_sg_data data;
+ struct iov_iter iter;
+ size_t bufsize;
+
+ bufsize = 0x200000;
+ iov_kunit_iter_to_sg_init(test, bufsize, true, &data);
+
+ iov_iter_ubuf(&iter, READ, data.ubuf, bufsize);
+
+ iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data);
+}
+
static struct kunit_case __refdata iov_kunit_cases[] = {
KUNIT_CASE(iov_kunit_copy_to_kvec),
KUNIT_CASE(iov_kunit_copy_from_kvec),
@@ -1022,6 +1234,11 @@ static struct kunit_case __refdata iov_kunit_cases[] = {
KUNIT_CASE(iov_kunit_extract_pages_bvec),
KUNIT_CASE(iov_kunit_extract_pages_folioq),
KUNIT_CASE(iov_kunit_extract_pages_xarray),
+ KUNIT_CASE(iov_kunit_iter_to_sg_kvec),
+ KUNIT_CASE(iov_kunit_iter_to_sg_bvec),
+ KUNIT_CASE(iov_kunit_iter_to_sg_folioq),
+ KUNIT_CASE(iov_kunit_iter_to_sg_xarray),
+ KUNIT_CASE(iov_kunit_iter_to_sg_ubuf),
{}
};
diff --git a/lib/tests/liveupdate.c b/lib/tests/liveupdate.c
index 496d6ef91a30..4c08a7c6fb78 100644
--- a/lib/tests/liveupdate.c
+++ b/lib/tests/liveupdate.c
@@ -105,6 +105,9 @@ static void liveupdate_test_init(void)
pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
flb->compatible, ERR_PTR(err));
}
+
+ if (!err)
+ liveupdate_flb_put_incoming(flb);
}
initialized = true;
}
@@ -135,24 +138,6 @@ void liveupdate_test_register(struct liveupdate_file_handler *fh)
TEST_NFLBS, fh->compatible);
}
-void liveupdate_test_unregister(struct liveupdate_file_handler *fh)
-{
- int err, i;
-
- for (i = 0; i < TEST_NFLBS; i++) {
- struct liveupdate_flb *flb = &test_flbs[i];
-
- err = liveupdate_unregister_flb(fh, flb);
- if (err) {
- pr_err("Failed to unregister %s %pe\n",
- flb->compatible, ERR_PTR(err));
- }
- }
-
- pr_info("Unregistered %d FLBs from file handler: [%s]\n",
- TEST_NFLBS, fh->compatible);
-}
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
MODULE_DESCRIPTION("In-kernel test for LUO mechanism");
diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c
index f6f21b445ece..eccf041ebd56 100644
--- a/lib/tests/printf_kunit.c
+++ b/lib/tests/printf_kunit.c
@@ -17,6 +17,7 @@
#include <linux/dcache.h>
#include <linux/socket.h>
#include <linux/in.h>
+#include <linux/in6.h>
#include <linux/gfp.h>
#include <linux/mm.h>
@@ -318,7 +319,27 @@ symbol_ptr(struct kunit *kunittest)
static void
kernel_ptr(struct kunit *kunittest)
{
- /* We can't test this without access to kptr_restrict. */
+ switch (kptr_restrict) {
+ case 0:
+ if (no_hash_pointers) {
+ test(PTR_STR, "%pK", PTR);
+ } else {
+ char buf[PLAIN_BUF_SIZE];
+
+ plain_hash_to_buffer(kunittest, PTR, buf, PLAIN_BUF_SIZE);
+ /* %pK behaves the same as hashing */
+ test(buf, "%pK", PTR);
+ }
+ break;
+ case 1:
+ /* The KUnit kthread has all capabilities, including CAP_SYSLOG */
+ test(PTR_STR, "%pK", PTR);
+ break;
+ case 2:
+ default:
+ test(ZEROS "00000000", "%pK", PTR);
+ break;
+ }
}
static void
@@ -414,8 +435,10 @@ mac(struct kunit *kunittest)
test("2d:48:d6:fc:7a:05", "%pM", addr);
test("05:7a:fc:d6:48:2d", "%pMR", addr);
+ test("05:7A:FC:D6:48:2D", "%pMRU", addr);
test("2d-48-d6-fc-7a-05", "%pMF", addr);
test("2d48d6fc7a05", "%pm", addr);
+ test("2D48D6FC7A05", "%pmU", addr);
test("057afcd6482d", "%pmR", addr);
}
@@ -437,6 +460,27 @@ ip4(struct kunit *kunittest)
static void
ip6(struct kunit *kunittest)
{
+ const struct in6_addr addr = {
+ .s6_addr = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+ 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }
+ };
+ const struct in6_addr single_zero = {
+ .s6_addr = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04,
+ 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }
+ };
+ struct sockaddr_in6 sa = {
+ .sin6_family = AF_INET6,
+ .sin6_port = cpu_to_be16(12345),
+ .sin6_addr = addr,
+ };
+
+ test("00010002000300040005000600070008|0001:0002:0003:0004:0005:0006:0007:0008",
+ "%pi6|%pI6", &addr, &addr);
+ test("00010002000300040005000600070008|0001:0002:0003:0004:0005:0006:0007:0008",
+ "%piS|%pIS", &sa, &sa);
+ test("1:2:3:4:5:6:7:8", "%pI6c", &addr);
+ test("1:0:3:4:5:6:7:8", "%pI6c", &single_zero);
+ test("[1:2:3:4:5:6:7:8]:12345", "%pISpc", &sa);
}
static void
diff --git a/lib/tests/random32_kunit.c b/lib/tests/random32_kunit.c
new file mode 100644
index 000000000000..0b4af2b09c01
--- /dev/null
+++ b/lib/tests/random32_kunit.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for random32 functions.
+ */
+
+#include <linux/prandom.h>
+#include <kunit/test.h>
+
+/* prandom_warmup() is static in lib/random32.c; exposed for testing only. */
+void prandom_warmup(struct rnd_state *state);
+
+static const struct prandom_test1 {
+ u32 seed;
+ u32 result;
+} test1[] = {
+ { 1U, 3484351685U },
+ { 2U, 2623130059U },
+ { 3U, 3125133893U },
+ { 4U, 984847254U },
+};
+
+static const struct prandom_test2 {
+ u32 seed;
+ u32 iteration;
+ u32 result;
+} test2[] = {
+ /* Test cases against taus113 from GSL library. */
+ { 931557656U, 959U, 2975593782U },
+ { 1339693295U, 876U, 3887776532U },
+ { 1545556285U, 961U, 1615538833U },
+ { 601730776U, 723U, 1776162651U },
+ { 1027516047U, 687U, 511983079U },
+ { 416526298U, 700U, 916156552U },
+ { 1395522032U, 652U, 2222063676U },
+ { 366221443U, 617U, 2992857763U },
+ { 1539836965U, 714U, 3783265725U },
+ { 556206671U, 994U, 799626459U },
+ { 684907218U, 799U, 367789491U },
+ { 2121230701U, 931U, 2115467001U },
+ { 1668516451U, 644U, 3620590685U },
+ { 768046066U, 883U, 2034077390U },
+ { 1989159136U, 833U, 1195767305U },
+ { 536585145U, 996U, 3577259204U },
+ { 1008129373U, 642U, 1478080776U },
+ { 1740775604U, 939U, 1264980372U },
+ { 1967883163U, 508U, 10734624U },
+ { 1923019697U, 730U, 3821419629U },
+ { 442079932U, 560U, 3440032343U },
+ { 1961302714U, 845U, 841962572U },
+ { 2030205964U, 962U, 1325144227U },
+ { 1160407529U, 507U, 240940858U },
+ { 635482502U, 779U, 4200489746U },
+ { 1252788931U, 699U, 867195434U },
+ { 1961817131U, 719U, 668237657U },
+ { 1071468216U, 983U, 917876630U },
+ { 1281848367U, 932U, 1003100039U },
+ { 582537119U, 780U, 1127273778U },
+ { 1973672777U, 853U, 1071368872U },
+ { 1896756996U, 762U, 1127851055U },
+ { 847917054U, 500U, 1717499075U },
+ { 1240520510U, 951U, 2849576657U },
+ { 1685071682U, 567U, 1961810396U },
+ { 1516232129U, 557U, 3173877U },
+ { 1208118903U, 612U, 1613145022U },
+ { 1817269927U, 693U, 4279122573U },
+ { 1510091701U, 717U, 638191229U },
+ { 365916850U, 807U, 600424314U },
+ { 399324359U, 702U, 1803598116U },
+ { 1318480274U, 779U, 2074237022U },
+ { 697758115U, 840U, 1483639402U },
+ { 1696507773U, 840U, 577415447U },
+ { 2081979121U, 981U, 3041486449U },
+ { 955646687U, 742U, 3846494357U },
+ { 1250683506U, 749U, 836419859U },
+ { 595003102U, 534U, 366794109U },
+ { 47485338U, 558U, 3521120834U },
+ { 619433479U, 610U, 3991783875U },
+ { 704096520U, 518U, 4139493852U },
+ { 1712224984U, 606U, 2393312003U },
+ { 1318233152U, 922U, 3880361134U },
+ { 855572992U, 761U, 1472974787U },
+ { 64721421U, 703U, 683860550U },
+ { 678931758U, 840U, 380616043U },
+ { 692711973U, 778U, 1382361947U },
+ { 677703619U, 530U, 2826914161U },
+ { 92393223U, 586U, 1522128471U },
+ { 1222592920U, 743U, 3466726667U },
+ { 358288986U, 695U, 1091956998U },
+ { 1935056945U, 958U, 514864477U },
+ { 735675993U, 990U, 1294239989U },
+ { 1560089402U, 897U, 2238551287U },
+ { 70616361U, 829U, 22483098U },
+ { 368234700U, 731U, 2913875084U },
+ { 20221190U, 879U, 1564152970U },
+ { 539444654U, 682U, 1835141259U },
+ { 1314987297U, 840U, 1801114136U },
+ { 2019295544U, 645U, 3286438930U },
+ { 469023838U, 716U, 1637918202U },
+ { 1843754496U, 653U, 2562092152U },
+ { 400672036U, 809U, 4264212785U },
+ { 404722249U, 965U, 2704116999U },
+ { 600702209U, 758U, 584979986U },
+ { 519953954U, 667U, 2574436237U },
+ { 1658071126U, 694U, 2214569490U },
+ { 420480037U, 749U, 3430010866U },
+ { 690103647U, 969U, 3700758083U },
+ { 1029424799U, 937U, 3787746841U },
+ { 2012608669U, 506U, 3362628973U },
+ { 1535432887U, 998U, 42610943U },
+ { 1330635533U, 857U, 3040806504U },
+ { 1223800550U, 539U, 3954229517U },
+ { 1322411537U, 680U, 3223250324U },
+ { 1877847898U, 945U, 2915147143U },
+ { 1646356099U, 874U, 965988280U },
+ { 805687536U, 744U, 4032277920U },
+ { 1948093210U, 633U, 1346597684U },
+ { 392609744U, 783U, 1636083295U },
+ { 690241304U, 770U, 1201031298U },
+ { 1360302965U, 696U, 1665394461U },
+ { 1220090946U, 780U, 1316922812U },
+ { 447092251U, 500U, 3438743375U },
+ { 1613868791U, 592U, 828546883U },
+ { 523430951U, 548U, 2552392304U },
+ { 726692899U, 810U, 1656872867U },
+ { 1364340021U, 836U, 3710513486U },
+ { 1986257729U, 931U, 935013962U },
+ { 407983964U, 921U, 728767059U },
+};
+
+static void prandom_state_test_seed(struct rnd_state *state, u32 seed)
+{
+#define LCG(x) ((x) * 69069U) /* super-duper LCG */
+ state->s1 = __seed(LCG(seed), 2U);
+ state->s2 = __seed(LCG(state->s1), 8U);
+ state->s3 = __seed(LCG(state->s2), 16U);
+ state->s4 = __seed(LCG(state->s3), 128U);
+}
+
+static void test_prandom_seed_boundary(struct kunit *test)
+{
+ int i;
+ struct rnd_state state;
+
+ for (i = 0; i < ARRAY_SIZE(test1); i++) {
+ prandom_state_test_seed(&state, test1[i].seed);
+ prandom_warmup(&state);
+ KUNIT_EXPECT_EQ(test, test1[i].result, prandom_u32_state(&state));
+ }
+}
+
+static void test_prandom_taus113(struct kunit *test)
+{
+ int i, j;
+ struct rnd_state state;
+
+ for (i = 0; i < ARRAY_SIZE(test2); i++) {
+ prandom_state_test_seed(&state, test2[i].seed);
+ prandom_warmup(&state);
+
+ for (j = 0; j < test2[i].iteration - 1; j++)
+ prandom_u32_state(&state);
+
+ KUNIT_EXPECT_EQ(test, test2[i].result, prandom_u32_state(&state));
+ }
+}
+
+static struct kunit_case prandom_test_cases[] = {
+ KUNIT_CASE(test_prandom_seed_boundary),
+ KUNIT_CASE(test_prandom_taus113),
+ {}
+};
+
+static struct kunit_suite prandom_test_suite = {
+ .name = "prandom",
+ .test_cases = prandom_test_cases,
+};
+
+kunit_test_suite(prandom_test_suite);
+
+MODULE_DESCRIPTION("KUnit test for prandom");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
diff --git a/lib/tests/seq_buf_kunit.c b/lib/tests/seq_buf_kunit.c
index 8a01579a978e..eb466386bbef 100644
--- a/lib/tests/seq_buf_kunit.c
+++ b/lib/tests/seq_buf_kunit.c
@@ -184,6 +184,38 @@ static void seq_buf_get_buf_commit_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
}
+static void seq_buf_putmem_hex_test(struct kunit *test)
+{
+ DECLARE_SEQ_BUF(s, 24);
+ const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+#ifdef __BIG_ENDIAN
+ const char *expected = "0001020304050607 0809 ";
+#else
+ const char *expected = "0706050403020100 0908 ";
+#endif
+
+ KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), 0);
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), strlen(expected));
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
+}
+
+static void seq_buf_putmem_hex_overflow_test(struct kunit *test)
+{
+ DECLARE_SEQ_BUF(s, 20);
+ const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+#ifdef __BIG_ENDIAN
+ const char *expected = "0001020304050607 ";
+#else
+ const char *expected = "0706050403020100 ";
+#endif
+
+ KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), -1);
+ KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 20);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
+}
+
static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_init_test),
KUNIT_CASE(seq_buf_declare_test),
@@ -194,6 +226,8 @@ static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_printf_test),
KUNIT_CASE(seq_buf_printf_overflow_test),
KUNIT_CASE(seq_buf_get_buf_commit_test),
+ KUNIT_CASE(seq_buf_putmem_hex_test),
+ KUNIT_CASE(seq_buf_putmem_hex_overflow_test),
{}
};
diff --git a/lib/tests/shdi3_kunit.c b/lib/tests/shdi3_kunit.c
new file mode 100644
index 000000000000..44f65e66512b
--- /dev/null
+++ b/lib/tests/shdi3_kunit.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR Apache-2.0
+/*
+ * Test cases for __ashldi3(), __ashrdi3(), and __lshrdi3().
+ */
+
+#include <linux/array_size.h>
+#include <linux/module.h>
+#include <linux/libgcc.h>
+#include <kunit/test.h>
+
+struct shdi3_test_entry {
+ long long input;
+ int shift;
+ long long result;
+};
+
+static const struct shdi3_test_entry ashldi3_testdata[] = {
+ /* https://github.com/llvm/llvm-project/compiler-rt/test/builtins/Unit/ashldi3_test.c */
+ { 0x0123456789ABCDEFLL, 0, 0x123456789ABCDEFLL },
+ { 0x0123456789ABCDEFLL, 1, 0x2468ACF13579BDELL },
+ { 0x0123456789ABCDEFLL, 2, 0x48D159E26AF37BCLL },
+ { 0x0123456789ABCDEFLL, 3, 0x91A2B3C4D5E6F78LL },
+ { 0x0123456789ABCDEFLL, 4, 0x123456789ABCDEF0LL },
+ { 0x0123456789ABCDEFLL, 28, 0x789ABCDEF0000000LL },
+ { 0x0123456789ABCDEFLL, 29, 0xF13579BDE0000000LL },
+ { 0x0123456789ABCDEFLL, 30, 0xE26AF37BC0000000LL },
+ { 0x0123456789ABCDEFLL, 31, 0xC4D5E6F780000000LL },
+ { 0x0123456789ABCDEFLL, 32, 0x89ABCDEF00000000LL },
+ { 0x0123456789ABCDEFLL, 33, 0x13579BDE00000000LL },
+ { 0x0123456789ABCDEFLL, 34, 0x26AF37BC00000000LL },
+ { 0x0123456789ABCDEFLL, 35, 0x4D5E6F7800000000LL },
+ { 0x0123456789ABCDEFLL, 36, 0x9ABCDEF000000000LL },
+ { 0x0123456789ABCDEFLL, 60, 0xF000000000000000LL },
+ { 0x0123456789ABCDEFLL, 61, 0xE000000000000000LL },
+ { 0x0123456789ABCDEFLL, 62, 0xC000000000000000LL },
+ { 0x0123456789ABCDEFLL, 63, 0x8000000000000000LL },
+};
+
+static void shdi3_test_ashldi3(struct kunit *test)
+{
+ const struct shdi3_test_entry *e;
+ long long ret;
+
+ for (e = ashldi3_testdata;
+ e < ashldi3_testdata + ARRAY_SIZE(ashldi3_testdata); e++) {
+ ret = __ashldi3(e->input, e->shift);
+ KUNIT_EXPECT_EQ_MSG(test, ret, e->result,
+ " when evaluating __ashldi3(%lld, %d)",
+ e->input, e->shift);
+ }
+}
+
+static const struct shdi3_test_entry ashrdi3_testdata[] = {
+ /* https://github.com/llvm/llvm-project/compiler-rt/test/builtins/Unit/ashrdi3_test.c */
+ { 0x0123456789ABCDEFLL, 0, 0x123456789ABCDEFLL },
+ { 0x0123456789ABCDEFLL, 1, 0x91A2B3C4D5E6F7LL },
+ { 0x0123456789ABCDEFLL, 2, 0x48D159E26AF37BLL },
+ { 0x0123456789ABCDEFLL, 3, 0x2468ACF13579BDLL },
+ { 0x0123456789ABCDEFLL, 4, 0x123456789ABCDELL },
+ { 0x0123456789ABCDEFLL, 28, 0x12345678LL },
+ { 0x0123456789ABCDEFLL, 29, 0x91A2B3CLL },
+ { 0x0123456789ABCDEFLL, 30, 0x48D159ELL },
+ { 0x0123456789ABCDEFLL, 31, 0x2468ACFLL },
+ { 0x0123456789ABCDEFLL, 32, 0x1234567LL },
+ { 0x0123456789ABCDEFLL, 33, 0x91A2B3LL },
+ { 0x0123456789ABCDEFLL, 34, 0x48D159LL },
+ { 0x0123456789ABCDEFLL, 35, 0x2468ACLL },
+ { 0x0123456789ABCDEFLL, 36, 0x123456LL },
+ { 0x0123456789ABCDEFLL, 60, 0 },
+ { 0x0123456789ABCDEFLL, 61, 0 },
+ { 0x0123456789ABCDEFLL, 62, 0 },
+ { 0x0123456789ABCDEFLL, 63, 0 },
+ { 0xFEDCBA9876543210LL, 0, 0xFEDCBA9876543210LL },
+ { 0xFEDCBA9876543210LL, 1, 0xFF6E5D4C3B2A1908LL },
+ { 0xFEDCBA9876543210LL, 2, 0xFFB72EA61D950C84LL },
+ { 0xFEDCBA9876543210LL, 3, 0xFFDB97530ECA8642LL },
+ { 0xFEDCBA9876543210LL, 4, 0xFFEDCBA987654321LL },
+ { 0xFEDCBA9876543210LL, 28, 0xFFFFFFFFEDCBA987LL },
+ { 0xFEDCBA9876543210LL, 29, 0xFFFFFFFFF6E5D4C3LL },
+ { 0xFEDCBA9876543210LL, 30, 0xFFFFFFFFFB72EA61LL },
+ { 0xFEDCBA9876543210LL, 31, 0xFFFFFFFFFDB97530LL },
+ { 0xFEDCBA9876543210LL, 32, 0xFFFFFFFFFEDCBA98LL },
+ { 0xFEDCBA9876543210LL, 33, 0xFFFFFFFFFF6E5D4CLL },
+ { 0xFEDCBA9876543210LL, 34, 0xFFFFFFFFFFB72EA6LL },
+ { 0xFEDCBA9876543210LL, 35, 0xFFFFFFFFFFDB9753LL },
+ { 0xFEDCBA9876543210LL, 36, 0xFFFFFFFFFFEDCBA9LL },
+ { 0xAEDCBA9876543210LL, 60, 0xFFFFFFFFFFFFFFFALL },
+ { 0xAEDCBA9876543210LL, 61, 0xFFFFFFFFFFFFFFFDLL },
+ { 0xAEDCBA9876543210LL, 62, 0xFFFFFFFFFFFFFFFELL },
+ { 0xAEDCBA9876543210LL, 63, 0xFFFFFFFFFFFFFFFFLL },
+};
+
+static void shdi3_test_ashrdi3(struct kunit *test)
+{
+ const struct shdi3_test_entry *e;
+ long long ret;
+
+ for (e = ashrdi3_testdata;
+ e < ashrdi3_testdata + ARRAY_SIZE(ashrdi3_testdata); e++) {
+ ret = __ashrdi3(e->input, e->shift);
+ KUNIT_EXPECT_EQ_MSG(test, ret, e->result,
+ " when evaluating __ashrdi3(%lld, %d)",
+ e->input, e->shift);
+ }
+}
+
+static const struct shdi3_test_entry lshrdi3_testdata[] = {
+ /* https://github.com/llvm/llvm-project/compiler-rt/test/builtins/Unit/lshrdi3_test.c */
+ { 0x0123456789ABCDEFLL, 0, 0x123456789ABCDEFLL },
+ { 0x0123456789ABCDEFLL, 1, 0x91A2B3C4D5E6F7LL },
+ { 0x0123456789ABCDEFLL, 2, 0x48D159E26AF37BLL },
+ { 0x0123456789ABCDEFLL, 3, 0x2468ACF13579BDLL },
+ { 0x0123456789ABCDEFLL, 4, 0x123456789ABCDELL },
+ { 0x0123456789ABCDEFLL, 28, 0x12345678LL },
+ { 0x0123456789ABCDEFLL, 29, 0x91A2B3CLL },
+ { 0x0123456789ABCDEFLL, 30, 0x48D159ELL },
+ { 0x0123456789ABCDEFLL, 31, 0x2468ACFLL },
+ { 0x0123456789ABCDEFLL, 32, 0x1234567LL },
+ { 0x0123456789ABCDEFLL, 33, 0x91A2B3LL },
+ { 0x0123456789ABCDEFLL, 34, 0x48D159LL },
+ { 0x0123456789ABCDEFLL, 35, 0x2468ACLL },
+ { 0x0123456789ABCDEFLL, 36, 0x123456LL },
+ { 0x0123456789ABCDEFLL, 60, 0 },
+ { 0x0123456789ABCDEFLL, 61, 0 },
+ { 0x0123456789ABCDEFLL, 62, 0 },
+ { 0x0123456789ABCDEFLL, 63, 0 },
+ { 0xFEDCBA9876543210LL, 0, 0xFEDCBA9876543210LL },
+ { 0xFEDCBA9876543210LL, 1, 0x7F6E5D4C3B2A1908LL },
+ { 0xFEDCBA9876543210LL, 2, 0x3FB72EA61D950C84LL },
+ { 0xFEDCBA9876543210LL, 3, 0x1FDB97530ECA8642LL },
+ { 0xFEDCBA9876543210LL, 4, 0xFEDCBA987654321LL },
+ { 0xFEDCBA9876543210LL, 28, 0xFEDCBA987LL },
+ { 0xFEDCBA9876543210LL, 29, 0x7F6E5D4C3LL },
+ { 0xFEDCBA9876543210LL, 30, 0x3FB72EA61LL },
+ { 0xFEDCBA9876543210LL, 31, 0x1FDB97530LL },
+ { 0xFEDCBA9876543210LL, 32, 0xFEDCBA98LL },
+ { 0xFEDCBA9876543210LL, 33, 0x7F6E5D4CLL },
+ { 0xFEDCBA9876543210LL, 34, 0x3FB72EA6LL },
+ { 0xFEDCBA9876543210LL, 35, 0x1FDB9753LL },
+ { 0xFEDCBA9876543210LL, 36, 0xFEDCBA9LL },
+ { 0xAEDCBA9876543210LL, 60, 0xALL },
+ { 0xAEDCBA9876543210LL, 61, 0x5LL },
+ { 0xAEDCBA9876543210LL, 62, 0x2LL },
+ { 0xAEDCBA9876543210LL, 63, 0x1LL },
+};
+
+static void shdi3_test_lshrdi3(struct kunit *test)
+{
+ const struct shdi3_test_entry *e;
+ long long ret;
+
+ for (e = lshrdi3_testdata;
+ e < lshrdi3_testdata + ARRAY_SIZE(lshrdi3_testdata); e++) {
+ ret = __lshrdi3(e->input, e->shift);
+ KUNIT_EXPECT_EQ_MSG(test, ret, e->result,
+ " when evaluating __lshrdi3(%lld, %d)",
+ e->input, e->shift);
+ }
+}
+
+static struct kunit_case shdi3_test_cases[] = {
+ KUNIT_CASE(shdi3_test_ashldi3),
+ KUNIT_CASE(shdi3_test_ashrdi3),
+ KUNIT_CASE(shdi3_test_lshrdi3),
+ {}
+};
+
+static struct kunit_suite shdi3_test_suite = {
+ .name = "shdi3",
+ .test_cases = shdi3_test_cases,
+};
+kunit_test_suite(shdi3_test_suite);
+
+MODULE_DESCRIPTION("Test cases for __ashldi3(), __ashrdi3(), and __lshrdi3()");
+MODULE_LICENSE("GPL");
diff --git a/lib/tests/slub_kunit.c b/lib/tests/slub_kunit.c
index 848b682a2d70..e3b63f0338d5 100644
--- a/lib/tests/slub_kunit.c
+++ b/lib/tests/slub_kunit.c
@@ -7,6 +7,8 @@
#include <linux/kernel.h>
#include <linux/rcupdate.h>
#include <linux/delay.h>
+#include <linux/perf_event.h>
+#include <linux/kprobes.h>
#include "../mm/slab.h"
static struct kunit_resource resource;
@@ -160,7 +162,10 @@ static void test_kmalloc_redzone_access(struct kunit *test)
}
struct test_kfree_rcu_struct {
- struct rcu_head rcu;
+ union {
+ struct rcu_head rcu;
+ struct kvfree_rcu_head kvrcu;
+ };
};
static void test_kfree_rcu(struct kunit *test)
@@ -291,6 +296,175 @@ static void test_krealloc_redzone_zeroing(struct kunit *test)
kmem_cache_destroy(s);
}
+#if defined(CONFIG_PERF_EVENTS) || (defined(CONFIG_KPROBES) && defined(CONFIG_SMP))
+#define NR_ITERATIONS 1000
+#define NR_OBJECTS 1000
+static struct test_kfree_rcu_struct *objects[NR_OBJECTS];
+
+struct test_nolock_context {
+ struct kunit *test;
+ int callback_count;
+ int alloc_ok;
+ int alloc_fail;
+#ifdef CONFIG_PERF_EVENTS
+ struct perf_event *event;
+#endif
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+ struct kprobe kprobe;
+#endif
+};
+
+static void test_kmalloc_and_friends(void)
+{
+ int i, j;
+ bool can_use_kfree_rcu = !IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST);
+
+ for (i = 0; i < NR_ITERATIONS; i++) {
+ for (j = 0; j < NR_OBJECTS; j++) {
+ gfp_t gfp = (i & 1) ? GFP_KERNEL : GFP_KERNEL_ACCOUNT;
+
+ objects[j] = kmalloc_obj(*objects[j], gfp);
+ if (!objects[j]) {
+ j--;
+ while (j >= 0)
+ kfree(objects[j--]);
+ return;
+ }
+ }
+
+ for (j = 0; j < NR_OBJECTS; j++) {
+ if (can_use_kfree_rcu && (i & 2))
+ kfree_rcu(objects[j], rcu);
+ else
+ kfree(objects[j]);
+ }
+ }
+}
+
+static void test_nolock(struct test_nolock_context *ctx)
+{
+ struct test_kfree_rcu_struct *objp;
+ gfp_t gfp;
+ bool can_use_kfree_rcu = !IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST);
+
+ /* __GFP_ACCOUNT to test kmalloc_nolock() in alloc_slab_obj_exts() */
+ gfp = (ctx->callback_count & 1) ? 0 : __GFP_ACCOUNT;
+ objp = kmalloc_nolock(sizeof(*objp), gfp, NUMA_NO_NODE);
+
+ if (objp)
+ ctx->alloc_ok++;
+ else
+ ctx->alloc_fail++;
+
+ if (can_use_kfree_rcu && (ctx->callback_count & 2))
+ kfree_rcu_nolock(objp, kvrcu);
+ else
+ kfree_nolock(objp);
+
+ ctx->callback_count++;
+}
+#endif
+
+#ifdef CONFIG_PERF_EVENTS
+static struct perf_event_attr hw_attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .size = sizeof(struct perf_event_attr),
+ .pinned = 1,
+ .disabled = 1,
+ .freq = 1,
+ .sample_freq = 100000,
+};
+
+static void overflow_handler_test_nolock(struct perf_event *event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ struct test_nolock_context *ctx = event->overflow_handler_context;
+
+ test_nolock(ctx);
+}
+
+static bool enable_perf_events(struct test_nolock_context *ctx)
+{
+ struct perf_event *event;
+
+ event = perf_event_create_kernel_counter(&hw_attr, -1, current,
+ overflow_handler_test_nolock,
+ ctx);
+
+ if (IS_ERR(event))
+ return false;
+
+ ctx->event = event;
+ perf_event_enable(ctx->event);
+ return true;
+}
+
+static void disable_perf_events(struct test_nolock_context *ctx)
+{
+ kunit_info(ctx->test, "HW perf events: callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
+ ctx->callback_count, ctx->alloc_ok, ctx->alloc_fail);
+
+ perf_event_disable(ctx->event);
+ perf_event_release_kernel(ctx->event);
+}
+
+static void test_kmalloc_nolock_and_friends_perf(struct kunit *test)
+{
+ struct test_nolock_context ctx = { .test = test };
+
+ if (!enable_perf_events(&ctx))
+ kunit_skip(test, "Failed to enable perf event, skipping");
+
+ test_kmalloc_and_friends();
+
+ disable_perf_events(&ctx);
+ KUNIT_EXPECT_EQ(test, 0, slab_errors);
+}
+#endif
+
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+static int slab_kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct test_nolock_context *ctx;
+
+ ctx = container_of(p, struct test_nolock_context, kprobe);
+ test_nolock(ctx);
+ return 0;
+}
+
+static bool register_slab_kprobes(struct test_nolock_context *ctx)
+{
+ ctx->kprobe.symbol_name = "slab_attach_kprobe_locked";
+ ctx->kprobe.pre_handler = slab_kprobe_pre_handler;
+
+ if (register_kprobe(&ctx->kprobe))
+ return false;
+ return true;
+}
+
+static void unregister_slab_kprobes(struct test_nolock_context *ctx)
+{
+ kunit_info(ctx->test, "kprobes: callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
+ ctx->callback_count, ctx->alloc_ok, ctx->alloc_fail);
+ unregister_kprobe(&ctx->kprobe);
+}
+
+static void test_kmalloc_nolock_and_friends_kprobe(struct kunit *test)
+{
+ struct test_nolock_context ctx = { .test = test };
+
+ if (!register_slab_kprobes(&ctx))
+ kunit_skip(test, "Failed to register kprobe, skipping");
+
+ test_kmalloc_and_friends();
+
+ unregister_slab_kprobes(&ctx);
+ KUNIT_EXPECT_EQ(test, 0, slab_errors);
+}
+#endif
+
static int test_init(struct kunit *test)
{
slab_errors = 0;
@@ -315,6 +489,12 @@ static struct kunit_case test_cases[] = {
KUNIT_CASE(test_kfree_rcu_wq_destroy),
KUNIT_CASE(test_leak_destroy),
KUNIT_CASE(test_krealloc_redzone_zeroing),
+#ifdef CONFIG_PERF_EVENTS
+ KUNIT_CASE_SLOW(test_kmalloc_nolock_and_friends_perf),
+#endif
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+ KUNIT_CASE_SLOW(test_kmalloc_nolock_and_friends_kprobe),
+#endif
{}
};
diff --git a/lib/tests/string_helpers_kunit.c b/lib/tests/string_helpers_kunit.c
index c853046183d2..9fbe91079c7e 100644
--- a/lib/tests/string_helpers_kunit.c
+++ b/lib/tests/string_helpers_kunit.c
@@ -5,11 +5,16 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <kunit/test.h>
+
#include <linux/array_size.h>
-#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/limits.h>
+#include <linux/module.h>
#include <linux/random.h>
-#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sprintf.h>
#include <linux/string_helpers.h>
+#include <linux/types.h>
static void test_string_check_buf(struct kunit *test,
const char *name, unsigned int flags,
@@ -601,6 +606,11 @@ static void test_unescape(struct kunit *test)
test_string_unescape(test, "unescape", i, false);
test_string_unescape(test, "unescape inplace",
get_random_u32_below(UNESCAPE_ALL_MASK + 1), true);
+}
+
+static void test_escape(struct kunit *test)
+{
+ unsigned int i;
/* Without dictionary */
for (i = 0; i < ESCAPE_ALL_MASK + 1; i++)
@@ -615,6 +625,7 @@ static struct kunit_case string_helpers_test_cases[] = {
KUNIT_CASE(test_get_size),
KUNIT_CASE(test_upper_lower),
KUNIT_CASE(test_unescape),
+ KUNIT_CASE(test_escape),
{}
};
diff --git a/lib/tests/string_kunit.c b/lib/tests/string_kunit.c
index f9a8e557ba77..0819ace5b027 100644
--- a/lib/tests/string_kunit.c
+++ b/lib/tests/string_kunit.c
@@ -6,10 +6,18 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <kunit/test.h>
+#include <linux/ktime.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/prandom.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/time64.h>
+#include <linux/units.h>
+#include <linux/vmalloc.h>
#define STRCMP_LARGE_BUF_LEN 2048
#define STRCMP_CHANGE_POINT 1337
@@ -17,6 +25,12 @@
#define STRCMP_TEST_EXPECT_LOWER(test, fn, ...) KUNIT_EXPECT_LT(test, fn(__VA_ARGS__), 0)
#define STRCMP_TEST_EXPECT_GREATER(test, fn, ...) KUNIT_EXPECT_GT(test, fn(__VA_ARGS__), 0)
+#define STRING_TEST_MAX_LEN 128
+#define STRING_TEST_MAX_OFFSET 16
+
+#define STRING_BENCH_SEED 888
+#define STRING_BENCH_WORKLOAD (1 * MEGA)
+
static void string_test_memset16(struct kunit *test)
{
unsigned i, j, k;
@@ -104,6 +118,64 @@ static void string_test_memset64(struct kunit *test)
}
}
+static void string_test_strlen(struct kunit *test)
+{
+ size_t buf_size;
+ char *buf, *s;
+
+ buf_size = PAGE_ALIGN(STRING_TEST_MAX_LEN + STRING_TEST_MAX_OFFSET + 1);
+ buf = vmalloc(buf_size);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+
+ memset(buf, 'A', buf_size);
+
+ for (size_t offset = 0; offset < STRING_TEST_MAX_OFFSET; offset++) {
+ for (size_t len = 0; len <= STRING_TEST_MAX_LEN; len++) {
+ s = buf + buf_size - 1 - offset - len;
+ s[len] = '\0';
+ KUNIT_EXPECT_EQ_MSG(test, strlen(s), len,
+ "offset:%zu len:%zu", offset, len);
+ s[len] = 'A';
+ }
+ }
+
+ vfree(buf);
+}
+
+static void string_test_strnlen(struct kunit *test)
+{
+ size_t buf_size;
+ char *buf, *s;
+
+ buf_size = PAGE_ALIGN(STRING_TEST_MAX_LEN + STRING_TEST_MAX_OFFSET + 1);
+ buf = vmalloc(buf_size);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+
+ memset(buf, 'A', buf_size);
+
+ for (size_t offset = 0; offset < STRING_TEST_MAX_OFFSET; offset++) {
+ for (size_t len = 0; len <= STRING_TEST_MAX_LEN; len++) {
+ s = buf + buf_size - 1 - offset - len;
+ s[len] = '\0';
+
+ if (len > 0)
+ KUNIT_EXPECT_EQ(test, strnlen(s, len - 1), len - 1);
+ if (len > 1)
+ KUNIT_EXPECT_EQ(test, strnlen(s, len - 2), len - 2);
+
+ KUNIT_EXPECT_EQ(test, strnlen(s, len), len);
+
+ KUNIT_EXPECT_EQ(test, strnlen(s, len + 1), len);
+ KUNIT_EXPECT_EQ(test, strnlen(s, len + 2), len);
+ KUNIT_EXPECT_EQ(test, strnlen(s, len + 10), len);
+
+ s[len] = 'A';
+ }
+ }
+
+ vfree(buf);
+}
+
static void string_test_strchr(struct kunit *test)
{
const char *test_string = "abcdefghijkl";
@@ -127,6 +199,36 @@ static void string_test_strchr(struct kunit *test)
KUNIT_ASSERT_NULL(test, result);
}
+static void string_test_strrchr(struct kunit *test)
+{
+ size_t buf_size;
+ char *buf, *s;
+
+ buf_size = PAGE_ALIGN(STRING_TEST_MAX_LEN + STRING_TEST_MAX_OFFSET + 1);
+ buf = vmalloc(buf_size);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+
+ memset(buf, 'A', buf_size);
+
+ for (size_t offset = 0; offset < STRING_TEST_MAX_OFFSET; offset++) {
+ for (size_t len = 0; len <= STRING_TEST_MAX_LEN; len++) {
+ s = buf + buf_size - 1 - offset - len;
+ s[len] = '\0';
+
+ KUNIT_EXPECT_PTR_EQ(test, strrchr(s, 'Z'), NULL);
+
+ if (len > 0)
+ KUNIT_EXPECT_PTR_EQ(test, strrchr(s, 'A'), s + len - 1);
+ else
+ KUNIT_EXPECT_PTR_EQ(test, strrchr(s, 'A'), NULL);
+
+ s[len] = 'A';
+ }
+ }
+
+ vfree(buf);
+}
+
static void string_test_strnchr(struct kunit *test)
{
const char *test_string = "abcdefghijkl";
@@ -614,12 +716,180 @@ static void string_test_strends(struct kunit *test)
KUNIT_EXPECT_TRUE(test, strends("", ""));
}
+#if IS_ENABLED(CONFIG_STRING_KUNIT_BENCH)
+/* Target string lengths for benchmarking */
+static const size_t bench_lens[] = {
+ 0, 1, 7, 8, 16, 31, 64, 127, 512, 1024, 3173, 4096,
+};
+
+/**
+ * alloc_max_bench_buffer() - Allocate buffer for the max test case.
+ * @test: KUnit context for managed allocation.
+ * @lens: Array of lengths used in the benchmark cases.
+ * @count: Number of elements in the @lens array.
+ * @buf_len: [out] Pointer to store the actually allocated buffer
+ * size (including NUL character).
+ *
+ * Return: Pointer to the allocated memory, or NULL on failure.
+ */
+static void *alloc_max_bench_buffer(struct kunit *test, const size_t *lens,
+ size_t count, size_t *buf_len)
+{
+ size_t max_len = 0;
+ void *buf;
+
+ for (size_t i = 0; i < count; i++)
+ max_len = max(lens[i], max_len);
+
+ /* Add space for NUL character */
+ max_len += 1;
+
+ buf = kunit_kzalloc(test, max_len, GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ if (buf_len)
+ *buf_len = max_len;
+
+ return buf;
+}
+
+/**
+ * fill_random_string() - Populate a buffer with a random NUL-terminated string.
+ * @buf: Buffer to fill.
+ * @len: Length of the buffer in bytes.
+ *
+ * Fills the buffer with random non-NUL bytes and ensures the string is
+ * properly NUL-terminated.
+ */
+static void fill_random_string(char *buf, size_t len)
+{
+ struct rnd_state state;
+
+ if (!buf || !len)
+ return;
+
+ /* Use a fixed seed to ensure deterministic benchmark results */
+ prandom_seed_state(&state, STRING_BENCH_SEED);
+ prandom_bytes_state(&state, buf, len);
+
+ /* Replace NUL characters to avoid early string termination */
+ for (size_t i = 0; i < len; i++) {
+ if (buf[i] == '\0')
+ buf[i] = 0x01;
+ }
+
+ buf[len - 1] = '\0';
+}
+
+/**
+ * STRING_BENCH() - Benchmark string functions.
+ * @iters: Number of iterations to run.
+ * @func: Function to benchmark.
+ * @...: Variable arguments passed to @func.
+ *
+ * Disables preemption and measures the total time in nanoseconds to execute
+ * @func(@__VA_ARGS__) for @iters times, including a small warm-up phase.
+ *
+ * Context: Disables preemption during measurement.
+ * Return: Total execution time in nanoseconds (u64).
+ */
+#define STRING_BENCH(iters, func, ...) \
+({ \
+ /* Volatile function pointer prevents dead code elimination */ \
+ typeof(func) (* volatile __func) = (func); \
+ size_t __bn_iters = (iters); \
+ size_t __bn_warm_iters; \
+ u64 __bn_t; \
+ \
+ /* Use 10% of the given iterations (maximum 50) to warm up */ \
+ __bn_warm_iters = max(__bn_iters / 10, 50U); \
+ \
+ for (size_t __bn_i = 0; __bn_i < __bn_warm_iters; __bn_i++) \
+ (void)__func(__VA_ARGS__); \
+ \
+ preempt_disable(); \
+ __bn_t = ktime_get_ns(); \
+ for (size_t __bn_i = 0; __bn_i < __bn_iters; __bn_i++) \
+ (void)__func(__VA_ARGS__); \
+ __bn_t = ktime_get_ns() - __bn_t; \
+ preempt_enable(); \
+ __bn_t; \
+})
+
+/**
+ * STRING_BENCH_BUF() - Benchmark harness for single-buffer functions.
+ * @test: KUnit context.
+ * @buf_name: Local char * variable name to be defined.
+ * @buf_size: Local size_t variable name to be defined.
+ * @func: Function to benchmark.
+ * @...: Extra arguments for @func.
+ *
+ * Prepares a randomized, NUL-terminated buffer and iterates through lengths
+ * in bench_lens, defining @buf_name and @buf_size in each loop.
+ */
+#define STRING_BENCH_BUF(test, buf_name, buf_size, func, ...) \
+do { \
+ size_t _bn_i, _bn_iters, _bn_size = 0; \
+ u64 _bn_t, _bn_mbps = 0, _bn_lat = 0; \
+ char *_bn_buf; \
+ \
+ _bn_buf = alloc_max_bench_buffer(test, bench_lens, \
+ ARRAY_SIZE(bench_lens), &_bn_size); \
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, _bn_buf); \
+ \
+ fill_random_string(_bn_buf, _bn_size); \
+ \
+ for (_bn_i = 0; _bn_i < ARRAY_SIZE(bench_lens); _bn_i++) { \
+ size_t buf_size = bench_lens[_bn_i]; \
+ char *buf_name = _bn_buf + _bn_size - buf_size - 1; \
+ _bn_iters = STRING_BENCH_WORKLOAD / max(buf_size, 1U); \
+ \
+ _bn_t = STRING_BENCH(_bn_iters, func, ##__VA_ARGS__); \
+ if (_bn_t > 0) { \
+ _bn_mbps = (u64)(buf_size) * _bn_iters * \
+ (NSEC_PER_SEC / MEGA); \
+ _bn_mbps = div64_u64(_bn_mbps, _bn_t); \
+ _bn_lat = div64_u64(_bn_t, _bn_iters); \
+ } \
+ kunit_info(test, "len=%zu: %llu MB/s (%llu ns/call)\n", \
+ buf_size, _bn_mbps, _bn_lat); \
+ } \
+} while (0)
+#else
+#define STRING_BENCH_BUF(test, buf_name, buf_size, func, ...) \
+ kunit_skip(test, "not enabled")
+#endif /* IS_ENABLED(CONFIG_STRING_KUNIT_BENCH) */
+
+static void string_bench_strlen(struct kunit *test)
+{
+ STRING_BENCH_BUF(test, buf, len, strlen, buf);
+}
+
+static void string_bench_strnlen(struct kunit *test)
+{
+ STRING_BENCH_BUF(test, buf, len, strnlen, buf, len);
+}
+
+static void string_bench_strchr(struct kunit *test)
+{
+ STRING_BENCH_BUF(test, buf, len, strchr, buf, '\0');
+}
+
+static void string_bench_strrchr(struct kunit *test)
+{
+ STRING_BENCH_BUF(test, buf, len, strrchr, buf, '\0');
+}
+
static struct kunit_case string_test_cases[] = {
KUNIT_CASE(string_test_memset16),
KUNIT_CASE(string_test_memset32),
KUNIT_CASE(string_test_memset64),
+ KUNIT_CASE(string_test_strlen),
+ KUNIT_CASE(string_test_strnlen),
KUNIT_CASE(string_test_strchr),
KUNIT_CASE(string_test_strnchr),
+ KUNIT_CASE(string_test_strrchr),
KUNIT_CASE(string_test_strspn),
KUNIT_CASE(string_test_strcmp),
KUNIT_CASE(string_test_strcmp_long_strings),
@@ -636,6 +906,10 @@ static struct kunit_case string_test_cases[] = {
KUNIT_CASE(string_test_strtomem),
KUNIT_CASE(string_test_memtostr),
KUNIT_CASE(string_test_strends),
+ KUNIT_CASE(string_bench_strlen),
+ KUNIT_CASE(string_bench_strnlen),
+ KUNIT_CASE(string_bench_strchr),
+ KUNIT_CASE(string_bench_strrchr),
{}
};
diff --git a/lib/tests/test_kprobes.c b/lib/tests/test_kprobes.c
index b7582010125c..06e729e4de05 100644
--- a/lib/tests/test_kprobes.c
+++ b/lib/tests/test_kprobes.c
@@ -12,6 +12,12 @@
#define div_factor 3
+#define KP_CLEAR(_kp) \
+do { \
+ (_kp).addr = NULL; \
+ (_kp).flags = 0; \
+} while (0)
+
static u32 rand1, preh_val, posth_val;
static u32 (*target)(u32 value);
static u32 (*recursed_target)(u32 value);
@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test)
current_test = test;
- /* addr and flags should be cleard for reusing kprobe. */
- kp.addr = NULL;
- kp.flags = 0;
-
KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2));
preh_val = 0;
posth_val = 0;
@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test)
struct kretprobe *rps[2] = {&rp, &rp2};
current_test = test;
- /* addr and flags should be cleard for reusing kprobe. */
- rp.kp.addr = NULL;
- rp.kp.flags = 0;
KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2));
krph_val = 0;
@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test)
unsigned long myretaddr = (unsigned long)__builtin_return_address(0);
current_test = test;
- rp3.kp.addr = NULL;
- rp3.kp.flags = 0;
/*
* Run the stacktrace_driver() to record correct return address in
@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)
struct kretprobe *rps[2] = {&rp3, &rp4};
current_test = test;
- rp3.kp.addr = NULL;
- rp3.kp.flags = 0;
//KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver());
@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)
static int kprobes_test_init(struct kunit *test)
{
+ KP_CLEAR(kp);
+ KP_CLEAR(kp2);
+ KP_CLEAR(kp_missed);
+#ifdef CONFIG_KRETPROBES
+ KP_CLEAR(rp.kp);
+ KP_CLEAR(rp2.kp);
+#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
+ KP_CLEAR(rp3.kp);
+ KP_CLEAR(rp4.kp);
+#endif
+#endif
+
target = kprobe_target;
target2 = kprobe_target2;
recursed_target = kprobe_recursed_target;
diff --git a/lib/tests/test_ratelimit.c b/lib/tests/test_ratelimit.c
index 33cea5f3d28b..e244f8cd47d7 100644
--- a/lib/tests/test_ratelimit.c
+++ b/lib/tests/test_ratelimit.c
@@ -68,7 +68,6 @@ static void test_ratelimit_smoke(struct kunit *test)
static struct ratelimit_state stressrl = RATELIMIT_STATE_INIT_FLAGS("stressrl", HZ / 10, 3,
RATELIMIT_MSG_ON_RELEASE);
-static int doneflag;
static const int stress_duration = 2 * HZ;
struct stress_kthread {
@@ -84,9 +83,8 @@ static int test_ratelimit_stress_child(void *arg)
struct stress_kthread *sktp = arg;
set_user_nice(current, MAX_NICE);
- WARN_ON_ONCE(!sktp->tp);
- while (!READ_ONCE(doneflag)) {
+ while (!kthread_should_stop()) {
sktp->nattempts++;
if (___ratelimit(&stressrl, __func__))
sktp->nunlimited++;
@@ -105,26 +103,37 @@ static void test_ratelimit_stress(struct kunit *test)
const int n_stress_kthread = cpumask_weight(cpu_online_mask);
struct stress_kthread skt = { 0 };
struct stress_kthread *sktp = kzalloc_objs(*sktp, n_stress_kthread);
+ int n_started = 0;
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
+ KUNIT_ASSERT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
for (i = 0; i < n_stress_kthread; i++) {
sktp[i].tp = kthread_run(test_ratelimit_stress_child, &sktp[i], "%s/%i",
"test_ratelimit_stress_child", i);
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "kthread creation failure");
+ if (IS_ERR(sktp[i].tp)) {
+ KUNIT_FAIL(test, "kthread_run failed: %ld", PTR_ERR(sktp[i].tp));
+ goto out_stop;
+ }
+ n_started++;
pr_alert("Spawned test_ratelimit_stress_child %d\n", i);
}
schedule_timeout_idle(stress_duration);
- WRITE_ONCE(doneflag, 1);
- for (i = 0; i < n_stress_kthread; i++) {
+
+out_stop:
+ for (i = 0; i < n_started; i++) {
kthread_stop(sktp[i].tp);
skt.nattempts += sktp[i].nattempts;
skt.nunlimited += sktp[i].nunlimited;
skt.nlimited += sktp[i].nlimited;
skt.nmissed += sktp[i].nmissed;
}
- KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
- "Outcomes not equal to attempts");
- KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed, "Misses not equal to limits");
+ if (n_started == n_stress_kthread) {
+ KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
+ "Outcomes not equal to attempts");
+ KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed,
+ "Misses not equal to limits");
+ }
+
+ kfree(sktp);
}
static struct kunit_case ratelimit_test_cases[] = {
diff --git a/lib/tests/uuid_kunit.c b/lib/tests/uuid_kunit.c
index de71b2649dac..2ef64fbe67d6 100644
--- a/lib/tests/uuid_kunit.c
+++ b/lib/tests/uuid_kunit.c
@@ -86,11 +86,67 @@ static void uuid_test_uuid_invalid(struct kunit *test)
}
}
+/*
+ * RFC 4122 section 4.4 says random UUIDs/GUIDs (version 4) must have:
+ * - version 4 in the high nibble of the version byte,
+ * - variant DCE 1.1 (binary 10x) in the high bits of byte 8.
+ *
+ * The version byte is byte 6 in the "wire" uuid_t layout and byte 7 in
+ * the byte-swapped guid_t layout.
+ */
+static void uuid_test_uuid_gen(struct kunit *test)
+{
+ uuid_t u;
+
+ for (unsigned int i = 0; i < 8; i++) {
+ uuid_gen(&u);
+ KUNIT_EXPECT_EQ(test, u.b[6] & 0xf0, 0x40);
+ KUNIT_EXPECT_EQ(test, u.b[8] & 0xc0, 0x80);
+ }
+}
+
+static void uuid_test_guid_gen(struct kunit *test)
+{
+ guid_t g;
+
+ for (unsigned int i = 0; i < 8; i++) {
+ guid_gen(&g);
+ KUNIT_EXPECT_EQ(test, g.b[7] & 0xf0, 0x40);
+ KUNIT_EXPECT_EQ(test, g.b[8] & 0xc0, 0x80);
+ }
+}
+
+static void uuid_test_generate_random_uuid(struct kunit *test)
+{
+ unsigned char buf[16];
+
+ for (unsigned int i = 0; i < 8; i++) {
+ generate_random_uuid(buf);
+ KUNIT_EXPECT_EQ(test, buf[6] & 0xf0, 0x40);
+ KUNIT_EXPECT_EQ(test, buf[8] & 0xc0, 0x80);
+ }
+}
+
+static void uuid_test_generate_random_guid(struct kunit *test)
+{
+ unsigned char buf[16];
+
+ for (unsigned int i = 0; i < 8; i++) {
+ generate_random_guid(buf);
+ KUNIT_EXPECT_EQ(test, buf[7] & 0xf0, 0x40);
+ KUNIT_EXPECT_EQ(test, buf[8] & 0xc0, 0x80);
+ }
+}
+
static struct kunit_case uuid_test_cases[] = {
KUNIT_CASE(uuid_test_guid_valid),
KUNIT_CASE(uuid_test_uuid_valid),
KUNIT_CASE(uuid_test_guid_invalid),
KUNIT_CASE(uuid_test_uuid_invalid),
+ KUNIT_CASE(uuid_test_uuid_gen),
+ KUNIT_CASE(uuid_test_guid_gen),
+ KUNIT_CASE(uuid_test_generate_random_uuid),
+ KUNIT_CASE(uuid_test_generate_random_guid),
{},
};