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 time64_t get_32bit_time(const struct timestamp_expectation * const test) 84 { 85 if (test->msb_set) { 86 if (test->lower_bound) 87 return LOWER_MSB_1; 88 89 return UPPER_MSB_1; 90 } 91 92 if (test->lower_bound) 93 return LOWER_MSB_0; 94 return UPPER_MSB_0; 95 } 96 97 98 /* 99 * Test data is derived from the table in the Inode Timestamps section of 100 * Documentation/filesystems/ext4/inodes.rst. 101 */ 102 static void inode_test_xtimestamp_decoding(struct kunit *test) 103 { 104 const struct timestamp_expectation test_data[] = { 105 { 106 .test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE, 107 .msb_set = true, 108 .lower_bound = true, 109 .extra_bits = 0, 110 .expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L}, 111 }, 112 113 { 114 .test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE, 115 .msb_set = true, 116 .lower_bound = false, 117 .extra_bits = 0, 118 .expected = {.tv_sec = -1LL, .tv_nsec = 0L}, 119 }, 120 121 { 122 .test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE, 123 .msb_set = false, 124 .lower_bound = true, 125 .extra_bits = 0, 126 .expected = {0LL, 0L}, 127 }, 128 129 { 130 .test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE, 131 .msb_set = false, 132 .lower_bound = false, 133 .extra_bits = 0, 134 .expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L}, 135 }, 136 137 { 138 .test_case_name = LOWER_BOUND_NEG_LO_1_CASE, 139 .msb_set = true, 140 .lower_bound = true, 141 .extra_bits = 1, 142 .expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L}, 143 }, 144 145 { 146 .test_case_name = UPPER_BOUND_NEG_LO_1_CASE, 147 .msb_set = true, 148 .lower_bound = false, 149 .extra_bits = 1, 150 .expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L}, 151 }, 152 153 { 154 .test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE, 155 .msb_set = false, 156 .lower_bound = true, 157 .extra_bits = 1, 158 .expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L}, 159 }, 160 161 { 162 .test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE, 163 .msb_set = false, 164 .lower_bound = false, 165 .extra_bits = 1, 166 .expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L}, 167 }, 168 169 { 170 .test_case_name = LOWER_BOUND_NEG_HI_1_CASE, 171 .msb_set = true, 172 .lower_bound = true, 173 .extra_bits = 2, 174 .expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L}, 175 }, 176 177 { 178 .test_case_name = UPPER_BOUND_NEG_HI_1_CASE, 179 .msb_set = true, 180 .lower_bound = false, 181 .extra_bits = 2, 182 .expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L}, 183 }, 184 185 { 186 .test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE, 187 .msb_set = false, 188 .lower_bound = true, 189 .extra_bits = 2, 190 .expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L}, 191 }, 192 193 { 194 .test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE, 195 .msb_set = false, 196 .lower_bound = false, 197 .extra_bits = 2, 198 .expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L}, 199 }, 200 201 { 202 .test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE, 203 .msb_set = false, 204 .lower_bound = false, 205 .extra_bits = 6, 206 .expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L}, 207 }, 208 209 { 210 .test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE, 211 .msb_set = false, 212 .lower_bound = true, 213 .extra_bits = 0xFFFFFFFF, 214 .expected = {.tv_sec = 0x300000000LL, 215 .tv_nsec = MAX_NANOSECONDS}, 216 }, 217 218 { 219 .test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE, 220 .msb_set = false, 221 .lower_bound = true, 222 .extra_bits = 3, 223 .expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L}, 224 }, 225 226 { 227 .test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE, 228 .msb_set = false, 229 .lower_bound = false, 230 .extra_bits = 3, 231 .expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L}, 232 } 233 }; 234 235 struct timespec64 timestamp; 236 int i; 237 238 for (i = 0; i < ARRAY_SIZE(test_data); ++i) { 239 timestamp.tv_sec = get_32bit_time(&test_data[i]); 240 ext4_decode_extra_time(×tamp, 241 cpu_to_le32(test_data[i].extra_bits)); 242 243 KUNIT_EXPECT_EQ_MSG(test, 244 test_data[i].expected.tv_sec, 245 timestamp.tv_sec, 246 CASE_NAME_FORMAT, 247 test_data[i].test_case_name, 248 test_data[i].msb_set, 249 test_data[i].lower_bound, 250 test_data[i].extra_bits); 251 KUNIT_EXPECT_EQ_MSG(test, 252 test_data[i].expected.tv_nsec, 253 timestamp.tv_nsec, 254 CASE_NAME_FORMAT, 255 test_data[i].test_case_name, 256 test_data[i].msb_set, 257 test_data[i].lower_bound, 258 test_data[i].extra_bits); 259 } 260 } 261 262 static struct kunit_case ext4_inode_test_cases[] = { 263 KUNIT_CASE(inode_test_xtimestamp_decoding), 264 {} 265 }; 266 267 static struct kunit_suite ext4_inode_test_suite = { 268 .name = "ext4_inode_test", 269 .test_cases = ext4_inode_test_cases, 270 }; 271 272 kunit_test_suites(&ext4_inode_test_suite); 273 274 MODULE_LICENSE("GPL v2"); 275