linux/fs/ext4/inode-test.c
<<
>>
Prefs
   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 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 */
 102static 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(&timestamp,
 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
 262static struct kunit_case ext4_inode_test_cases[] = {
 263        KUNIT_CASE(inode_test_xtimestamp_decoding),
 264        {}
 265};
 266
 267static struct kunit_suite ext4_inode_test_suite = {
 268        .name = "ext4_inode_test",
 269        .test_cases = ext4_inode_test_cases,
 270};
 271
 272kunit_test_suite(ext4_inode_test_suite);
 273