1 // SPDX-License-Identifier: GPL-2.0 or later 2 /* 3 * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 4 * Email : code (at) zilogic.com 5 */ 6 7 /* 8 * DESCRIPTION : 9 * 10 * Test-Case 1 : Testing btime 11 * flow : The time before and after the execution of the create 12 * system call is noted. 13 * It is checked whether the birth time returned by statx lies in 14 * this range. 15 * 16 * Test-Case 2 : Testing mtime 17 * flow : The time before and after the execution of the write 18 * system call is noted. 19 * It is checked whether the modification time returned 20 * by statx lies in this range. 21 * 22 * Test-Case 3 : Testing atime 23 * flow : The time before and after the execution of the read 24 * system call is noted. 25 * It is checked whether the access time returned by statx lies in 26 * this range. 27 * 28 * Test-Case 4 : Testing ctime 29 * flow : The time before and after the execution of the chmod 30 * system call is noted. 31 * It is checked whether the status change time returned by statx 32 * lies in this range. 33 * 34 */ 35 36 #define _GNU_SOURCE 37 #include <stdio.h> 38 #include <sys/mount.h> 39 #include <time.h> 40 41 #include "tst_test.h" 42 #include "tst_safe_clocks.h" 43 #include "tst_safe_macros.h" 44 #include "tst_timer.h" 45 #include "lapi/stat.h" 46 #include "lapi/mount.h" 47 #include "lapi/fcntl.h" 48 #include "lapi/posix_clocks.h" 49 50 #define MOUNT_POINT "mount_ext" 51 #define TEST_FILE MOUNT_POINT"/test_file.txt" 52 #define SIZE 2 53 54 static int fd; 55 56 static void timestamp_to_timespec(const struct statx_timestamp *timestamp, 57 struct timespec *timespec) 58 { 59 timespec->tv_sec = timestamp->tv_sec; 60 timespec->tv_nsec = timestamp->tv_nsec; 61 } 62 63 static void clock_wait_tick(void) 64 { 65 struct timespec res; 66 unsigned int usecs; 67 68 SAFE_CLOCK_GETRES(CLOCK_REALTIME_COARSE, &res); 69 usecs = tst_timespec_to_us(res); 70 71 usleep(usecs); 72 } 73 74 static void create_file(void) 75 { 76 if (fd > 0) { 77 SAFE_CLOSE(fd); 78 SAFE_UNLINK(TEST_FILE); 79 } 80 fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_RDWR, 0666); 81 } 82 83 static void write_file(void) 84 { 85 char data[SIZE] = "hi"; 86 87 SAFE_WRITE(0, fd, data, sizeof(data)); 88 } 89 90 static void read_file(void) 91 { 92 char data[SIZE]; 93 94 SAFE_READ(0, fd, data, sizeof(data)); 95 } 96 97 static void change_mode(void) 98 { 99 SAFE_CHMOD(TEST_FILE, 0777); 100 } 101 102 static struct test_case { 103 void (*operation)(void); 104 char *op_name; 105 } tcases[] = { 106 {.operation = create_file, 107 .op_name = "Birth time"}, 108 {.operation = write_file, 109 .op_name = "Modified time"}, 110 {.operation = read_file, 111 .op_name = "Access time"}, 112 {.operation = change_mode, 113 .op_name = "Change time"} 114 }; 115 116 static void test_statx(unsigned int test_nr) 117 { 118 struct statx buff; 119 struct timespec before_time; 120 struct timespec after_time; 121 struct timespec statx_time = {0, 0}; 122 123 struct test_case *tc = &tcases[test_nr]; 124 125 SAFE_CLOCK_GETTIME(CLOCK_REALTIME_COARSE, &before_time); 126 clock_wait_tick(); 127 tc->operation(); 128 clock_wait_tick(); 129 SAFE_CLOCK_GETTIME(CLOCK_REALTIME_COARSE, &after_time); 130 131 TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_ALL, &buff)); 132 if (TST_RET != 0) { 133 tst_brk(TFAIL | TTERRNO, 134 "statx(AT_FDCWD, %s, 0, STATX_ALL, &buff)", 135 TEST_FILE); 136 } 137 138 switch (test_nr) { 139 case 0: 140 timestamp_to_timespec(&buff.stx_btime, &statx_time); 141 break; 142 case 1: 143 timestamp_to_timespec(&buff.stx_mtime, &statx_time); 144 break; 145 case 2: 146 timestamp_to_timespec(&buff.stx_atime, &statx_time); 147 break; 148 case 3: 149 timestamp_to_timespec(&buff.stx_ctime, &statx_time); 150 break; 151 } 152 if (tst_timespec_lt(statx_time, before_time)) 153 tst_res(TFAIL, "%s < before time", tc->op_name); 154 else if (tst_timespec_lt(after_time, statx_time)) 155 tst_res(TFAIL, "%s > after_time", tc->op_name); 156 else 157 tst_res(TPASS, "%s Passed", tc->op_name); 158 } 159 160 161 static void cleanup(void) 162 { 163 if (fd > 0) 164 SAFE_CLOSE(fd); 165 } 166 167 static struct tst_test test = { 168 .cleanup = cleanup, 169 .tcnt = ARRAY_SIZE(tcases), 170 .test = test_statx, 171 .min_kver = "4.11", 172 .needs_root = 1, 173 .needs_tmpdir = 1, 174 .mntpoint = MOUNT_POINT, 175 .mount_device = 1, 176 .dev_fs_type = "ext4", 177 .dev_fs_opts = (const char *const []){"-I", "256", NULL}, 178 .mnt_flags = MS_STRICTATIME, 179 }; 180