mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
Merge d3eb52113d ("Merge tag 'printk-for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux") into android-mainline
Steps on the way to 5.11-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ic32dabe18e83519db6d9320a1284f8a404cc76b7
This commit is contained in:
@@ -15,10 +15,10 @@ project, see :doc:`start`.
|
||||
Organization of this document
|
||||
=============================
|
||||
|
||||
This document is organized into two main sections: Testing and Isolating
|
||||
Behavior. The first covers what unit tests are and how to use KUnit to write
|
||||
them. The second covers how to use KUnit to isolate code and make it possible
|
||||
to unit test code that was otherwise un-unit-testable.
|
||||
This document is organized into two main sections: Testing and Common Patterns.
|
||||
The first covers what unit tests are and how to use KUnit to write them. The
|
||||
second covers common testing patterns, e.g. how to isolate code and make it
|
||||
possible to unit test code that was otherwise un-unit-testable.
|
||||
|
||||
Testing
|
||||
=======
|
||||
@@ -218,8 +218,11 @@ test was built in or not).
|
||||
|
||||
For more information on these types of things see the :doc:`api/test`.
|
||||
|
||||
Common Patterns
|
||||
===============
|
||||
|
||||
Isolating Behavior
|
||||
==================
|
||||
------------------
|
||||
|
||||
The most important aspect of unit testing that other forms of testing do not
|
||||
provide is the ability to limit the amount of code under test to a single unit.
|
||||
@@ -233,7 +236,7 @@ implementer, and architecture-specific functions which have definitions selected
|
||||
at compile time.
|
||||
|
||||
Classes
|
||||
-------
|
||||
~~~~~~~
|
||||
|
||||
Classes are not a construct that is built into the C programming language;
|
||||
however, it is an easily derived concept. Accordingly, pretty much every project
|
||||
@@ -451,6 +454,74 @@ We can now use it to test ``struct eeprom_buffer``:
|
||||
destroy_eeprom_buffer(ctx->eeprom_buffer);
|
||||
}
|
||||
|
||||
Testing against multiple inputs
|
||||
-------------------------------
|
||||
|
||||
Testing just a few inputs might not be enough to have confidence that the code
|
||||
works correctly, e.g. for a hash function.
|
||||
|
||||
In such cases, it can be helpful to have a helper macro or function, e.g. this
|
||||
fictitious example for ``sha1sum(1)``
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Note: the cast is to satisfy overly strict type-checking. */
|
||||
#define TEST_SHA1(in, want) \
|
||||
sha1sum(in, out); \
|
||||
KUNIT_EXPECT_STREQ_MSG(test, (char *)out, want, "sha1sum(%s)", in);
|
||||
|
||||
char out[40];
|
||||
TEST_SHA1("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
|
||||
TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169");
|
||||
|
||||
|
||||
Note the use of ``KUNIT_EXPECT_STREQ_MSG`` to give more context when it fails
|
||||
and make it easier to track down. (Yes, in this example, ``want`` is likely
|
||||
going to be unique enough on its own).
|
||||
|
||||
The ``_MSG`` variants are even more useful when the same expectation is called
|
||||
multiple times (in a loop or helper function) and thus the line number isn't
|
||||
enough to identify what failed, like below.
|
||||
|
||||
In some cases, it can be helpful to write a *table-driven test* instead, e.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int i;
|
||||
char out[40];
|
||||
|
||||
struct sha1_test_case {
|
||||
const char *str;
|
||||
const char *sha1;
|
||||
};
|
||||
|
||||
struct sha1_test_case cases[] = {
|
||||
{
|
||||
.str = "hello world",
|
||||
.sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
|
||||
},
|
||||
{
|
||||
.str = "hello world!",
|
||||
.sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
|
||||
},
|
||||
};
|
||||
for (i = 0; i < ARRAY_SIZE(cases); ++i) {
|
||||
sha1sum(cases[i].str, out);
|
||||
KUNIT_EXPECT_STREQ_MSG(test, (char *)out, cases[i].sha1,
|
||||
"sha1sum(%s)", cases[i].str);
|
||||
}
|
||||
|
||||
|
||||
There's more boilerplate involved, but it can:
|
||||
|
||||
* be more readable when there are multiple inputs/outputs thanks to field names,
|
||||
|
||||
* E.g. see ``fs/ext4/inode-test.c`` for an example of both.
|
||||
* reduce duplication if test cases can be shared across multiple tests.
|
||||
|
||||
* E.g. if we wanted to also test ``sha256sum``, we could add a ``sha256``
|
||||
field and reuse ``cases``.
|
||||
|
||||
.. _kunit-on-non-uml:
|
||||
|
||||
KUnit on non-UML architectures
|
||||
|
||||
@@ -31,6 +31,7 @@ endif
|
||||
BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
|
||||
-fno-strict-aliasing -O2 -msoft-float -mno-altivec -mno-vsx \
|
||||
-pipe -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \
|
||||
-include $(srctree)/include/linux/compiler_attributes.h \
|
||||
$(LINUXINCLUDE)
|
||||
|
||||
ifdef CONFIG_PPC64_BOOT_WRAPPER
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#define STATIC static
|
||||
#define INIT
|
||||
#define __always_inline inline
|
||||
|
||||
/*
|
||||
* The build process will copy the required zlib source files and headers
|
||||
|
||||
@@ -355,6 +355,7 @@ static int __init prom_strtobool(const char *s, bool *res)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ int arch_uprobe_exception_notify(struct notifier_block *self,
|
||||
case DIE_SSTEP:
|
||||
if (uprobe_post_sstep_notifier(regs))
|
||||
return NOTIFY_STOP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1500,6 +1500,7 @@ static int update_pmu_ops(struct imc_pmu *pmu)
|
||||
pmu->pmu.stop = trace_imc_event_stop;
|
||||
pmu->pmu.read = trace_imc_event_read;
|
||||
pmu->attr_groups[IMC_FORMAT_ATTR] = &trace_imc_format_group;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -401,20 +401,6 @@ config MIPS_EJTAG_FDC_KGDB_CHAN
|
||||
help
|
||||
FDC channel number to use for KGDB.
|
||||
|
||||
config NULL_TTY
|
||||
tristate "NULL TTY driver"
|
||||
help
|
||||
Say Y here if you want a NULL TTY which simply discards messages.
|
||||
|
||||
This is useful to allow userspace applications which expect a console
|
||||
device to work without modifications even when no console is
|
||||
available or desired.
|
||||
|
||||
In order to use this driver, you should redirect the console to this
|
||||
TTY, or boot the kernel with console=ttynull.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TRACE_ROUTER
|
||||
tristate "Trace data router for MIPI P1149.7 cJTAG standard"
|
||||
depends on TRACE_SINK
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
||||
tty_buffer.o tty_port.o tty_mutex.o \
|
||||
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
|
||||
n_null.o
|
||||
n_null.o ttynull.o
|
||||
obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
||||
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
||||
obj-$(CONFIG_AUDIT) += tty_audit.o
|
||||
@@ -25,7 +25,6 @@ obj-$(CONFIG_ISI) += isicom.o
|
||||
obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
|
||||
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
|
||||
obj-$(CONFIG_NOZOMI) += nozomi.o
|
||||
obj-$(CONFIG_NULL_TTY) += ttynull.o
|
||||
obj-$(CONFIG_ROCKETPORT) += rocket.o
|
||||
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
|
||||
obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Axis Communications AB
|
||||
*
|
||||
* The console is useful for userspace applications which expect a console
|
||||
* device to work without modifications even when no console is available
|
||||
* or desired.
|
||||
*
|
||||
* In order to use this driver, you should redirect the console to this
|
||||
* TTY, or boot the kernel with console=ttynull.
|
||||
*
|
||||
* Based on ttyprintk.c:
|
||||
* Copyright (C) 2010 Samo Pogacnik
|
||||
*/
|
||||
@@ -59,6 +66,17 @@ static struct console ttynull_console = {
|
||||
.device = ttynull_device,
|
||||
};
|
||||
|
||||
void __init register_ttynull_console(void)
|
||||
{
|
||||
if (!ttynull_driver)
|
||||
return;
|
||||
|
||||
if (add_preferred_console(ttynull_console.name, 0, NULL))
|
||||
return;
|
||||
|
||||
register_console(&ttynull_console);
|
||||
}
|
||||
|
||||
static int __init ttynull_init(void)
|
||||
{
|
||||
struct tty_driver *driver;
|
||||
|
||||
@@ -80,6 +80,145 @@ struct timestamp_expectation {
|
||||
bool lower_bound;
|
||||
};
|
||||
|
||||
static const struct timestamp_expectation test_data[] = {
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = -1LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0,
|
||||
.expected = {0LL, 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_LO_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_LO_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_HI_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_HI_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 6,
|
||||
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0xFFFFFFFF,
|
||||
.expected = {.tv_sec = 0x300000000LL,
|
||||
.tv_nsec = MAX_NANOSECONDS},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 3,
|
||||
.expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 3,
|
||||
.expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L},
|
||||
}
|
||||
};
|
||||
|
||||
static void timestamp_expectation_to_desc(const struct timestamp_expectation *t,
|
||||
char *desc)
|
||||
{
|
||||
strscpy(desc, t->test_case_name, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(ext4_inode, test_data, timestamp_expectation_to_desc);
|
||||
|
||||
static time64_t get_32bit_time(const struct timestamp_expectation * const test)
|
||||
{
|
||||
if (test->msb_set) {
|
||||
@@ -101,166 +240,35 @@ static time64_t get_32bit_time(const struct timestamp_expectation * const test)
|
||||
*/
|
||||
static void inode_test_xtimestamp_decoding(struct kunit *test)
|
||||
{
|
||||
const struct timestamp_expectation test_data[] = {
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = -1LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0,
|
||||
.expected = {0LL, 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 0,
|
||||
.expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_LO_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_LO_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 1,
|
||||
.expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NEG_HI_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NEG_HI_1_CASE,
|
||||
.msb_set = true,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 2,
|
||||
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 6,
|
||||
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 0xFFFFFFFF,
|
||||
.expected = {.tv_sec = 0x300000000LL,
|
||||
.tv_nsec = MAX_NANOSECONDS},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = true,
|
||||
.extra_bits = 3,
|
||||
.expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L},
|
||||
},
|
||||
|
||||
{
|
||||
.test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
|
||||
.msb_set = false,
|
||||
.lower_bound = false,
|
||||
.extra_bits = 3,
|
||||
.expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L},
|
||||
}
|
||||
};
|
||||
|
||||
struct timespec64 timestamp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(test_data); ++i) {
|
||||
timestamp.tv_sec = get_32bit_time(&test_data[i]);
|
||||
ext4_decode_extra_time(×tamp,
|
||||
cpu_to_le32(test_data[i].extra_bits));
|
||||
struct timestamp_expectation *test_param =
|
||||
(struct timestamp_expectation *)(test->param_value);
|
||||
|
||||
KUNIT_EXPECT_EQ_MSG(test,
|
||||
test_data[i].expected.tv_sec,
|
||||
timestamp.tv_sec,
|
||||
CASE_NAME_FORMAT,
|
||||
test_data[i].test_case_name,
|
||||
test_data[i].msb_set,
|
||||
test_data[i].lower_bound,
|
||||
test_data[i].extra_bits);
|
||||
KUNIT_EXPECT_EQ_MSG(test,
|
||||
test_data[i].expected.tv_nsec,
|
||||
timestamp.tv_nsec,
|
||||
CASE_NAME_FORMAT,
|
||||
test_data[i].test_case_name,
|
||||
test_data[i].msb_set,
|
||||
test_data[i].lower_bound,
|
||||
test_data[i].extra_bits);
|
||||
}
|
||||
timestamp.tv_sec = get_32bit_time(test_param);
|
||||
ext4_decode_extra_time(×tamp,
|
||||
cpu_to_le32(test_param->extra_bits));
|
||||
|
||||
KUNIT_EXPECT_EQ_MSG(test,
|
||||
test_param->expected.tv_sec,
|
||||
timestamp.tv_sec,
|
||||
CASE_NAME_FORMAT,
|
||||
test_param->test_case_name,
|
||||
test_param->msb_set,
|
||||
test_param->lower_bound,
|
||||
test_param->extra_bits);
|
||||
KUNIT_EXPECT_EQ_MSG(test,
|
||||
test_param->expected.tv_nsec,
|
||||
timestamp.tv_nsec,
|
||||
CASE_NAME_FORMAT,
|
||||
test_param->test_case_name,
|
||||
test_param->msb_set,
|
||||
test_param->lower_bound,
|
||||
test_param->extra_bits);
|
||||
}
|
||||
|
||||
static struct kunit_case ext4_inode_test_cases[] = {
|
||||
KUNIT_CASE(inode_test_xtimestamp_decoding),
|
||||
KUNIT_CASE_PARAM(inode_test_xtimestamp_decoding, ext4_inode_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ struct kunit;
|
||||
/* Size of log associated with test. */
|
||||
#define KUNIT_LOG_SIZE 512
|
||||
|
||||
/* Maximum size of parameter description string. */
|
||||
#define KUNIT_PARAM_DESC_SIZE 128
|
||||
|
||||
/*
|
||||
* TAP specifies subtest stream indentation of 4 spaces, 8 spaces for a
|
||||
* sub-subtest. See the "Subtests" section in
|
||||
@@ -107,6 +110,7 @@ struct kunit;
|
||||
*
|
||||
* @run_case: the function representing the actual test case.
|
||||
* @name: the name of the test case.
|
||||
* @generate_params: the generator function for parameterized tests.
|
||||
*
|
||||
* A test case is a function with the signature,
|
||||
* ``void (*)(struct kunit *)``
|
||||
@@ -141,6 +145,7 @@ struct kunit;
|
||||
struct kunit_case {
|
||||
void (*run_case)(struct kunit *test);
|
||||
const char *name;
|
||||
const void* (*generate_params)(const void *prev, char *desc);
|
||||
|
||||
/* private: internal use only. */
|
||||
bool success;
|
||||
@@ -163,6 +168,27 @@ static inline char *kunit_status_to_string(bool status)
|
||||
*/
|
||||
#define KUNIT_CASE(test_name) { .run_case = test_name, .name = #test_name }
|
||||
|
||||
/**
|
||||
* KUNIT_CASE_PARAM - A helper for creation a parameterized &struct kunit_case
|
||||
*
|
||||
* @test_name: a reference to a test case function.
|
||||
* @gen_params: a reference to a parameter generator function.
|
||||
*
|
||||
* The generator function::
|
||||
*
|
||||
* const void* gen_params(const void *prev, char *desc)
|
||||
*
|
||||
* is used to lazily generate a series of arbitrarily typed values that fit into
|
||||
* a void*. The argument @prev is the previously returned value, which should be
|
||||
* used to derive the next value; @prev is set to NULL on the initial generator
|
||||
* call. When no more values are available, the generator must return NULL.
|
||||
* Optionally write a string into @desc (size of KUNIT_PARAM_DESC_SIZE)
|
||||
* describing the parameter.
|
||||
*/
|
||||
#define KUNIT_CASE_PARAM(test_name, gen_params) \
|
||||
{ .run_case = test_name, .name = #test_name, \
|
||||
.generate_params = gen_params }
|
||||
|
||||
/**
|
||||
* struct kunit_suite - describes a related collection of &struct kunit_case
|
||||
*
|
||||
@@ -208,6 +234,10 @@ struct kunit {
|
||||
const char *name; /* Read only after initialization! */
|
||||
char *log; /* Points at case log after initialization */
|
||||
struct kunit_try_catch try_catch;
|
||||
/* param_value is the current parameter value for a test case. */
|
||||
const void *param_value;
|
||||
/* param_index stores the index of the parameter in parameterized tests. */
|
||||
int param_index;
|
||||
/*
|
||||
* success starts as true, and may only be set to false during a
|
||||
* test case; thus, it is safe to update this across multiple
|
||||
@@ -1742,4 +1772,25 @@ do { \
|
||||
fmt, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* KUNIT_ARRAY_PARAM() - Define test parameter generator from an array.
|
||||
* @name: prefix for the test parameter generator function.
|
||||
* @array: array of test parameters.
|
||||
* @get_desc: function to convert param to description; NULL to use default
|
||||
*
|
||||
* Define function @name_gen_params which uses @array to generate parameters.
|
||||
*/
|
||||
#define KUNIT_ARRAY_PARAM(name, array, get_desc) \
|
||||
static const void *name##_gen_params(const void *prev, char *desc) \
|
||||
{ \
|
||||
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
|
||||
if (__next - (array) < ARRAY_SIZE((array))) { \
|
||||
void (*__get_desc)(typeof(__next), char *) = get_desc; \
|
||||
if (__get_desc) \
|
||||
__get_desc(__next, desc); \
|
||||
return __next; \
|
||||
} \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#endif /* _KUNIT_TEST_H */
|
||||
|
||||
@@ -186,9 +186,12 @@ extern int braille_register_console(struct console *, int index,
|
||||
extern int braille_unregister_console(struct console *);
|
||||
#ifdef CONFIG_TTY
|
||||
extern void console_sysfs_notify(void);
|
||||
extern void register_ttynull_console(void);
|
||||
#else
|
||||
static inline void console_sysfs_notify(void)
|
||||
{ }
|
||||
static inline void register_ttynull_console(void)
|
||||
{ }
|
||||
#endif
|
||||
extern bool console_suspend_enabled;
|
||||
|
||||
|
||||
10
init/main.c
10
init/main.c
@@ -1480,8 +1480,14 @@ void __init console_on_rootfs(void)
|
||||
struct file *file = filp_open("/dev/console", O_RDWR, 0);
|
||||
|
||||
if (IS_ERR(file)) {
|
||||
pr_err("Warning: unable to open an initial console.\n");
|
||||
return;
|
||||
pr_err("Warning: unable to open an initial console. Fallback to ttynull.\n");
|
||||
register_ttynull_console();
|
||||
|
||||
file = filp_open("/dev/console", O_RDWR, 0);
|
||||
if (IS_ERR(file)) {
|
||||
pr_err("Warning: Failed to add ttynull console. No stdin, stdout, and stderr for the init process!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
init_dup(file);
|
||||
init_dup(file);
|
||||
|
||||
@@ -493,52 +493,6 @@ static void truncate_msg(u16 *text_len, u16 *trunc_msg_len)
|
||||
*trunc_msg_len = 0;
|
||||
}
|
||||
|
||||
/* insert record into the buffer, discard old ones, update heads */
|
||||
static int log_store(u32 caller_id, int facility, int level,
|
||||
enum log_flags flags, u64 ts_nsec,
|
||||
const struct dev_printk_info *dev_info,
|
||||
const char *text, u16 text_len)
|
||||
{
|
||||
struct prb_reserved_entry e;
|
||||
struct printk_record r;
|
||||
u16 trunc_msg_len = 0;
|
||||
|
||||
prb_rec_init_wr(&r, text_len);
|
||||
|
||||
if (!prb_reserve(&e, prb, &r)) {
|
||||
/* truncate the message if it is too long for empty buffer */
|
||||
truncate_msg(&text_len, &trunc_msg_len);
|
||||
prb_rec_init_wr(&r, text_len + trunc_msg_len);
|
||||
/* survive when the log buffer is too small for trunc_msg */
|
||||
if (!prb_reserve(&e, prb, &r))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fill message */
|
||||
memcpy(&r.text_buf[0], text, text_len);
|
||||
if (trunc_msg_len)
|
||||
memcpy(&r.text_buf[text_len], trunc_msg, trunc_msg_len);
|
||||
r.info->text_len = text_len + trunc_msg_len;
|
||||
r.info->facility = facility;
|
||||
r.info->level = level & 7;
|
||||
r.info->flags = flags & 0x1f;
|
||||
if (ts_nsec > 0)
|
||||
r.info->ts_nsec = ts_nsec;
|
||||
else
|
||||
r.info->ts_nsec = local_clock();
|
||||
r.info->caller_id = caller_id;
|
||||
if (dev_info)
|
||||
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
|
||||
|
||||
/* A message without a trailing newline can be continued. */
|
||||
if (!(flags & LOG_NEWLINE))
|
||||
prb_commit(&e);
|
||||
else
|
||||
prb_final_commit(&e);
|
||||
|
||||
return (text_len + trunc_msg_len);
|
||||
}
|
||||
|
||||
int dmesg_restrict = IS_ENABLED(CONFIG_SECURITY_DMESG_RESTRICT);
|
||||
|
||||
static int syslog_action_restricted(int type)
|
||||
@@ -743,7 +697,6 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (LOG_FACILITY(u) != 0)
|
||||
facility = LOG_FACILITY(u);
|
||||
endp++;
|
||||
len -= endp - line;
|
||||
line = endp;
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1127,7 @@ void __init setup_log_buf(int early)
|
||||
new_descs, ilog2(new_descs_count),
|
||||
new_infos);
|
||||
|
||||
logbuf_lock_irqsave(flags);
|
||||
printk_safe_enter_irqsave(flags);
|
||||
|
||||
log_buf_len = new_log_buf_len;
|
||||
log_buf = new_log_buf;
|
||||
@@ -1191,7 +1144,7 @@ void __init setup_log_buf(int early)
|
||||
*/
|
||||
prb = &printk_rb_dynamic;
|
||||
|
||||
logbuf_unlock_irqrestore(flags);
|
||||
printk_safe_exit_irqrestore(flags);
|
||||
|
||||
if (seq != prb_next_seq(&printk_rb_static)) {
|
||||
pr_err("dropped %llu messages\n",
|
||||
@@ -1909,75 +1862,117 @@ static inline u32 printk_caller_id(void)
|
||||
0x80000000 + raw_smp_processor_id();
|
||||
}
|
||||
|
||||
static size_t log_output(int facility, int level, enum log_flags lflags,
|
||||
const struct dev_printk_info *dev_info,
|
||||
char *text, size_t text_len)
|
||||
/**
|
||||
* parse_prefix - Parse level and control flags.
|
||||
*
|
||||
* @text: The terminated text message.
|
||||
* @level: A pointer to the current level value, will be updated.
|
||||
* @lflags: A pointer to the current log flags, will be updated.
|
||||
*
|
||||
* @level may be NULL if the caller is not interested in the parsed value.
|
||||
* Otherwise the variable pointed to by @level must be set to
|
||||
* LOGLEVEL_DEFAULT in order to be updated with the parsed value.
|
||||
*
|
||||
* @lflags may be NULL if the caller is not interested in the parsed value.
|
||||
* Otherwise the variable pointed to by @lflags will be OR'd with the parsed
|
||||
* value.
|
||||
*
|
||||
* Return: The length of the parsed level and control flags.
|
||||
*/
|
||||
static u16 parse_prefix(char *text, int *level, enum log_flags *lflags)
|
||||
{
|
||||
const u32 caller_id = printk_caller_id();
|
||||
u16 prefix_len = 0;
|
||||
int kern_level;
|
||||
|
||||
if (lflags & LOG_CONT) {
|
||||
struct prb_reserved_entry e;
|
||||
struct printk_record r;
|
||||
while (*text) {
|
||||
kern_level = printk_get_level(text);
|
||||
if (!kern_level)
|
||||
break;
|
||||
|
||||
prb_rec_init_wr(&r, text_len);
|
||||
if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
|
||||
memcpy(&r.text_buf[r.info->text_len], text, text_len);
|
||||
r.info->text_len += text_len;
|
||||
if (lflags & LOG_NEWLINE) {
|
||||
r.info->flags |= LOG_NEWLINE;
|
||||
prb_final_commit(&e);
|
||||
} else {
|
||||
prb_commit(&e);
|
||||
}
|
||||
return text_len;
|
||||
switch (kern_level) {
|
||||
case '0' ... '7':
|
||||
if (level && *level == LOGLEVEL_DEFAULT)
|
||||
*level = kern_level - '0';
|
||||
break;
|
||||
case 'c': /* KERN_CONT */
|
||||
if (lflags)
|
||||
*lflags |= LOG_CONT;
|
||||
}
|
||||
|
||||
prefix_len += 2;
|
||||
text += 2;
|
||||
}
|
||||
|
||||
return prefix_len;
|
||||
}
|
||||
|
||||
static u16 printk_sprint(char *text, u16 size, int facility, enum log_flags *lflags,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
u16 text_len;
|
||||
|
||||
text_len = vscnprintf(text, size, fmt, args);
|
||||
|
||||
/* Mark and strip a trailing newline. */
|
||||
if (text_len && text[text_len - 1] == '\n') {
|
||||
text_len--;
|
||||
*lflags |= LOG_NEWLINE;
|
||||
}
|
||||
|
||||
/* Strip log level and control flags. */
|
||||
if (facility == 0) {
|
||||
u16 prefix_len;
|
||||
|
||||
prefix_len = parse_prefix(text, NULL, NULL);
|
||||
if (prefix_len) {
|
||||
text_len -= prefix_len;
|
||||
memmove(text, text + prefix_len, text_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store it in the record log */
|
||||
return log_store(caller_id, facility, level, lflags, 0,
|
||||
dev_info, text, text_len);
|
||||
return text_len;
|
||||
}
|
||||
|
||||
/* Must be called under logbuf_lock. */
|
||||
__printf(4, 0)
|
||||
int vprintk_store(int facility, int level,
|
||||
const struct dev_printk_info *dev_info,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
static char textbuf[LOG_LINE_MAX];
|
||||
char *text = textbuf;
|
||||
size_t text_len;
|
||||
const u32 caller_id = printk_caller_id();
|
||||
struct prb_reserved_entry e;
|
||||
enum log_flags lflags = 0;
|
||||
struct printk_record r;
|
||||
u16 trunc_msg_len = 0;
|
||||
char prefix_buf[8];
|
||||
u16 reserve_size;
|
||||
va_list args2;
|
||||
u16 text_len;
|
||||
u64 ts_nsec;
|
||||
|
||||
/*
|
||||
* The printf needs to come first; we need the syslog
|
||||
* prefix which might be passed-in as a parameter.
|
||||
* Since the duration of printk() can vary depending on the message
|
||||
* and state of the ringbuffer, grab the timestamp now so that it is
|
||||
* close to the call of printk(). This provides a more deterministic
|
||||
* timestamp with respect to the caller.
|
||||
*/
|
||||
text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
|
||||
ts_nsec = local_clock();
|
||||
|
||||
/* mark and strip a trailing newline */
|
||||
if (text_len && text[text_len-1] == '\n') {
|
||||
text_len--;
|
||||
lflags |= LOG_NEWLINE;
|
||||
}
|
||||
/*
|
||||
* The sprintf needs to come first since the syslog prefix might be
|
||||
* passed in as a parameter. An extra byte must be reserved so that
|
||||
* later the vscnprintf() into the reserved buffer has room for the
|
||||
* terminating '\0', which is not counted by vsnprintf().
|
||||
*/
|
||||
va_copy(args2, args);
|
||||
reserve_size = vsnprintf(&prefix_buf[0], sizeof(prefix_buf), fmt, args2) + 1;
|
||||
va_end(args2);
|
||||
|
||||
/* strip kernel syslog prefix and extract log level or control flags */
|
||||
if (facility == 0) {
|
||||
int kern_level;
|
||||
if (reserve_size > LOG_LINE_MAX)
|
||||
reserve_size = LOG_LINE_MAX;
|
||||
|
||||
while ((kern_level = printk_get_level(text)) != 0) {
|
||||
switch (kern_level) {
|
||||
case '0' ... '7':
|
||||
if (level == LOGLEVEL_DEFAULT)
|
||||
level = kern_level - '0';
|
||||
break;
|
||||
case 'c': /* KERN_CONT */
|
||||
lflags |= LOG_CONT;
|
||||
}
|
||||
|
||||
text_len -= 2;
|
||||
text += 2;
|
||||
}
|
||||
}
|
||||
/* Extract log level or control flags. */
|
||||
if (facility == 0)
|
||||
parse_prefix(&prefix_buf[0], &level, &lflags);
|
||||
|
||||
if (level == LOGLEVEL_DEFAULT)
|
||||
level = default_message_loglevel;
|
||||
@@ -1985,7 +1980,59 @@ int vprintk_store(int facility, int level,
|
||||
if (dev_info)
|
||||
lflags |= LOG_NEWLINE;
|
||||
|
||||
return log_output(facility, level, lflags, dev_info, text, text_len);
|
||||
if (lflags & LOG_CONT) {
|
||||
prb_rec_init_wr(&r, reserve_size);
|
||||
if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
|
||||
text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size,
|
||||
facility, &lflags, fmt, args);
|
||||
r.info->text_len += text_len;
|
||||
|
||||
if (lflags & LOG_NEWLINE) {
|
||||
r.info->flags |= LOG_NEWLINE;
|
||||
prb_final_commit(&e);
|
||||
} else {
|
||||
prb_commit(&e);
|
||||
}
|
||||
|
||||
return text_len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Explicitly initialize the record before every prb_reserve() call.
|
||||
* prb_reserve_in_last() and prb_reserve() purposely invalidate the
|
||||
* structure when they fail.
|
||||
*/
|
||||
prb_rec_init_wr(&r, reserve_size);
|
||||
if (!prb_reserve(&e, prb, &r)) {
|
||||
/* truncate the message if it is too long for empty buffer */
|
||||
truncate_msg(&reserve_size, &trunc_msg_len);
|
||||
|
||||
prb_rec_init_wr(&r, reserve_size + trunc_msg_len);
|
||||
if (!prb_reserve(&e, prb, &r))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fill message */
|
||||
text_len = printk_sprint(&r.text_buf[0], reserve_size, facility, &lflags, fmt, args);
|
||||
if (trunc_msg_len)
|
||||
memcpy(&r.text_buf[text_len], trunc_msg, trunc_msg_len);
|
||||
r.info->text_len = text_len + trunc_msg_len;
|
||||
r.info->facility = facility;
|
||||
r.info->level = level & 7;
|
||||
r.info->flags = lflags & 0x1f;
|
||||
r.info->ts_nsec = ts_nsec;
|
||||
r.info->caller_id = caller_id;
|
||||
if (dev_info)
|
||||
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
|
||||
|
||||
/* A message without a trailing newline can be continued. */
|
||||
if (!(lflags & LOG_NEWLINE))
|
||||
prb_commit(&e);
|
||||
else
|
||||
prb_final_commit(&e);
|
||||
|
||||
return (text_len + trunc_msg_len);
|
||||
}
|
||||
|
||||
asmlinkage int vprintk_emit(int facility, int level,
|
||||
@@ -2008,10 +2055,9 @@ asmlinkage int vprintk_emit(int facility, int level,
|
||||
boot_delay_msec(level);
|
||||
printk_delay();
|
||||
|
||||
/* This stops the holder of console_sem just where we want him */
|
||||
logbuf_lock_irqsave(flags);
|
||||
printk_safe_enter_irqsave(flags);
|
||||
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
|
||||
logbuf_unlock_irqrestore(flags);
|
||||
printk_safe_exit_irqrestore(flags);
|
||||
|
||||
/* If called from the scheduler, we can not call up(). */
|
||||
if (!in_sched) {
|
||||
@@ -2191,8 +2237,15 @@ static int __init console_setup(char *str)
|
||||
char *s, *options, *brl_options = NULL;
|
||||
int idx;
|
||||
|
||||
if (str[0] == 0)
|
||||
/*
|
||||
* console="" or console=null have been suggested as a way to
|
||||
* disable console output. Use ttynull that has been created
|
||||
* for exacly this purpose.
|
||||
*/
|
||||
if (str[0] == 0 || strcmp(str, "null") == 0) {
|
||||
__add_preferred_console("ttynull", 0, NULL, NULL, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_braille_console_setup(&str, &brl_options))
|
||||
return 1;
|
||||
|
||||
@@ -559,11 +559,12 @@ static void desc_make_reusable(struct prb_desc_ring *desc_ring,
|
||||
* on error the caller can re-load the tail lpos to determine the situation.
|
||||
*/
|
||||
static bool data_make_reusable(struct printk_ringbuffer *rb,
|
||||
struct prb_data_ring *data_ring,
|
||||
unsigned long lpos_begin,
|
||||
unsigned long lpos_end,
|
||||
unsigned long *lpos_out)
|
||||
{
|
||||
|
||||
struct prb_data_ring *data_ring = &rb->text_data_ring;
|
||||
struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
||||
struct prb_data_block *blk;
|
||||
enum desc_state d_state;
|
||||
@@ -625,10 +626,9 @@ static bool data_make_reusable(struct printk_ringbuffer *rb,
|
||||
* descriptors into the reusable state if the tail is pushed beyond
|
||||
* their associated data block.
|
||||
*/
|
||||
static bool data_push_tail(struct printk_ringbuffer *rb,
|
||||
struct prb_data_ring *data_ring,
|
||||
unsigned long lpos)
|
||||
static bool data_push_tail(struct printk_ringbuffer *rb, unsigned long lpos)
|
||||
{
|
||||
struct prb_data_ring *data_ring = &rb->text_data_ring;
|
||||
unsigned long tail_lpos_new;
|
||||
unsigned long tail_lpos;
|
||||
unsigned long next_lpos;
|
||||
@@ -669,8 +669,7 @@ static bool data_push_tail(struct printk_ringbuffer *rb,
|
||||
* Make all descriptors reusable that are associated with
|
||||
* data blocks before @lpos.
|
||||
*/
|
||||
if (!data_make_reusable(rb, data_ring, tail_lpos, lpos,
|
||||
&next_lpos)) {
|
||||
if (!data_make_reusable(rb, tail_lpos, lpos, &next_lpos)) {
|
||||
/*
|
||||
* 1. Guarantee the block ID loaded in
|
||||
* data_make_reusable() is performed before
|
||||
@@ -807,7 +806,7 @@ static bool desc_push_tail(struct printk_ringbuffer *rb,
|
||||
* data blocks once their associated descriptor is gone.
|
||||
*/
|
||||
|
||||
if (!data_push_tail(rb, &rb->text_data_ring, desc.text_blk_lpos.next))
|
||||
if (!data_push_tail(rb, desc.text_blk_lpos.next))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@@ -1019,10 +1018,10 @@ static unsigned long get_next_lpos(struct prb_data_ring *data_ring,
|
||||
* if necessary. This function also associates the data block with
|
||||
* a specified descriptor.
|
||||
*/
|
||||
static char *data_alloc(struct printk_ringbuffer *rb,
|
||||
struct prb_data_ring *data_ring, unsigned int size,
|
||||
static char *data_alloc(struct printk_ringbuffer *rb, unsigned int size,
|
||||
struct prb_data_blk_lpos *blk_lpos, unsigned long id)
|
||||
{
|
||||
struct prb_data_ring *data_ring = &rb->text_data_ring;
|
||||
struct prb_data_block *blk;
|
||||
unsigned long begin_lpos;
|
||||
unsigned long next_lpos;
|
||||
@@ -1041,7 +1040,7 @@ static char *data_alloc(struct printk_ringbuffer *rb,
|
||||
do {
|
||||
next_lpos = get_next_lpos(data_ring, begin_lpos, size);
|
||||
|
||||
if (!data_push_tail(rb, data_ring, next_lpos - DATA_SIZE(data_ring))) {
|
||||
if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) {
|
||||
/* Failed to allocate, specify a data-less block. */
|
||||
blk_lpos->begin = FAILED_LPOS;
|
||||
blk_lpos->next = FAILED_LPOS;
|
||||
@@ -1100,10 +1099,10 @@ static char *data_alloc(struct printk_ringbuffer *rb,
|
||||
* Return a pointer to the beginning of the entire data buffer or NULL on
|
||||
* failure.
|
||||
*/
|
||||
static char *data_realloc(struct printk_ringbuffer *rb,
|
||||
struct prb_data_ring *data_ring, unsigned int size,
|
||||
static char *data_realloc(struct printk_ringbuffer *rb, unsigned int size,
|
||||
struct prb_data_blk_lpos *blk_lpos, unsigned long id)
|
||||
{
|
||||
struct prb_data_ring *data_ring = &rb->text_data_ring;
|
||||
struct prb_data_block *blk;
|
||||
unsigned long head_lpos;
|
||||
unsigned long next_lpos;
|
||||
@@ -1130,7 +1129,7 @@ static char *data_realloc(struct printk_ringbuffer *rb,
|
||||
return &blk->data[0];
|
||||
}
|
||||
|
||||
if (!data_push_tail(rb, data_ring, next_lpos - DATA_SIZE(data_ring)))
|
||||
if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring)))
|
||||
return NULL;
|
||||
|
||||
/* The memory barrier involvement is the same as data_alloc:A. */
|
||||
@@ -1395,7 +1394,7 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer
|
||||
if (r->text_buf_size > max_size)
|
||||
goto fail;
|
||||
|
||||
r->text_buf = data_alloc(rb, &rb->text_data_ring, r->text_buf_size,
|
||||
r->text_buf = data_alloc(rb, r->text_buf_size,
|
||||
&d->text_blk_lpos, id);
|
||||
} else {
|
||||
if (!get_data(&rb->text_data_ring, &d->text_blk_lpos, &data_size))
|
||||
@@ -1419,7 +1418,7 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer
|
||||
if (r->text_buf_size > max_size)
|
||||
goto fail;
|
||||
|
||||
r->text_buf = data_realloc(rb, &rb->text_data_ring, r->text_buf_size,
|
||||
r->text_buf = data_realloc(rb, r->text_buf_size,
|
||||
&d->text_blk_lpos, id);
|
||||
}
|
||||
if (r->text_buf_size && !r->text_buf)
|
||||
@@ -1547,8 +1546,7 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
|
||||
if (info->seq > 0)
|
||||
desc_make_final(desc_ring, DESC_ID(id - 1));
|
||||
|
||||
r->text_buf = data_alloc(rb, &rb->text_data_ring, r->text_buf_size,
|
||||
&d->text_blk_lpos, id);
|
||||
r->text_buf = data_alloc(rb, r->text_buf_size, &d->text_blk_lpos, id);
|
||||
/* If text data allocation fails, a data-less record is committed. */
|
||||
if (r->text_buf_size && !r->text_buf) {
|
||||
prb_commit(e);
|
||||
|
||||
@@ -381,7 +381,7 @@ next_op:
|
||||
case ASN1_OP_END_SET_ACT:
|
||||
if (unlikely(!(flags & FLAG_MATCHED)))
|
||||
goto tag_mismatch;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case ASN1_OP_END_SEQ:
|
||||
case ASN1_OP_END_SET_OF:
|
||||
@@ -448,7 +448,7 @@ next_op:
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case ASN1_OP_ACT:
|
||||
ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
|
||||
|
||||
@@ -1113,7 +1113,7 @@ struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
|
||||
index_key))
|
||||
goto found_leaf;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case assoc_array_walk_tree_empty:
|
||||
case assoc_array_walk_found_wrong_shortcut:
|
||||
default:
|
||||
|
||||
@@ -827,7 +827,7 @@ int __init xbc_init(char *buf, const char **emsg, int *epos)
|
||||
q - 2);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case '=':
|
||||
ret = xbc_parse_kv(&p, q, c);
|
||||
break;
|
||||
@@ -836,7 +836,7 @@ int __init xbc_init(char *buf, const char **emsg, int *epos)
|
||||
break;
|
||||
case '#':
|
||||
q = skip_comment(q);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case ';':
|
||||
case '\n':
|
||||
ret = xbc_parse_key(&p, q);
|
||||
|
||||
@@ -144,27 +144,28 @@ unsigned long long memparse(const char *ptr, char **retptr)
|
||||
case 'E':
|
||||
case 'e':
|
||||
ret <<= 10;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'P':
|
||||
case 'p':
|
||||
ret <<= 10;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'T':
|
||||
case 't':
|
||||
ret <<= 10;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'G':
|
||||
case 'g':
|
||||
ret <<= 10;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'M':
|
||||
case 'm':
|
||||
ret <<= 10;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'K':
|
||||
case 'k':
|
||||
ret <<= 10;
|
||||
endptr++;
|
||||
fallthrough;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ void net_dim(struct dim *dim, struct dim_sample end_sample)
|
||||
schedule_work(&dim->work);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DIM_START_MEASURE:
|
||||
dim_update_sample(end_sample.event_ctr, end_sample.pkt_ctr,
|
||||
end_sample.byte_ctr, &dim->start_sample);
|
||||
|
||||
@@ -59,7 +59,7 @@ static bool rdma_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
|
||||
break;
|
||||
case DIM_STATS_WORSE:
|
||||
dim_turn(dim);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DIM_STATS_BETTER:
|
||||
step_res = rdma_dim_step(dim);
|
||||
if (step_res == DIM_ON_EDGE)
|
||||
@@ -94,7 +94,7 @@ void rdma_dim(struct dim *dim, u64 completions)
|
||||
schedule_work(&dim->work);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DIM_START_MEASURE:
|
||||
dim->state = DIM_MEASURE_IN_PROGRESS;
|
||||
dim_update_sample_with_comps(curr_sample->event_ctr, 0, 0,
|
||||
|
||||
@@ -102,7 +102,7 @@ bool __pure glob_match(char const *pat, char const *str)
|
||||
break;
|
||||
case '\\':
|
||||
d = *pat++;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default: /* Literal character */
|
||||
literal:
|
||||
if (c == d) {
|
||||
|
||||
@@ -355,6 +355,7 @@ int kstrtobool(const char *s, bool *res)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -325,39 +325,72 @@ static void kunit_catch_run_case(void *data)
|
||||
* occur in a test case and reports them as failures.
|
||||
*/
|
||||
static void kunit_run_case_catch_errors(struct kunit_suite *suite,
|
||||
struct kunit_case *test_case)
|
||||
struct kunit_case *test_case,
|
||||
struct kunit *test)
|
||||
{
|
||||
struct kunit_try_catch_context context;
|
||||
struct kunit_try_catch *try_catch;
|
||||
struct kunit test;
|
||||
|
||||
kunit_init_test(&test, test_case->name, test_case->log);
|
||||
try_catch = &test.try_catch;
|
||||
kunit_init_test(test, test_case->name, test_case->log);
|
||||
try_catch = &test->try_catch;
|
||||
|
||||
kunit_try_catch_init(try_catch,
|
||||
&test,
|
||||
test,
|
||||
kunit_try_run_case,
|
||||
kunit_catch_run_case);
|
||||
context.test = &test;
|
||||
context.test = test;
|
||||
context.suite = suite;
|
||||
context.test_case = test_case;
|
||||
kunit_try_catch_run(try_catch, &context);
|
||||
|
||||
test_case->success = test.success;
|
||||
|
||||
kunit_print_ok_not_ok(&test, true, test_case->success,
|
||||
kunit_test_case_num(suite, test_case),
|
||||
test_case->name);
|
||||
test_case->success = test->success;
|
||||
}
|
||||
|
||||
int kunit_run_tests(struct kunit_suite *suite)
|
||||
{
|
||||
char param_desc[KUNIT_PARAM_DESC_SIZE];
|
||||
struct kunit_case *test_case;
|
||||
|
||||
kunit_print_subtest_start(suite);
|
||||
|
||||
kunit_suite_for_each_test_case(suite, test_case)
|
||||
kunit_run_case_catch_errors(suite, test_case);
|
||||
kunit_suite_for_each_test_case(suite, test_case) {
|
||||
struct kunit test = { .param_value = NULL, .param_index = 0 };
|
||||
bool test_success = true;
|
||||
|
||||
if (test_case->generate_params) {
|
||||
/* Get initial param. */
|
||||
param_desc[0] = '\0';
|
||||
test.param_value = test_case->generate_params(NULL, param_desc);
|
||||
}
|
||||
|
||||
do {
|
||||
kunit_run_case_catch_errors(suite, test_case, &test);
|
||||
test_success &= test_case->success;
|
||||
|
||||
if (test_case->generate_params) {
|
||||
if (param_desc[0] == '\0') {
|
||||
snprintf(param_desc, sizeof(param_desc),
|
||||
"param-%d", test.param_index);
|
||||
}
|
||||
|
||||
kunit_log(KERN_INFO, &test,
|
||||
KUNIT_SUBTEST_INDENT
|
||||
"# %s: %s %d - %s",
|
||||
test_case->name,
|
||||
kunit_status_to_string(test.success),
|
||||
test.param_index + 1, param_desc);
|
||||
|
||||
/* Get next param. */
|
||||
param_desc[0] = '\0';
|
||||
test.param_value = test_case->generate_params(test.param_value, param_desc);
|
||||
test.param_index++;
|
||||
}
|
||||
} while (test.param_value);
|
||||
|
||||
kunit_print_ok_not_ok(&test, true, test_success,
|
||||
kunit_test_case_num(suite, test_case),
|
||||
test_case->name);
|
||||
}
|
||||
|
||||
kunit_print_subtest_end(suite);
|
||||
|
||||
|
||||
@@ -432,7 +432,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case NLA_STRING:
|
||||
if (attrlen < 1)
|
||||
|
||||
@@ -68,11 +68,11 @@ u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
|
||||
bytemask_from_count(left)));
|
||||
#else
|
||||
switch (left) {
|
||||
case 7: b |= ((u64)end[6]) << 48; /* fall through */
|
||||
case 6: b |= ((u64)end[5]) << 40; /* fall through */
|
||||
case 5: b |= ((u64)end[4]) << 32; /* fall through */
|
||||
case 7: b |= ((u64)end[6]) << 48; fallthrough;
|
||||
case 6: b |= ((u64)end[5]) << 40; fallthrough;
|
||||
case 5: b |= ((u64)end[4]) << 32; fallthrough;
|
||||
case 4: b |= le32_to_cpup(data); break;
|
||||
case 3: b |= ((u64)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u64)end[2]) << 16; fallthrough;
|
||||
case 2: b |= le16_to_cpup(data); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
@@ -101,11 +101,11 @@ u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
|
||||
bytemask_from_count(left)));
|
||||
#else
|
||||
switch (left) {
|
||||
case 7: b |= ((u64)end[6]) << 48; /* fall through */
|
||||
case 6: b |= ((u64)end[5]) << 40; /* fall through */
|
||||
case 5: b |= ((u64)end[4]) << 32; /* fall through */
|
||||
case 7: b |= ((u64)end[6]) << 48; fallthrough;
|
||||
case 6: b |= ((u64)end[5]) << 40; fallthrough;
|
||||
case 5: b |= ((u64)end[4]) << 32; fallthrough;
|
||||
case 4: b |= get_unaligned_le32(end); break;
|
||||
case 3: b |= ((u64)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u64)end[2]) << 16; fallthrough;
|
||||
case 2: b |= get_unaligned_le16(end); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
@@ -268,11 +268,11 @@ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
|
||||
bytemask_from_count(left)));
|
||||
#else
|
||||
switch (left) {
|
||||
case 7: b |= ((u64)end[6]) << 48; /* fall through */
|
||||
case 6: b |= ((u64)end[5]) << 40; /* fall through */
|
||||
case 5: b |= ((u64)end[4]) << 32; /* fall through */
|
||||
case 7: b |= ((u64)end[6]) << 48; fallthrough;
|
||||
case 6: b |= ((u64)end[5]) << 40; fallthrough;
|
||||
case 5: b |= ((u64)end[4]) << 32; fallthrough;
|
||||
case 4: b |= le32_to_cpup(data); break;
|
||||
case 3: b |= ((u64)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u64)end[2]) << 16; fallthrough;
|
||||
case 2: b |= le16_to_cpup(data); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
@@ -301,11 +301,11 @@ u32 __hsiphash_unaligned(const void *data, size_t len,
|
||||
bytemask_from_count(left)));
|
||||
#else
|
||||
switch (left) {
|
||||
case 7: b |= ((u64)end[6]) << 48; /* fall through */
|
||||
case 6: b |= ((u64)end[5]) << 40; /* fall through */
|
||||
case 5: b |= ((u64)end[4]) << 32; /* fall through */
|
||||
case 7: b |= ((u64)end[6]) << 48; fallthrough;
|
||||
case 6: b |= ((u64)end[5]) << 40; fallthrough;
|
||||
case 5: b |= ((u64)end[4]) << 32; fallthrough;
|
||||
case 4: b |= get_unaligned_le32(end); break;
|
||||
case 3: b |= ((u64)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u64)end[2]) << 16; fallthrough;
|
||||
case 2: b |= get_unaligned_le16(end); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
@@ -431,7 +431,7 @@ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
|
||||
v0 ^= m;
|
||||
}
|
||||
switch (left) {
|
||||
case 3: b |= ((u32)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u32)end[2]) << 16; fallthrough;
|
||||
case 2: b |= le16_to_cpup(data); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
@@ -454,7 +454,7 @@ u32 __hsiphash_unaligned(const void *data, size_t len,
|
||||
v0 ^= m;
|
||||
}
|
||||
switch (left) {
|
||||
case 3: b |= ((u32)end[2]) << 16; /* fall through */
|
||||
case 3: b |= ((u32)end[2]) << 16; fallthrough;
|
||||
case 2: b |= get_unaligned_le16(end); break;
|
||||
case 1: b |= end[0];
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ startover:
|
||||
TOKEN_MISMATCH();
|
||||
|
||||
block_idx++;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case TS_FSM_ANY:
|
||||
if (next == NULL)
|
||||
|
||||
@@ -1265,7 +1265,7 @@ char *mac_address_string(char *buf, char *end, u8 *addr,
|
||||
|
||||
case 'R':
|
||||
reversed = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
separator = ':';
|
||||
@@ -1682,7 +1682,7 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
|
||||
switch (*(++fmt)) {
|
||||
case 'L':
|
||||
uc = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'l':
|
||||
index = guid_index;
|
||||
break;
|
||||
@@ -2219,7 +2219,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
case 'S':
|
||||
case 's':
|
||||
ptr = dereference_symbol_descriptor(ptr);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'B':
|
||||
return symbol_string(buf, end, ptr, spec, fmt);
|
||||
case 'R':
|
||||
@@ -2450,7 +2450,7 @@ qualifier:
|
||||
|
||||
case 'x':
|
||||
spec->flags |= SMALL;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case 'X':
|
||||
spec->base = 16;
|
||||
@@ -2459,6 +2459,7 @@ qualifier:
|
||||
case 'd':
|
||||
case 'i':
|
||||
spec->flags |= SIGN;
|
||||
break;
|
||||
case 'u':
|
||||
break;
|
||||
|
||||
@@ -2468,7 +2469,7 @@ qualifier:
|
||||
* utility, treat it as any other invalid or
|
||||
* unsupported format specifier.
|
||||
*/
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt);
|
||||
@@ -3411,10 +3412,10 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||
break;
|
||||
case 'i':
|
||||
base = 0;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'd':
|
||||
is_sign = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 'u':
|
||||
break;
|
||||
case '%':
|
||||
|
||||
@@ -1043,7 +1043,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
|
||||
|
||||
s->lzma2.sequence = SEQ_LZMA_PREPARE;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_LZMA_PREPARE:
|
||||
if (s->lzma2.compressed < RC_INIT_BYTES)
|
||||
@@ -1055,7 +1055,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
|
||||
s->lzma2.compressed -= RC_INIT_BYTES;
|
||||
s->lzma2.sequence = SEQ_LZMA_RUN;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_LZMA_RUN:
|
||||
/*
|
||||
|
||||
@@ -583,7 +583,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/* We need one byte of input to continue. */
|
||||
@@ -608,7 +608,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
@@ -620,7 +620,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS:
|
||||
ret = dec_block(s, b);
|
||||
@@ -629,7 +629,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
@@ -651,7 +651,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
if (s->check_type == XZ_CHECK_CRC32) {
|
||||
@@ -675,7 +675,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
while ((s->index.size + (b->in_pos - s->in_start))
|
||||
@@ -699,7 +699,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
ret = crc32_validate(s, b);
|
||||
@@ -709,7 +709,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
|
||||
@@ -396,7 +396,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
strm->adler = state->check = REVERSE(hold);
|
||||
INITBITS();
|
||||
state->mode = DICT;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DICT:
|
||||
if (state->havedict == 0) {
|
||||
RESTORE();
|
||||
@@ -404,10 +404,10 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
}
|
||||
strm->adler = state->check = zlib_adler32(0L, NULL, 0);
|
||||
state->mode = TYPE;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case TYPE:
|
||||
if (flush == Z_BLOCK) goto inf_leave;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case TYPEDO:
|
||||
INFLATE_TYPEDO_HOOK(strm, flush);
|
||||
if (state->last) {
|
||||
@@ -446,7 +446,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
state->length = (unsigned)hold & 0xffff;
|
||||
INITBITS();
|
||||
state->mode = COPY;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case COPY:
|
||||
copy = state->length;
|
||||
if (copy) {
|
||||
@@ -480,7 +480,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
#endif
|
||||
state->have = 0;
|
||||
state->mode = LENLENS;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case LENLENS:
|
||||
while (state->have < state->ncode) {
|
||||
NEEDBITS(3);
|
||||
@@ -501,7 +501,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
}
|
||||
state->have = 0;
|
||||
state->mode = CODELENS;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case CODELENS:
|
||||
while (state->have < state->nlen + state->ndist) {
|
||||
for (;;) {
|
||||
@@ -575,7 +575,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
break;
|
||||
}
|
||||
state->mode = LEN;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case LEN:
|
||||
if (have >= 6 && left >= 258) {
|
||||
RESTORE();
|
||||
@@ -615,7 +615,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
}
|
||||
state->extra = (unsigned)(this.op) & 15;
|
||||
state->mode = LENEXT;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case LENEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@@ -623,7 +623,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
DROPBITS(state->extra);
|
||||
}
|
||||
state->mode = DIST;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DIST:
|
||||
for (;;) {
|
||||
this = state->distcode[BITS(state->distbits)];
|
||||
@@ -649,7 +649,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
state->offset = (unsigned)this.val;
|
||||
state->extra = (unsigned)(this.op) & 15;
|
||||
state->mode = DISTEXT;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DISTEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@@ -669,7 +669,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
break;
|
||||
}
|
||||
state->mode = MATCH;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MATCH:
|
||||
if (left == 0) goto inf_leave;
|
||||
copy = out - left;
|
||||
@@ -720,7 +720,7 @@ int zlib_inflate(z_streamp strm, int flush)
|
||||
INITBITS();
|
||||
}
|
||||
state->mode = DONE;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case DONE:
|
||||
ret = Z_STREAM_END;
|
||||
goto inf_leave;
|
||||
|
||||
@@ -259,16 +259,17 @@ ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, s
|
||||
bitD->bitContainer = *(const BYTE *)(bitD->start);
|
||||
switch (srcSize) {
|
||||
case 7: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[6]) << (sizeof(bitD->bitContainer) * 8 - 16);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 6: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 5: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 4: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[3]) << 24;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 3: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[2]) << 16;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 2: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[1]) << 8;
|
||||
fallthrough;
|
||||
default:;
|
||||
}
|
||||
{
|
||||
|
||||
@@ -3182,7 +3182,7 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream *zcs, void *dst, size_t *
|
||||
zcs->outBuffFlushedSize = 0;
|
||||
zcs->stage = zcss_flush; /* pass-through to flush stage */
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case zcss_flush: {
|
||||
size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
|
||||
|
||||
@@ -442,7 +442,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize
|
||||
case set_repeat:
|
||||
if (dctx->litEntropy == 0)
|
||||
return ERROR(dictionary_corrupted);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case set_compressed:
|
||||
if (srcSize < 5)
|
||||
return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
|
||||
@@ -1768,7 +1768,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, c
|
||||
return 0;
|
||||
}
|
||||
dctx->expected = 0; /* not necessary to copy more */
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case ZSTDds_decodeFrameHeader:
|
||||
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
|
||||
@@ -2309,7 +2309,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
|
||||
switch (zds->stage) {
|
||||
case zdss_init:
|
||||
ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case zdss_loadHeader: {
|
||||
size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
|
||||
@@ -2376,7 +2376,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
|
||||
}
|
||||
zds->stage = zdss_read;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case zdss_read: {
|
||||
size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
|
||||
@@ -2405,7 +2405,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
|
||||
zds->stage = zdss_load;
|
||||
/* pass-through */
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case zdss_load: {
|
||||
size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
|
||||
@@ -2438,7 +2438,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
|
||||
/* pass-through */
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case zdss_flush: {
|
||||
size_t const toFlushSize = zds->outEnd - zds->outStart;
|
||||
|
||||
@@ -556,10 +556,11 @@ size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, si
|
||||
n = srcSize & ~3; /* join to mod 4 */
|
||||
switch (srcSize & 3) {
|
||||
case 3: HUF_encodeSymbol(&bitC, ip[n + 2], CTable); HUF_FLUSHBITS_2(&bitC);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 2: HUF_encodeSymbol(&bitC, ip[n + 1], CTable); HUF_FLUSHBITS_1(&bitC);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 1: HUF_encodeSymbol(&bitC, ip[n + 0], CTable); HUF_FLUSHBITS(&bitC);
|
||||
fallthrough;
|
||||
case 0:
|
||||
default:;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ DEFAULT_KUNITCONFIG_PATH = 'arch/um/configs/kunit_defconfig'
|
||||
BROKEN_ALLCONFIG_PATH = 'tools/testing/kunit/configs/broken_on_uml.config'
|
||||
OUTFILE_PATH = 'test.log'
|
||||
|
||||
def get_file_path(build_dir, default):
|
||||
if build_dir:
|
||||
default = os.path.join(build_dir, default)
|
||||
return default
|
||||
|
||||
class ConfigError(Exception):
|
||||
"""Represents an error trying to configure the Linux kernel."""
|
||||
|
||||
@@ -97,9 +102,7 @@ class LinuxSourceTreeOperations(object):
|
||||
|
||||
def linux_bin(self, params, timeout, build_dir):
|
||||
"""Runs the Linux UML binary. Must be named 'linux'."""
|
||||
linux_bin = './linux'
|
||||
if build_dir:
|
||||
linux_bin = os.path.join(build_dir, 'linux')
|
||||
linux_bin = get_file_path(build_dir, 'linux')
|
||||
outfile = get_outfile_path(build_dir)
|
||||
with open(outfile, 'w') as output:
|
||||
process = subprocess.Popen([linux_bin] + params,
|
||||
@@ -108,22 +111,13 @@ class LinuxSourceTreeOperations(object):
|
||||
process.wait(timeout)
|
||||
|
||||
def get_kconfig_path(build_dir):
|
||||
kconfig_path = KCONFIG_PATH
|
||||
if build_dir:
|
||||
kconfig_path = os.path.join(build_dir, KCONFIG_PATH)
|
||||
return kconfig_path
|
||||
return get_file_path(build_dir, KCONFIG_PATH)
|
||||
|
||||
def get_kunitconfig_path(build_dir):
|
||||
kunitconfig_path = KUNITCONFIG_PATH
|
||||
if build_dir:
|
||||
kunitconfig_path = os.path.join(build_dir, KUNITCONFIG_PATH)
|
||||
return kunitconfig_path
|
||||
return get_file_path(build_dir, KUNITCONFIG_PATH)
|
||||
|
||||
def get_outfile_path(build_dir):
|
||||
outfile_path = OUTFILE_PATH
|
||||
if build_dir:
|
||||
outfile_path = os.path.join(build_dir, OUTFILE_PATH)
|
||||
return outfile_path
|
||||
return get_file_path(build_dir, OUTFILE_PATH)
|
||||
|
||||
class LinuxSourceTree(object):
|
||||
"""Represents a Linux kernel source tree with KUnit tests."""
|
||||
|
||||
@@ -135,8 +135,8 @@ def parse_ok_not_ok_test_case(lines: List[str], test_case: TestCase) -> bool:
|
||||
else:
|
||||
return False
|
||||
|
||||
SUBTEST_DIAGNOSTIC = re.compile(r'^[\s]+# .*?: (.*)$')
|
||||
DIAGNOSTIC_CRASH_MESSAGE = 'kunit test case crashed!'
|
||||
SUBTEST_DIAGNOSTIC = re.compile(r'^[\s]+# (.*)$')
|
||||
DIAGNOSTIC_CRASH_MESSAGE = re.compile(r'^[\s]+# .*?: kunit test case crashed!$')
|
||||
|
||||
def parse_diagnostic(lines: List[str], test_case: TestCase) -> bool:
|
||||
save_non_diagnositic(lines, test_case)
|
||||
@@ -146,7 +146,8 @@ def parse_diagnostic(lines: List[str], test_case: TestCase) -> bool:
|
||||
match = SUBTEST_DIAGNOSTIC.match(line)
|
||||
if match:
|
||||
test_case.log.append(lines.pop(0))
|
||||
if match.group(1) == DIAGNOSTIC_CRASH_MESSAGE:
|
||||
crash_match = DIAGNOSTIC_CRASH_MESSAGE.match(line)
|
||||
if crash_match:
|
||||
test_case.status = TestStatus.TEST_CRASHED
|
||||
return True
|
||||
else:
|
||||
|
||||
@@ -66,6 +66,7 @@ endif
|
||||
TARGETS += tmpfs
|
||||
TARGETS += tpm2
|
||||
TARGETS += user
|
||||
TARGETS += vDSO
|
||||
TARGETS += vm
|
||||
TARGETS += x86
|
||||
TARGETS += zram
|
||||
|
||||
@@ -337,13 +337,13 @@ pid_t clone_into_cgroup(int cgroup_fd)
|
||||
#ifdef CLONE_ARGS_SIZE_VER2
|
||||
pid_t pid;
|
||||
|
||||
struct clone_args args = {
|
||||
struct __clone_args args = {
|
||||
.flags = CLONE_INTO_CGROUP,
|
||||
.exit_signal = SIGCHLD,
|
||||
.cgroup = cgroup_fd,
|
||||
};
|
||||
|
||||
pid = sys_clone3(&args, sizeof(struct clone_args));
|
||||
pid = sys_clone3(&args, sizeof(struct __clone_args));
|
||||
/*
|
||||
* Verify that this is a genuine test failure:
|
||||
* ENOSYS -> clone3() not available
|
||||
|
||||
@@ -11,22 +11,21 @@ LDLIBS += $(VAR_LDLIBS)
|
||||
|
||||
TEST_PROGS := gpio-mockup.sh
|
||||
TEST_FILES := gpio-mockup-sysfs.sh
|
||||
TEST_PROGS_EXTENDED := gpio-mockup-chardev
|
||||
|
||||
GPIODIR := $(realpath ../../../gpio)
|
||||
GPIOOBJ := gpio-utils.o
|
||||
|
||||
all: $(TEST_PROGS_EXTENDED)
|
||||
|
||||
override define CLEAN
|
||||
$(RM) $(TEST_PROGS_EXTENDED)
|
||||
$(MAKE) -C $(GPIODIR) OUTPUT=$(GPIODIR)/ clean
|
||||
endef
|
||||
TEST_GEN_PROGS_EXTENDED := gpio-mockup-chardev
|
||||
|
||||
KSFT_KHDR_INSTALL := 1
|
||||
include ../lib.mk
|
||||
|
||||
$(TEST_PROGS_EXTENDED): $(GPIODIR)/$(GPIOOBJ)
|
||||
GPIODIR := $(realpath ../../../gpio)
|
||||
GPIOOUT := $(OUTPUT)/tools-gpio/
|
||||
GPIOOBJ := $(GPIOOUT)/gpio-utils.o
|
||||
|
||||
$(GPIODIR)/$(GPIOOBJ):
|
||||
$(MAKE) OUTPUT=$(GPIODIR)/ -C $(GPIODIR)
|
||||
CLEAN += ; $(RM) -rf $(GPIOOUT)
|
||||
|
||||
$(TEST_GEN_PROGS_EXTENDED): $(GPIOOBJ)
|
||||
|
||||
$(GPIOOUT):
|
||||
mkdir -p $@
|
||||
|
||||
$(GPIOOBJ): $(GPIOOUT)
|
||||
$(MAKE) OUTPUT=$(GPIOOUT) -C $(GPIODIR)
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "../kselftest.h"
|
||||
|
||||
#define MSEC_PER_SEC 1000L
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
|
||||
void usage(char *name) {
|
||||
printf ("Usage: %s cpunum\n", name);
|
||||
}
|
||||
@@ -22,7 +26,7 @@ int main(int argc, char **argv) {
|
||||
long long tsc, old_tsc, new_tsc;
|
||||
long long aperf, old_aperf, new_aperf;
|
||||
long long mperf, old_mperf, new_mperf;
|
||||
struct timeb before, after;
|
||||
struct timespec before, after;
|
||||
long long int start, finish, total;
|
||||
cpu_set_t cpuset;
|
||||
|
||||
@@ -55,7 +59,10 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ftime(&before);
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &before) < 0) {
|
||||
perror("clock_gettime");
|
||||
return 1;
|
||||
}
|
||||
pread(fd, &old_tsc, sizeof(old_tsc), 0x10);
|
||||
pread(fd, &old_aperf, sizeof(old_mperf), 0xe7);
|
||||
pread(fd, &old_mperf, sizeof(old_aperf), 0xe8);
|
||||
@@ -64,7 +71,10 @@ int main(int argc, char **argv) {
|
||||
sqrt(i);
|
||||
}
|
||||
|
||||
ftime(&after);
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &after) < 0) {
|
||||
perror("clock_gettime");
|
||||
return 1;
|
||||
}
|
||||
pread(fd, &new_tsc, sizeof(new_tsc), 0x10);
|
||||
pread(fd, &new_aperf, sizeof(new_mperf), 0xe7);
|
||||
pread(fd, &new_mperf, sizeof(new_aperf), 0xe8);
|
||||
@@ -73,11 +83,11 @@ int main(int argc, char **argv) {
|
||||
aperf = new_aperf-old_aperf;
|
||||
mperf = new_mperf-old_mperf;
|
||||
|
||||
start = before.time*1000 + before.millitm;
|
||||
finish = after.time*1000 + after.millitm;
|
||||
start = before.tv_sec*MSEC_PER_SEC + before.tv_nsec/NSEC_PER_MSEC;
|
||||
finish = after.tv_sec*MSEC_PER_SEC + after.tv_nsec/NSEC_PER_MSEC;
|
||||
total = finish - start;
|
||||
|
||||
printf("runTime: %4.2f\n", 1.0*total/1000);
|
||||
printf("runTime: %4.2f\n", 1.0*total/MSEC_PER_SEC);
|
||||
printf("freq: %7.0f\n", tsc / (1.0*aperf / (1.0 * mperf)) / total);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/memfd.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/memfd.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -48,7 +48,7 @@ while true; do
|
||||
-l | --list)
|
||||
echo "$available"
|
||||
exit 0 ;;
|
||||
-n | --dry-run)
|
||||
-d | --dry-run)
|
||||
dryrun="echo"
|
||||
shift ;;
|
||||
-h | --help)
|
||||
|
||||
@@ -5,13 +5,16 @@ uname_M := $(shell uname -m 2>/dev/null || echo not)
|
||||
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
|
||||
|
||||
TEST_GEN_PROGS := $(OUTPUT)/vdso_test_gettimeofday $(OUTPUT)/vdso_test_getcpu
|
||||
ifeq ($(ARCH),x86)
|
||||
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_abi
|
||||
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_clock_getres
|
||||
ifeq ($(ARCH),$(filter $(ARCH),x86 x86_64))
|
||||
TEST_GEN_PROGS += $(OUTPUT)/vdso_standalone_test_x86
|
||||
endif
|
||||
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_correctness
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
CFLAGS := -std=gnu99
|
||||
CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
|
||||
LDFLAGS_vdso_test_correctness := -ldl
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
LDLIBS += -lgcc_s
|
||||
endif
|
||||
@@ -19,9 +22,14 @@ endif
|
||||
all: $(TEST_GEN_PROGS)
|
||||
$(OUTPUT)/vdso_test_gettimeofday: parse_vdso.c vdso_test_gettimeofday.c
|
||||
$(OUTPUT)/vdso_test_getcpu: parse_vdso.c vdso_test_getcpu.c
|
||||
$(OUTPUT)/vdso_test_abi: parse_vdso.c vdso_test_abi.c
|
||||
$(OUTPUT)/vdso_test_clock_getres: vdso_test_clock_getres.c
|
||||
$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
|
||||
$(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
|
||||
vdso_standalone_test_x86.c parse_vdso.c \
|
||||
-o $@
|
||||
|
||||
endif
|
||||
$(OUTPUT)/vdso_test_correctness: vdso_test_correctness.c
|
||||
$(CC) $(CFLAGS) \
|
||||
vdso_test_correctness.c \
|
||||
-o $@ \
|
||||
$(LDFLAGS_vdso_test_correctness)
|
||||
|
||||
92
tools/testing/selftests/vDSO/vdso_config.h
Normal file
92
tools/testing/selftests/vDSO/vdso_config.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* vdso_config.h: Configuration options for vDSO tests.
|
||||
* Copyright (c) 2019 Arm Ltd.
|
||||
*/
|
||||
#ifndef __VDSO_CONFIG_H__
|
||||
#define __VDSO_CONFIG_H__
|
||||
|
||||
/*
|
||||
* Each architecture exports its vDSO implementation with different names
|
||||
* and a different version from the others, so we need to handle it as a
|
||||
* special case.
|
||||
*/
|
||||
#if defined(__arm__)
|
||||
#define VDSO_VERSION 0
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined(__aarch64__)
|
||||
#define VDSO_VERSION 3
|
||||
#define VDSO_NAMES 0
|
||||
#elif defined(__powerpc__)
|
||||
#define VDSO_VERSION 1
|
||||
#define VDSO_NAMES 0
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined(__powerpc64__)
|
||||
#define VDSO_VERSION 1
|
||||
#define VDSO_NAMES 0
|
||||
#elif defined (__s390__)
|
||||
#define VDSO_VERSION 2
|
||||
#define VDSO_NAMES 0
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined (__s390X__)
|
||||
#define VDSO_VERSION 2
|
||||
#define VDSO_NAMES 0
|
||||
#elif defined(__mips__)
|
||||
#define VDSO_VERSION 0
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined(__sparc__)
|
||||
#define VDSO_VERSION 0
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined(__i386__)
|
||||
#define VDSO_VERSION 0
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#elif defined(__x86_64__)
|
||||
#define VDSO_VERSION 0
|
||||
#define VDSO_NAMES 1
|
||||
#elif defined(__riscv__)
|
||||
#define VDSO_VERSION 5
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#else /* nds32 */
|
||||
#define VDSO_VERSION 4
|
||||
#define VDSO_NAMES 1
|
||||
#define VDSO_32BIT 1
|
||||
#endif
|
||||
|
||||
static const char *versions[6] = {
|
||||
"LINUX_2.6",
|
||||
"LINUX_2.6.15",
|
||||
"LINUX_2.6.29",
|
||||
"LINUX_2.6.39",
|
||||
"LINUX_4",
|
||||
"LINUX_4.15",
|
||||
};
|
||||
|
||||
static const char *names[2][6] = {
|
||||
{
|
||||
"__kernel_gettimeofday",
|
||||
"__kernel_clock_gettime",
|
||||
"__kernel_time",
|
||||
"__kernel_clock_getres",
|
||||
"__kernel_getcpu",
|
||||
#if defined(VDSO_32BIT)
|
||||
"__kernel_clock_gettime64",
|
||||
#endif
|
||||
},
|
||||
{
|
||||
"__vdso_gettimeofday",
|
||||
"__vdso_clock_gettime",
|
||||
"__vdso_time",
|
||||
"__vdso_clock_getres",
|
||||
"__vdso_getcpu",
|
||||
#if defined(VDSO_32BIT)
|
||||
"__vdso_clock_gettime64",
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* __VDSO_CONFIG_H__ */
|
||||
244
tools/testing/selftests/vDSO/vdso_test_abi.c
Normal file
244
tools/testing/selftests/vDSO/vdso_test_abi.c
Normal file
@@ -0,0 +1,244 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* vdso_full_test.c: Sample code to test all the timers.
|
||||
* Copyright (c) 2019 Arm Ltd.
|
||||
*
|
||||
* Compile with:
|
||||
* gcc -std=gnu99 vdso_full_test.c parse_vdso.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <elf.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/time.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
#include "vdso_config.h"
|
||||
|
||||
extern void *vdso_sym(const char *version, const char *name);
|
||||
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
|
||||
extern void vdso_init_from_auxv(void *auxv);
|
||||
|
||||
static const char *version;
|
||||
static const char **name;
|
||||
|
||||
typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
|
||||
typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
|
||||
typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
|
||||
typedef time_t (*vdso_time_t)(time_t *t);
|
||||
|
||||
static int vdso_test_gettimeofday(void)
|
||||
{
|
||||
/* Find gettimeofday. */
|
||||
vdso_gettimeofday_t vdso_gettimeofday =
|
||||
(vdso_gettimeofday_t)vdso_sym(version, name[0]);
|
||||
|
||||
if (!vdso_gettimeofday) {
|
||||
printf("Could not find %s\n", name[0]);
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
long ret = vdso_gettimeofday(&tv, 0);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("The time is %lld.%06lld\n",
|
||||
(long long)tv.tv_sec, (long long)tv.tv_usec);
|
||||
} else {
|
||||
printf("%s failed\n", name[0]);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
static int vdso_test_clock_gettime(clockid_t clk_id)
|
||||
{
|
||||
/* Find clock_gettime. */
|
||||
vdso_clock_gettime_t vdso_clock_gettime =
|
||||
(vdso_clock_gettime_t)vdso_sym(version, name[1]);
|
||||
|
||||
if (!vdso_clock_gettime) {
|
||||
printf("Could not find %s\n", name[1]);
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
|
||||
struct timespec ts;
|
||||
long ret = vdso_clock_gettime(clk_id, &ts);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("The time is %lld.%06lld\n",
|
||||
(long long)ts.tv_sec, (long long)ts.tv_nsec);
|
||||
} else {
|
||||
printf("%s failed\n", name[1]);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
static int vdso_test_time(void)
|
||||
{
|
||||
/* Find time. */
|
||||
vdso_time_t vdso_time =
|
||||
(vdso_time_t)vdso_sym(version, name[2]);
|
||||
|
||||
if (!vdso_time) {
|
||||
printf("Could not find %s\n", name[2]);
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
|
||||
long ret = vdso_time(NULL);
|
||||
|
||||
if (ret > 0) {
|
||||
printf("The time in hours since January 1, 1970 is %lld\n",
|
||||
(long long)(ret / 3600));
|
||||
} else {
|
||||
printf("%s failed\n", name[2]);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
static int vdso_test_clock_getres(clockid_t clk_id)
|
||||
{
|
||||
/* Find clock_getres. */
|
||||
vdso_clock_getres_t vdso_clock_getres =
|
||||
(vdso_clock_getres_t)vdso_sym(version, name[3]);
|
||||
|
||||
if (!vdso_clock_getres) {
|
||||
printf("Could not find %s\n", name[3]);
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
|
||||
struct timespec ts, sys_ts;
|
||||
long ret = vdso_clock_getres(clk_id, &ts);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("The resolution is %lld %lld\n",
|
||||
(long long)ts.tv_sec, (long long)ts.tv_nsec);
|
||||
} else {
|
||||
printf("%s failed\n", name[3]);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
|
||||
|
||||
if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
|
||||
printf("%s failed\n", name[3]);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
const char *vdso_clock_name[12] = {
|
||||
"CLOCK_REALTIME",
|
||||
"CLOCK_MONOTONIC",
|
||||
"CLOCK_PROCESS_CPUTIME_ID",
|
||||
"CLOCK_THREAD_CPUTIME_ID",
|
||||
"CLOCK_MONOTONIC_RAW",
|
||||
"CLOCK_REALTIME_COARSE",
|
||||
"CLOCK_MONOTONIC_COARSE",
|
||||
"CLOCK_BOOTTIME",
|
||||
"CLOCK_REALTIME_ALARM",
|
||||
"CLOCK_BOOTTIME_ALARM",
|
||||
"CLOCK_SGI_CYCLE",
|
||||
"CLOCK_TAI",
|
||||
};
|
||||
|
||||
/*
|
||||
* This function calls vdso_test_clock_gettime and vdso_test_clock_getres
|
||||
* with different values for clock_id.
|
||||
*/
|
||||
static inline int vdso_test_clock(clockid_t clock_id)
|
||||
{
|
||||
int ret0, ret1;
|
||||
|
||||
ret0 = vdso_test_clock_gettime(clock_id);
|
||||
/* A skipped test is considered passed */
|
||||
if (ret0 == KSFT_SKIP)
|
||||
ret0 = KSFT_PASS;
|
||||
|
||||
ret1 = vdso_test_clock_getres(clock_id);
|
||||
/* A skipped test is considered passed */
|
||||
if (ret1 == KSFT_SKIP)
|
||||
ret1 = KSFT_PASS;
|
||||
|
||||
ret0 += ret1;
|
||||
|
||||
printf("clock_id: %s", vdso_clock_name[clock_id]);
|
||||
|
||||
if (ret0 > 0)
|
||||
printf(" [FAIL]\n");
|
||||
else
|
||||
printf(" [PASS]\n");
|
||||
|
||||
return ret0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
|
||||
int ret;
|
||||
|
||||
if (!sysinfo_ehdr) {
|
||||
printf("AT_SYSINFO_EHDR is not present!\n");
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
|
||||
version = versions[VDSO_VERSION];
|
||||
name = (const char **)&names[VDSO_NAMES];
|
||||
|
||||
printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
|
||||
|
||||
vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
|
||||
|
||||
ret = vdso_test_gettimeofday();
|
||||
|
||||
#if _POSIX_TIMERS > 0
|
||||
|
||||
#ifdef CLOCK_REALTIME
|
||||
ret += vdso_test_clock(CLOCK_REALTIME);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
ret += vdso_test_clock(CLOCK_BOOTTIME);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_TAI
|
||||
ret += vdso_test_clock(CLOCK_TAI);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
ret += vdso_test_time();
|
||||
|
||||
if (ret > 0)
|
||||
return KSFT_FAIL;
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
124
tools/testing/selftests/vDSO/vdso_test_clock_getres.c
Normal file
124
tools/testing/selftests/vDSO/vdso_test_clock_getres.c
Normal file
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
||||
/*
|
||||
* vdso_clock_getres.c: Sample code to test clock_getres.
|
||||
* Copyright (c) 2019 Arm Ltd.
|
||||
*
|
||||
* Compile with:
|
||||
* gcc -std=gnu99 vdso_clock_getres.c
|
||||
*
|
||||
* Tested on ARM, ARM64, MIPS32, x86 (32-bit and 64-bit),
|
||||
* Power (32-bit and 64-bit), S390x (32-bit and 64-bit).
|
||||
* Might work on other architectures.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <elf.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
static long syscall_clock_getres(clockid_t _clkid, struct timespec *_ts)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = syscall(SYS_clock_getres, _clkid, _ts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *vdso_clock_name[12] = {
|
||||
"CLOCK_REALTIME",
|
||||
"CLOCK_MONOTONIC",
|
||||
"CLOCK_PROCESS_CPUTIME_ID",
|
||||
"CLOCK_THREAD_CPUTIME_ID",
|
||||
"CLOCK_MONOTONIC_RAW",
|
||||
"CLOCK_REALTIME_COARSE",
|
||||
"CLOCK_MONOTONIC_COARSE",
|
||||
"CLOCK_BOOTTIME",
|
||||
"CLOCK_REALTIME_ALARM",
|
||||
"CLOCK_BOOTTIME_ALARM",
|
||||
"CLOCK_SGI_CYCLE",
|
||||
"CLOCK_TAI",
|
||||
};
|
||||
|
||||
/*
|
||||
* This function calls clock_getres in vdso and by system call
|
||||
* with different values for clock_id.
|
||||
*
|
||||
* Example of output:
|
||||
*
|
||||
* clock_id: CLOCK_REALTIME [PASS]
|
||||
* clock_id: CLOCK_BOOTTIME [PASS]
|
||||
* clock_id: CLOCK_TAI [PASS]
|
||||
* clock_id: CLOCK_REALTIME_COARSE [PASS]
|
||||
* clock_id: CLOCK_MONOTONIC [PASS]
|
||||
* clock_id: CLOCK_MONOTONIC_RAW [PASS]
|
||||
* clock_id: CLOCK_MONOTONIC_COARSE [PASS]
|
||||
*/
|
||||
static inline int vdso_test_clock(unsigned int clock_id)
|
||||
{
|
||||
struct timespec x, y;
|
||||
|
||||
printf("clock_id: %s", vdso_clock_name[clock_id]);
|
||||
clock_getres(clock_id, &x);
|
||||
syscall_clock_getres(clock_id, &y);
|
||||
|
||||
if ((x.tv_sec != y.tv_sec) || (x.tv_nsec != y.tv_nsec)) {
|
||||
printf(" [FAIL]\n");
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
printf(" [PASS]\n");
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if _POSIX_TIMERS > 0
|
||||
|
||||
#ifdef CLOCK_REALTIME
|
||||
ret = vdso_test_clock(CLOCK_REALTIME);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
ret += vdso_test_clock(CLOCK_BOOTTIME);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_TAI
|
||||
ret += vdso_test_clock(CLOCK_TAI);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
|
||||
#endif
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
if (ret > 0)
|
||||
return KSFT_FAIL;
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "vdso_config.h"
|
||||
|
||||
static const char **name;
|
||||
|
||||
#ifndef SYS_getcpu
|
||||
# ifdef __x86_64__
|
||||
# define SYS_getcpu 309
|
||||
@@ -27,6 +31,17 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __NR_clock_gettime64
|
||||
#define __NR_clock_gettime64 403
|
||||
#endif
|
||||
|
||||
#ifndef __kernel_timespec
|
||||
struct __kernel_timespec {
|
||||
long long tv_sec;
|
||||
long long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* max length of lines in /proc/self/maps - anything longer is skipped here */
|
||||
#define MAPS_LINE_LEN 128
|
||||
|
||||
@@ -36,6 +51,10 @@ typedef int (*vgettime_t)(clockid_t, struct timespec *);
|
||||
|
||||
vgettime_t vdso_clock_gettime;
|
||||
|
||||
typedef int (*vgettime64_t)(clockid_t, struct __kernel_timespec *);
|
||||
|
||||
vgettime64_t vdso_clock_gettime64;
|
||||
|
||||
typedef long (*vgtod_t)(struct timeval *tv, struct timezone *tz);
|
||||
|
||||
vgtod_t vdso_gettimeofday;
|
||||
@@ -99,17 +118,23 @@ static void fill_function_pointers()
|
||||
return;
|
||||
}
|
||||
|
||||
vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu");
|
||||
vdso_getcpu = (getcpu_t)dlsym(vdso, name[4]);
|
||||
if (!vdso_getcpu)
|
||||
printf("Warning: failed to find getcpu in vDSO\n");
|
||||
|
||||
vgetcpu = (getcpu_t) vsyscall_getcpu();
|
||||
|
||||
vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
|
||||
vdso_clock_gettime = (vgettime_t)dlsym(vdso, name[1]);
|
||||
if (!vdso_clock_gettime)
|
||||
printf("Warning: failed to find clock_gettime in vDSO\n");
|
||||
|
||||
vdso_gettimeofday = (vgtod_t)dlsym(vdso, "__vdso_gettimeofday");
|
||||
#if defined(VDSO_32BIT)
|
||||
vdso_clock_gettime64 = (vgettime64_t)dlsym(vdso, name[5]);
|
||||
if (!vdso_clock_gettime64)
|
||||
printf("Warning: failed to find clock_gettime64 in vDSO\n");
|
||||
#endif
|
||||
|
||||
vdso_gettimeofday = (vgtod_t)dlsym(vdso, name[0]);
|
||||
if (!vdso_gettimeofday)
|
||||
printf("Warning: failed to find gettimeofday in vDSO\n");
|
||||
|
||||
@@ -126,6 +151,11 @@ static inline int sys_clock_gettime(clockid_t id, struct timespec *ts)
|
||||
return syscall(__NR_clock_gettime, id, ts);
|
||||
}
|
||||
|
||||
static inline int sys_clock_gettime64(clockid_t id, struct __kernel_timespec *ts)
|
||||
{
|
||||
return syscall(__NR_clock_gettime64, id, ts);
|
||||
}
|
||||
|
||||
static inline int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
return syscall(__NR_gettimeofday, tv, tz);
|
||||
@@ -191,6 +221,15 @@ static bool ts_leq(const struct timespec *a, const struct timespec *b)
|
||||
return a->tv_nsec <= b->tv_nsec;
|
||||
}
|
||||
|
||||
static bool ts64_leq(const struct __kernel_timespec *a,
|
||||
const struct __kernel_timespec *b)
|
||||
{
|
||||
if (a->tv_sec != b->tv_sec)
|
||||
return a->tv_sec < b->tv_sec;
|
||||
else
|
||||
return a->tv_nsec <= b->tv_nsec;
|
||||
}
|
||||
|
||||
static bool tv_leq(const struct timeval *a, const struct timeval *b)
|
||||
{
|
||||
if (a->tv_sec != b->tv_sec)
|
||||
@@ -254,7 +293,10 @@ static void test_one_clock_gettime(int clock, const char *name)
|
||||
if (!ts_leq(&start, &vdso) || !ts_leq(&vdso, &end)) {
|
||||
printf("[FAIL]\tTimes are out of sequence\n");
|
||||
nerrs++;
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[OK]\tTest Passed.\n");
|
||||
}
|
||||
|
||||
static void test_clock_gettime(void)
|
||||
@@ -275,6 +317,70 @@ static void test_clock_gettime(void)
|
||||
test_one_clock_gettime(INT_MAX, "invalid");
|
||||
}
|
||||
|
||||
static void test_one_clock_gettime64(int clock, const char *name)
|
||||
{
|
||||
struct __kernel_timespec start, vdso, end;
|
||||
int vdso_ret, end_ret;
|
||||
|
||||
printf("[RUN]\tTesting clock_gettime64 for clock %s (%d)...\n", name, clock);
|
||||
|
||||
if (sys_clock_gettime64(clock, &start) < 0) {
|
||||
if (errno == EINVAL) {
|
||||
vdso_ret = vdso_clock_gettime64(clock, &vdso);
|
||||
if (vdso_ret == -EINVAL) {
|
||||
printf("[OK]\tNo such clock.\n");
|
||||
} else {
|
||||
printf("[FAIL]\tNo such clock, but __vdso_clock_gettime64 returned %d\n", vdso_ret);
|
||||
nerrs++;
|
||||
}
|
||||
} else {
|
||||
printf("[WARN]\t clock_gettime64(%d) syscall returned error %d\n", clock, errno);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
vdso_ret = vdso_clock_gettime64(clock, &vdso);
|
||||
end_ret = sys_clock_gettime64(clock, &end);
|
||||
|
||||
if (vdso_ret != 0 || end_ret != 0) {
|
||||
printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n",
|
||||
vdso_ret, errno);
|
||||
nerrs++;
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\t%llu.%09ld %llu.%09ld %llu.%09ld\n",
|
||||
(unsigned long long)start.tv_sec, start.tv_nsec,
|
||||
(unsigned long long)vdso.tv_sec, vdso.tv_nsec,
|
||||
(unsigned long long)end.tv_sec, end.tv_nsec);
|
||||
|
||||
if (!ts64_leq(&start, &vdso) || !ts64_leq(&vdso, &end)) {
|
||||
printf("[FAIL]\tTimes are out of sequence\n");
|
||||
nerrs++;
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[OK]\tTest Passed.\n");
|
||||
}
|
||||
|
||||
static void test_clock_gettime64(void)
|
||||
{
|
||||
if (!vdso_clock_gettime64) {
|
||||
printf("[SKIP]\tNo vDSO, so skipping clock_gettime64() tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int clock = 0; clock < sizeof(clocknames) / sizeof(clocknames[0]);
|
||||
clock++) {
|
||||
test_one_clock_gettime64(clock, clocknames[clock]);
|
||||
}
|
||||
|
||||
/* Also test some invalid clock ids */
|
||||
test_one_clock_gettime64(-1, "invalid");
|
||||
test_one_clock_gettime64(INT_MIN, "invalid");
|
||||
test_one_clock_gettime64(INT_MAX, "invalid");
|
||||
}
|
||||
|
||||
static void test_gettimeofday(void)
|
||||
{
|
||||
struct timeval start, vdso, end;
|
||||
@@ -327,9 +433,12 @@ static void test_gettimeofday(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
name = (const char **)&names[VDSO_NAMES];
|
||||
|
||||
fill_function_pointers();
|
||||
|
||||
test_clock_gettime();
|
||||
test_clock_gettime64();
|
||||
test_gettimeofday();
|
||||
|
||||
/*
|
||||
@@ -906,7 +906,7 @@ static int faulting_process(int signal_test)
|
||||
count_verify[nr]);
|
||||
}
|
||||
/*
|
||||
* Trigger write protection if there is by writting
|
||||
* Trigger write protection if there is by writing
|
||||
* the same value back.
|
||||
*/
|
||||
*area_count(area_dst, nr) = count;
|
||||
@@ -934,7 +934,7 @@ static int faulting_process(int signal_test)
|
||||
count_verify[nr]); exit(1);
|
||||
}
|
||||
/*
|
||||
* Trigger write protection if there is by writting
|
||||
* Trigger write protection if there is by writing
|
||||
* the same value back.
|
||||
*/
|
||||
*area_count(area_dst, nr) = count;
|
||||
|
||||
@@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie)
|
||||
|
||||
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
|
||||
check_initial_reg_state sigreturn iopl ioperm \
|
||||
test_vdso test_vsyscall mov_ss_trap \
|
||||
test_vsyscall mov_ss_trap \
|
||||
syscall_arg_fault fsgsbase_restore
|
||||
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \
|
||||
test_FCMOV test_FCOMI test_FISTTP \
|
||||
|
||||
Reference in New Issue
Block a user