inode-test.c (7686B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * KUnit test of ext4 inode that verify the seconds part of [a/c/m] 4 * timestamps in ext4 inode structs are decoded correctly. 5 */ 6 7#include <kunit/test.h> 8#include <linux/kernel.h> 9#include <linux/time64.h> 10 11#include "ext4.h" 12 13/* 14 * For constructing the nonnegative timestamp lower bound value. 15 * binary: 00000000 00000000 00000000 00000000 16 */ 17#define LOWER_MSB_0 0L 18/* 19 * For constructing the nonnegative timestamp upper bound value. 20 * binary: 01111111 11111111 11111111 11111111 21 * 22 */ 23#define UPPER_MSB_0 0x7fffffffL 24/* 25 * For constructing the negative timestamp lower bound value. 26 * binary: 10000000 00000000 00000000 00000000 27 */ 28#define LOWER_MSB_1 (-(UPPER_MSB_0) - 1L) /* avoid overflow */ 29/* 30 * For constructing the negative timestamp upper bound value. 31 * binary: 11111111 11111111 11111111 11111111 32 */ 33#define UPPER_MSB_1 (-1L) 34/* 35 * Upper bound for nanoseconds value supported by the encoding. 36 * binary: 00111111 11111111 11111111 11111111 37 */ 38#define MAX_NANOSECONDS ((1L << 30) - 1) 39 40#define CASE_NAME_FORMAT "%s: msb:%x lower_bound:%x extra_bits: %x" 41 42#define LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE\ 43 "1901-12-13 Lower bound of 32bit < 0 timestamp, no extra bits" 44#define UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE\ 45 "1969-12-31 Upper bound of 32bit < 0 timestamp, no extra bits" 46#define LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\ 47 "1970-01-01 Lower bound of 32bit >=0 timestamp, no extra bits" 48#define UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\ 49 "2038-01-19 Upper bound of 32bit >=0 timestamp, no extra bits" 50#define LOWER_BOUND_NEG_LO_1_CASE\ 51 "2038-01-19 Lower bound of 32bit <0 timestamp, lo extra sec bit on" 52#define UPPER_BOUND_NEG_LO_1_CASE\ 53 "2106-02-07 Upper bound of 32bit <0 timestamp, lo extra sec bit on" 54#define LOWER_BOUND_NONNEG_LO_1_CASE\ 55 "2106-02-07 Lower bound of 32bit >=0 timestamp, lo extra sec bit on" 56#define UPPER_BOUND_NONNEG_LO_1_CASE\ 57 "2174-02-25 Upper bound of 32bit >=0 timestamp, lo extra sec bit on" 58#define LOWER_BOUND_NEG_HI_1_CASE\ 59 "2174-02-25 Lower bound of 32bit <0 timestamp, hi extra sec bit on" 60#define UPPER_BOUND_NEG_HI_1_CASE\ 61 "2242-03-16 Upper bound of 32bit <0 timestamp, hi extra sec bit on" 62#define LOWER_BOUND_NONNEG_HI_1_CASE\ 63 "2242-03-16 Lower bound of 32bit >=0 timestamp, hi extra sec bit on" 64#define UPPER_BOUND_NONNEG_HI_1_CASE\ 65 "2310-04-04 Upper bound of 32bit >=0 timestamp, hi extra sec bit on" 66#define UPPER_BOUND_NONNEG_HI_1_NS_1_CASE\ 67 "2310-04-04 Upper bound of 32bit>=0 timestamp, hi extra sec bit 1. 1 ns" 68#define LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE\ 69 "2378-04-22 Lower bound of 32bit>= timestamp. Extra sec bits 1. Max ns" 70#define LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE\ 71 "2378-04-22 Lower bound of 32bit >=0 timestamp. All extra sec bits on" 72#define UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE\ 73 "2446-05-10 Upper bound of 32bit >=0 timestamp. All extra sec bits on" 74 75struct timestamp_expectation { 76 const char *test_case_name; 77 struct timespec64 expected; 78 u32 extra_bits; 79 bool msb_set; 80 bool lower_bound; 81}; 82 83static const struct timestamp_expectation test_data[] = { 84 { 85 .test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE, 86 .msb_set = true, 87 .lower_bound = true, 88 .extra_bits = 0, 89 .expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L}, 90 }, 91 92 { 93 .test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE, 94 .msb_set = true, 95 .lower_bound = false, 96 .extra_bits = 0, 97 .expected = {.tv_sec = -1LL, .tv_nsec = 0L}, 98 }, 99 100 { 101 .test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE, 102 .msb_set = false, 103 .lower_bound = true, 104 .extra_bits = 0, 105 .expected = {0LL, 0L}, 106 }, 107 108 { 109 .test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE, 110 .msb_set = false, 111 .lower_bound = false, 112 .extra_bits = 0, 113 .expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L}, 114 }, 115 116 { 117 .test_case_name = LOWER_BOUND_NEG_LO_1_CASE, 118 .msb_set = true, 119 .lower_bound = true, 120 .extra_bits = 1, 121 .expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L}, 122 }, 123 124 { 125 .test_case_name = UPPER_BOUND_NEG_LO_1_CASE, 126 .msb_set = true, 127 .lower_bound = false, 128 .extra_bits = 1, 129 .expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L}, 130 }, 131 132 { 133 .test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE, 134 .msb_set = false, 135 .lower_bound = true, 136 .extra_bits = 1, 137 .expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L}, 138 }, 139 140 { 141 .test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE, 142 .msb_set = false, 143 .lower_bound = false, 144 .extra_bits = 1, 145 .expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L}, 146 }, 147 148 { 149 .test_case_name = LOWER_BOUND_NEG_HI_1_CASE, 150 .msb_set = true, 151 .lower_bound = true, 152 .extra_bits = 2, 153 .expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L}, 154 }, 155 156 { 157 .test_case_name = UPPER_BOUND_NEG_HI_1_CASE, 158 .msb_set = true, 159 .lower_bound = false, 160 .extra_bits = 2, 161 .expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L}, 162 }, 163 164 { 165 .test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE, 166 .msb_set = false, 167 .lower_bound = true, 168 .extra_bits = 2, 169 .expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L}, 170 }, 171 172 { 173 .test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE, 174 .msb_set = false, 175 .lower_bound = false, 176 .extra_bits = 2, 177 .expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L}, 178 }, 179 180 { 181 .test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE, 182 .msb_set = false, 183 .lower_bound = false, 184 .extra_bits = 6, 185 .expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L}, 186 }, 187 188 { 189 .test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE, 190 .msb_set = false, 191 .lower_bound = true, 192 .extra_bits = 0xFFFFFFFF, 193 .expected = {.tv_sec = 0x300000000LL, 194 .tv_nsec = MAX_NANOSECONDS}, 195 }, 196 197 { 198 .test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE, 199 .msb_set = false, 200 .lower_bound = true, 201 .extra_bits = 3, 202 .expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L}, 203 }, 204 205 { 206 .test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE, 207 .msb_set = false, 208 .lower_bound = false, 209 .extra_bits = 3, 210 .expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L}, 211 } 212}; 213 214static void timestamp_expectation_to_desc(const struct timestamp_expectation *t, 215 char *desc) 216{ 217 strscpy(desc, t->test_case_name, KUNIT_PARAM_DESC_SIZE); 218} 219 220KUNIT_ARRAY_PARAM(ext4_inode, test_data, timestamp_expectation_to_desc); 221 222static time64_t get_32bit_time(const struct timestamp_expectation * const test) 223{ 224 if (test->msb_set) { 225 if (test->lower_bound) 226 return LOWER_MSB_1; 227 228 return UPPER_MSB_1; 229 } 230 231 if (test->lower_bound) 232 return LOWER_MSB_0; 233 return UPPER_MSB_0; 234} 235 236 237/* 238 * Test data is derived from the table in the Inode Timestamps section of 239 * Documentation/filesystems/ext4/inodes.rst. 240 */ 241static void inode_test_xtimestamp_decoding(struct kunit *test) 242{ 243 struct timespec64 timestamp; 244 245 struct timestamp_expectation *test_param = 246 (struct timestamp_expectation *)(test->param_value); 247 248 timestamp.tv_sec = get_32bit_time(test_param); 249 ext4_decode_extra_time(×tamp, 250 cpu_to_le32(test_param->extra_bits)); 251 252 KUNIT_EXPECT_EQ_MSG(test, 253 test_param->expected.tv_sec, 254 timestamp.tv_sec, 255 CASE_NAME_FORMAT, 256 test_param->test_case_name, 257 test_param->msb_set, 258 test_param->lower_bound, 259 test_param->extra_bits); 260 KUNIT_EXPECT_EQ_MSG(test, 261 test_param->expected.tv_nsec, 262 timestamp.tv_nsec, 263 CASE_NAME_FORMAT, 264 test_param->test_case_name, 265 test_param->msb_set, 266 test_param->lower_bound, 267 test_param->extra_bits); 268} 269 270static struct kunit_case ext4_inode_test_cases[] = { 271 KUNIT_CASE_PARAM(inode_test_xtimestamp_decoding, ext4_inode_gen_params), 272 {} 273}; 274 275static struct kunit_suite ext4_inode_test_suite = { 276 .name = "ext4_inode_test", 277 .test_cases = ext4_inode_test_cases, 278}; 279 280kunit_test_suites(&ext4_inode_test_suite); 281 282MODULE_LICENSE("GPL v2");