xref: /openbmc/linux/fs/ext4/inode-test.c (revision 1bc33893)
11cbeab1bSIurii Zaikin // SPDX-License-Identifier: GPL-2.0
21cbeab1bSIurii Zaikin /*
31cbeab1bSIurii Zaikin  * KUnit test of ext4 inode that verify the seconds part of [a/c/m]
41cbeab1bSIurii Zaikin  * timestamps in ext4 inode structs are decoded correctly.
51cbeab1bSIurii Zaikin  */
61cbeab1bSIurii Zaikin 
71cbeab1bSIurii Zaikin #include <kunit/test.h>
81cbeab1bSIurii Zaikin #include <linux/kernel.h>
91cbeab1bSIurii Zaikin #include <linux/time64.h>
101cbeab1bSIurii Zaikin 
111cbeab1bSIurii Zaikin #include "ext4.h"
121cbeab1bSIurii Zaikin 
131cbeab1bSIurii Zaikin /*
141cbeab1bSIurii Zaikin  * For constructing the nonnegative timestamp lower bound value.
151cbeab1bSIurii Zaikin  * binary: 00000000 00000000 00000000 00000000
161cbeab1bSIurii Zaikin  */
171cbeab1bSIurii Zaikin #define LOWER_MSB_0 0L
181cbeab1bSIurii Zaikin /*
191cbeab1bSIurii Zaikin  * For constructing the nonnegative timestamp upper bound value.
201cbeab1bSIurii Zaikin  * binary: 01111111 11111111 11111111 11111111
211cbeab1bSIurii Zaikin  *
221cbeab1bSIurii Zaikin  */
231cbeab1bSIurii Zaikin #define UPPER_MSB_0 0x7fffffffL
241cbeab1bSIurii Zaikin /*
251cbeab1bSIurii Zaikin  * For constructing the negative timestamp lower bound value.
261cbeab1bSIurii Zaikin  * binary: 10000000 00000000 00000000 00000000
271cbeab1bSIurii Zaikin  */
2839101b22SIurii Zaikin #define LOWER_MSB_1 (-(UPPER_MSB_0) - 1L)  /* avoid overflow */
291cbeab1bSIurii Zaikin /*
301cbeab1bSIurii Zaikin  * For constructing the negative timestamp upper bound value.
311cbeab1bSIurii Zaikin  * binary: 11111111 11111111 11111111 11111111
321cbeab1bSIurii Zaikin  */
331cbeab1bSIurii Zaikin #define UPPER_MSB_1 (-1L)
341cbeab1bSIurii Zaikin /*
351cbeab1bSIurii Zaikin  * Upper bound for nanoseconds value supported by the encoding.
361cbeab1bSIurii Zaikin  * binary: 00111111 11111111 11111111 11111111
371cbeab1bSIurii Zaikin  */
381cbeab1bSIurii Zaikin #define MAX_NANOSECONDS ((1L << 30) - 1)
391cbeab1bSIurii Zaikin 
401cbeab1bSIurii Zaikin #define CASE_NAME_FORMAT "%s: msb:%x lower_bound:%x extra_bits: %x"
411cbeab1bSIurii Zaikin 
421cbeab1bSIurii Zaikin #define LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE\
431cbeab1bSIurii Zaikin 	"1901-12-13 Lower bound of 32bit < 0 timestamp, no extra bits"
441cbeab1bSIurii Zaikin #define UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE\
451cbeab1bSIurii Zaikin 	"1969-12-31 Upper bound of 32bit < 0 timestamp, no extra bits"
461cbeab1bSIurii Zaikin #define LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\
471cbeab1bSIurii Zaikin 	"1970-01-01 Lower bound of 32bit >=0 timestamp, no extra bits"
481cbeab1bSIurii Zaikin #define UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\
491cbeab1bSIurii Zaikin 	"2038-01-19 Upper bound of 32bit >=0 timestamp, no extra bits"
501cbeab1bSIurii Zaikin #define LOWER_BOUND_NEG_LO_1_CASE\
511cbeab1bSIurii Zaikin 	"2038-01-19 Lower bound of 32bit <0 timestamp, lo extra sec bit on"
521cbeab1bSIurii Zaikin #define UPPER_BOUND_NEG_LO_1_CASE\
531cbeab1bSIurii Zaikin 	"2106-02-07 Upper bound of 32bit <0 timestamp, lo extra sec bit on"
541cbeab1bSIurii Zaikin #define LOWER_BOUND_NONNEG_LO_1_CASE\
551cbeab1bSIurii Zaikin 	"2106-02-07 Lower bound of 32bit >=0 timestamp, lo extra sec bit on"
561cbeab1bSIurii Zaikin #define UPPER_BOUND_NONNEG_LO_1_CASE\
571cbeab1bSIurii Zaikin 	"2174-02-25 Upper bound of 32bit >=0 timestamp, lo extra sec bit on"
581cbeab1bSIurii Zaikin #define LOWER_BOUND_NEG_HI_1_CASE\
591cbeab1bSIurii Zaikin 	"2174-02-25 Lower bound of 32bit <0 timestamp, hi extra sec bit on"
601cbeab1bSIurii Zaikin #define UPPER_BOUND_NEG_HI_1_CASE\
611cbeab1bSIurii Zaikin 	"2242-03-16 Upper bound of 32bit <0 timestamp, hi extra sec bit on"
621cbeab1bSIurii Zaikin #define LOWER_BOUND_NONNEG_HI_1_CASE\
631cbeab1bSIurii Zaikin 	"2242-03-16 Lower bound of 32bit >=0 timestamp, hi extra sec bit on"
641cbeab1bSIurii Zaikin #define UPPER_BOUND_NONNEG_HI_1_CASE\
651cbeab1bSIurii Zaikin 	"2310-04-04 Upper bound of 32bit >=0 timestamp, hi extra sec bit on"
661cbeab1bSIurii Zaikin #define UPPER_BOUND_NONNEG_HI_1_NS_1_CASE\
671cbeab1bSIurii Zaikin 	"2310-04-04 Upper bound of 32bit>=0 timestamp, hi extra sec bit 1. 1 ns"
681cbeab1bSIurii Zaikin #define LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE\
691cbeab1bSIurii Zaikin 	"2378-04-22 Lower bound of 32bit>= timestamp. Extra sec bits 1. Max ns"
701cbeab1bSIurii Zaikin #define LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE\
711cbeab1bSIurii Zaikin 	"2378-04-22 Lower bound of 32bit >=0 timestamp. All extra sec bits on"
721cbeab1bSIurii Zaikin #define UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE\
731cbeab1bSIurii Zaikin 	"2446-05-10 Upper bound of 32bit >=0 timestamp. All extra sec bits on"
741cbeab1bSIurii Zaikin 
751cbeab1bSIurii Zaikin struct timestamp_expectation {
761cbeab1bSIurii Zaikin 	const char *test_case_name;
771cbeab1bSIurii Zaikin 	struct timespec64 expected;
781cbeab1bSIurii Zaikin 	u32 extra_bits;
791cbeab1bSIurii Zaikin 	bool msb_set;
801cbeab1bSIurii Zaikin 	bool lower_bound;
811cbeab1bSIurii Zaikin };
821cbeab1bSIurii Zaikin 
835f6b99d0SArpitha Raghunandan static const struct timestamp_expectation test_data[] = {
841cbeab1bSIurii Zaikin 	{
851cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE,
861cbeab1bSIurii Zaikin 		.msb_set = true,
871cbeab1bSIurii Zaikin 		.lower_bound = true,
881cbeab1bSIurii Zaikin 		.extra_bits = 0,
891cbeab1bSIurii Zaikin 		.expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L},
901cbeab1bSIurii Zaikin 	},
911cbeab1bSIurii Zaikin 
921cbeab1bSIurii Zaikin 	{
931cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE,
941cbeab1bSIurii Zaikin 		.msb_set = true,
951cbeab1bSIurii Zaikin 		.lower_bound = false,
961cbeab1bSIurii Zaikin 		.extra_bits = 0,
971cbeab1bSIurii Zaikin 		.expected = {.tv_sec = -1LL, .tv_nsec = 0L},
981cbeab1bSIurii Zaikin 	},
991cbeab1bSIurii Zaikin 
1001cbeab1bSIurii Zaikin 	{
1011cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
1021cbeab1bSIurii Zaikin 		.msb_set = false,
1031cbeab1bSIurii Zaikin 		.lower_bound = true,
1041cbeab1bSIurii Zaikin 		.extra_bits = 0,
1051cbeab1bSIurii Zaikin 		.expected = {0LL, 0L},
1061cbeab1bSIurii Zaikin 	},
1071cbeab1bSIurii Zaikin 
1081cbeab1bSIurii Zaikin 	{
1091cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
1101cbeab1bSIurii Zaikin 		.msb_set = false,
1111cbeab1bSIurii Zaikin 		.lower_bound = false,
1121cbeab1bSIurii Zaikin 		.extra_bits = 0,
1131cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L},
1141cbeab1bSIurii Zaikin 	},
1151cbeab1bSIurii Zaikin 
1161cbeab1bSIurii Zaikin 	{
1171cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NEG_LO_1_CASE,
1181cbeab1bSIurii Zaikin 		.msb_set = true,
1191cbeab1bSIurii Zaikin 		.lower_bound = true,
1201cbeab1bSIurii Zaikin 		.extra_bits = 1,
1211cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L},
1221cbeab1bSIurii Zaikin 	},
1231cbeab1bSIurii Zaikin 
1241cbeab1bSIurii Zaikin 	{
1251cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NEG_LO_1_CASE,
1261cbeab1bSIurii Zaikin 		.msb_set = true,
1271cbeab1bSIurii Zaikin 		.lower_bound = false,
1281cbeab1bSIurii Zaikin 		.extra_bits = 1,
1291cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L},
1301cbeab1bSIurii Zaikin 	},
1311cbeab1bSIurii Zaikin 
1321cbeab1bSIurii Zaikin 	{
1331cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE,
1341cbeab1bSIurii Zaikin 		.msb_set = false,
1351cbeab1bSIurii Zaikin 		.lower_bound = true,
1361cbeab1bSIurii Zaikin 		.extra_bits = 1,
1371cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L},
1381cbeab1bSIurii Zaikin 	},
1391cbeab1bSIurii Zaikin 
1401cbeab1bSIurii Zaikin 	{
1411cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE,
1421cbeab1bSIurii Zaikin 		.msb_set = false,
1431cbeab1bSIurii Zaikin 		.lower_bound = false,
1441cbeab1bSIurii Zaikin 		.extra_bits = 1,
1451cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L},
1461cbeab1bSIurii Zaikin 	},
1471cbeab1bSIurii Zaikin 
1481cbeab1bSIurii Zaikin 	{
1491cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NEG_HI_1_CASE,
1501cbeab1bSIurii Zaikin 		.msb_set = true,
1511cbeab1bSIurii Zaikin 		.lower_bound = true,
1521cbeab1bSIurii Zaikin 		.extra_bits =  2,
1531cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L},
1541cbeab1bSIurii Zaikin 	},
1551cbeab1bSIurii Zaikin 
1561cbeab1bSIurii Zaikin 	{
1571cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NEG_HI_1_CASE,
1581cbeab1bSIurii Zaikin 		.msb_set = true,
1591cbeab1bSIurii Zaikin 		.lower_bound = false,
1601cbeab1bSIurii Zaikin 		.extra_bits = 2,
1611cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L},
1621cbeab1bSIurii Zaikin 	},
1631cbeab1bSIurii Zaikin 
1641cbeab1bSIurii Zaikin 	{
1651cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE,
1661cbeab1bSIurii Zaikin 		.msb_set = false,
1671cbeab1bSIurii Zaikin 		.lower_bound = true,
1681cbeab1bSIurii Zaikin 		.extra_bits = 2,
1691cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L},
1701cbeab1bSIurii Zaikin 	},
1711cbeab1bSIurii Zaikin 
1721cbeab1bSIurii Zaikin 	{
1731cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE,
1741cbeab1bSIurii Zaikin 		.msb_set = false,
1751cbeab1bSIurii Zaikin 		.lower_bound = false,
1761cbeab1bSIurii Zaikin 		.extra_bits = 2,
1771cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L},
1781cbeab1bSIurii Zaikin 	},
1791cbeab1bSIurii Zaikin 
1801cbeab1bSIurii Zaikin 	{
1811cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE,
1821cbeab1bSIurii Zaikin 		.msb_set = false,
1831cbeab1bSIurii Zaikin 		.lower_bound = false,
1841cbeab1bSIurii Zaikin 		.extra_bits = 6,
1851cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L},
1861cbeab1bSIurii Zaikin 	},
1871cbeab1bSIurii Zaikin 
1881cbeab1bSIurii Zaikin 	{
1891cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE,
1901cbeab1bSIurii Zaikin 		.msb_set = false,
1911cbeab1bSIurii Zaikin 		.lower_bound = true,
1921cbeab1bSIurii Zaikin 		.extra_bits = 0xFFFFFFFF,
1931cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x300000000LL,
1941cbeab1bSIurii Zaikin 			     .tv_nsec = MAX_NANOSECONDS},
1951cbeab1bSIurii Zaikin 	},
1961cbeab1bSIurii Zaikin 
1971cbeab1bSIurii Zaikin 	{
1981cbeab1bSIurii Zaikin 		.test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
1991cbeab1bSIurii Zaikin 		.msb_set = false,
2001cbeab1bSIurii Zaikin 		.lower_bound = true,
2011cbeab1bSIurii Zaikin 		.extra_bits = 3,
2021cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L},
2031cbeab1bSIurii Zaikin 	},
2041cbeab1bSIurii Zaikin 
2051cbeab1bSIurii Zaikin 	{
2061cbeab1bSIurii Zaikin 		.test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
2071cbeab1bSIurii Zaikin 		.msb_set = false,
2081cbeab1bSIurii Zaikin 		.lower_bound = false,
2091cbeab1bSIurii Zaikin 		.extra_bits = 3,
2101cbeab1bSIurii Zaikin 		.expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L},
2111cbeab1bSIurii Zaikin 	}
2121cbeab1bSIurii Zaikin };
2131cbeab1bSIurii Zaikin 
timestamp_expectation_to_desc(const struct timestamp_expectation * t,char * desc)2145f6b99d0SArpitha Raghunandan static void timestamp_expectation_to_desc(const struct timestamp_expectation *t,
2155f6b99d0SArpitha Raghunandan 					  char *desc)
2165f6b99d0SArpitha Raghunandan {
2175f6b99d0SArpitha Raghunandan 	strscpy(desc, t->test_case_name, KUNIT_PARAM_DESC_SIZE);
2185f6b99d0SArpitha Raghunandan }
2191cbeab1bSIurii Zaikin 
2205f6b99d0SArpitha Raghunandan KUNIT_ARRAY_PARAM(ext4_inode, test_data, timestamp_expectation_to_desc);
2215f6b99d0SArpitha Raghunandan 
get_32bit_time(const struct timestamp_expectation * const test)2225f6b99d0SArpitha Raghunandan static time64_t get_32bit_time(const struct timestamp_expectation * const test)
2235f6b99d0SArpitha Raghunandan {
2245f6b99d0SArpitha Raghunandan 	if (test->msb_set) {
2255f6b99d0SArpitha Raghunandan 		if (test->lower_bound)
2265f6b99d0SArpitha Raghunandan 			return LOWER_MSB_1;
2275f6b99d0SArpitha Raghunandan 
2285f6b99d0SArpitha Raghunandan 		return UPPER_MSB_1;
2295f6b99d0SArpitha Raghunandan 	}
2305f6b99d0SArpitha Raghunandan 
2315f6b99d0SArpitha Raghunandan 	if (test->lower_bound)
2325f6b99d0SArpitha Raghunandan 		return LOWER_MSB_0;
2335f6b99d0SArpitha Raghunandan 	return UPPER_MSB_0;
2345f6b99d0SArpitha Raghunandan }
2355f6b99d0SArpitha Raghunandan 
2365f6b99d0SArpitha Raghunandan 
2375f6b99d0SArpitha Raghunandan /*
2385f6b99d0SArpitha Raghunandan  *  Test data is derived from the table in the Inode Timestamps section of
2395f6b99d0SArpitha Raghunandan  *  Documentation/filesystems/ext4/inodes.rst.
2405f6b99d0SArpitha Raghunandan  */
inode_test_xtimestamp_decoding(struct kunit * test)2415f6b99d0SArpitha Raghunandan static void inode_test_xtimestamp_decoding(struct kunit *test)
2425f6b99d0SArpitha Raghunandan {
2435f6b99d0SArpitha Raghunandan 	struct timespec64 timestamp;
2445f6b99d0SArpitha Raghunandan 
2455f6b99d0SArpitha Raghunandan 	struct timestamp_expectation *test_param =
2465f6b99d0SArpitha Raghunandan 			(struct timestamp_expectation *)(test->param_value);
2475f6b99d0SArpitha Raghunandan 
248*1bc33893SJeff Layton 	timestamp = ext4_decode_extra_time(
249*1bc33893SJeff Layton 				cpu_to_le32(get_32bit_time(test_param)),
2505f6b99d0SArpitha Raghunandan 				cpu_to_le32(test_param->extra_bits));
2511cbeab1bSIurii Zaikin 
2521cbeab1bSIurii Zaikin 	KUNIT_EXPECT_EQ_MSG(test,
2535f6b99d0SArpitha Raghunandan 			    test_param->expected.tv_sec,
2541cbeab1bSIurii Zaikin 			    timestamp.tv_sec,
2551cbeab1bSIurii Zaikin 			    CASE_NAME_FORMAT,
2565f6b99d0SArpitha Raghunandan 			    test_param->test_case_name,
2575f6b99d0SArpitha Raghunandan 			    test_param->msb_set,
2585f6b99d0SArpitha Raghunandan 			    test_param->lower_bound,
2595f6b99d0SArpitha Raghunandan 			    test_param->extra_bits);
2601cbeab1bSIurii Zaikin 	KUNIT_EXPECT_EQ_MSG(test,
2615f6b99d0SArpitha Raghunandan 			    test_param->expected.tv_nsec,
2621cbeab1bSIurii Zaikin 			    timestamp.tv_nsec,
2631cbeab1bSIurii Zaikin 			    CASE_NAME_FORMAT,
2645f6b99d0SArpitha Raghunandan 			    test_param->test_case_name,
2655f6b99d0SArpitha Raghunandan 			    test_param->msb_set,
2665f6b99d0SArpitha Raghunandan 			    test_param->lower_bound,
2675f6b99d0SArpitha Raghunandan 			    test_param->extra_bits);
2681cbeab1bSIurii Zaikin }
2691cbeab1bSIurii Zaikin 
2701cbeab1bSIurii Zaikin static struct kunit_case ext4_inode_test_cases[] = {
2715f6b99d0SArpitha Raghunandan 	KUNIT_CASE_PARAM(inode_test_xtimestamp_decoding, ext4_inode_gen_params),
2721cbeab1bSIurii Zaikin 	{}
2731cbeab1bSIurii Zaikin };
2741cbeab1bSIurii Zaikin 
2751cbeab1bSIurii Zaikin static struct kunit_suite ext4_inode_test_suite = {
2761cbeab1bSIurii Zaikin 	.name = "ext4_inode_test",
2771cbeab1bSIurii Zaikin 	.test_cases = ext4_inode_test_cases,
2781cbeab1bSIurii Zaikin };
2791cbeab1bSIurii Zaikin 
280c475c77dSAlan Maguire kunit_test_suites(&ext4_inode_test_suite);
281c475c77dSAlan Maguire 
282c475c77dSAlan Maguire MODULE_LICENSE("GPL v2");
283