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 75 struct 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 83 static 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 214 static 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 220 KUNIT_ARRAY_PARAM(ext4_inode, test_data, timestamp_expectation_to_desc); 221 222 static 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 */ 241 static 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 = ext4_decode_extra_time( 249 cpu_to_le32(get_32bit_time(test_param)), 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 270 static struct kunit_case ext4_inode_test_cases[] = { 271 KUNIT_CASE_PARAM(inode_test_xtimestamp_decoding, ext4_inode_gen_params), 272 {} 273 }; 274 275 static struct kunit_suite ext4_inode_test_suite = { 276 .name = "ext4_inode_test", 277 .test_cases = ext4_inode_test_cases, 278 }; 279 280 kunit_test_suites(&ext4_inode_test_suite); 281 282 MODULE_DESCRIPTION("KUnit test of ext4 inode timestamp decoding"); 283 MODULE_LICENSE("GPL v2"); 284