1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
4 * Email : code@zilogic.com
5 */
6
7 /*
8 * Test statx
9 *
10 * This code tests the following flags:
11 * 1) AT_STATX_FORCE_SYNC
12 * 2) AT_STATX_DONT_SYNC
13 *
14 * By exportfs cmd creating NFS setup.
15 *
16 * A test file is created in server folder and statx is being
17 * done in client folder.
18 *
19 * TESTCASE 1:
20 * BY AT_STATX_SYNC_AS_STAT getting predefined mode value.
21 * Then, by using AT_STATX_FORCE_SYNC getting new updated vaue
22 * from server file changes.
23 *
24 * TESTCASE 2:
25 * BY AT_STATX_SYNC_AS_STAT getting predefined mode value.
26 * AT_STATX_FORCE_SYNC is called to create cache data of the file.
27 * Then, by using DONT_SYNC_FILE getting old cached data in client folder,
28 * but mode has been chaged in server file.
29 *
30 * The support for SYNC flags was implemented in NFS in:
31 *
32 * commit 9ccee940bd5b766b6dab6c1a80908b9490a4850d
33 * Author: Trond Myklebust <trond.myklebust@primarydata.com>
34 * Date: Thu Jan 4 17:46:09 2018 -0500
35 *
36 * Support statx() mask and query flags parameters
37 *
38 * Hence we skip the test on anything older than 4.16.
39 */
40
41 #define _GNU_SOURCE
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <errno.h>
46 #include <linux/limits.h>
47 #include <sys/mount.h>
48 #include "tst_test.h"
49 #include "lapi/stat.h"
50
51 #define MODE(X) (X & (~S_IFMT))
52 #define FLAG_NAME(x) .flag = x, .flag_name = #x
53 #define BUFF_SIZE PATH_MAX
54 #define DEFAULT_MODE 0644
55 #define CURRENT_MODE 0777
56
57 #define CLI_PATH "client"
58 #define SERV_PATH "server"
59 #define CLI_FORCE_SYNC "client/force_sync_file"
60 #define CLI_DONT_SYNC "client/dont_sync_file"
61 #define SERV_FORCE_SYNC "server/force_sync_file"
62 #define SERV_DONT_SYNC "server/dont_sync_file"
63
64 static char *cwd;
65 static char cmd[BUFF_SIZE];
66 static int mounted;
67 static int exported;
68
get_mode(char * file_name,int flag_type,char * flag_name)69 static int get_mode(char *file_name, int flag_type, char *flag_name)
70 {
71 struct statx buf;
72
73 TEST(statx(AT_FDCWD, file_name, flag_type, STATX_ALL, &buf));
74
75 if (TST_RET == -1) {
76 tst_brk(TFAIL | TST_ERR,
77 "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf)",
78 file_name, flag_name);
79 }
80
81 tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf) = %o",
82 file_name, flag_name, buf.stx_mode);
83
84 return buf.stx_mode;
85 }
86
87 const struct test_cases {
88 int flag;
89 char *flag_name;
90 char *server_file;
91 char *client_file;
92 unsigned int mode;
93 } tcases[] = {
94 {FLAG_NAME(AT_STATX_DONT_SYNC), SERV_DONT_SYNC, CLI_DONT_SYNC, DEFAULT_MODE},
95 {FLAG_NAME(AT_STATX_FORCE_SYNC), SERV_FORCE_SYNC, CLI_FORCE_SYNC, CURRENT_MODE}
96 };
97
test_statx(unsigned int i)98 static void test_statx(unsigned int i)
99 {
100 const struct test_cases *tc = &tcases[i];
101 unsigned int cur_mode;
102
103 get_mode(tc->client_file, AT_STATX_FORCE_SYNC, "AT_STATX_FORCE_SYNC");
104
105 SAFE_CHMOD(tc->server_file, CURRENT_MODE);
106 cur_mode = get_mode(tc->client_file, tc->flag, tc->flag_name);
107
108 if (MODE(cur_mode) == tc->mode) {
109 tst_res(TPASS,
110 "statx() with %s for mode %o",
111 tc->flag_name, tc->mode);
112 } else {
113 tst_res(TFAIL,
114 "statx() with %s for mode %o %o",
115 tc->flag_name, tc->mode, MODE(cur_mode));
116 }
117
118 SAFE_CHMOD(tc->server_file, DEFAULT_MODE);
119 }
120
setup(void)121 static void setup(void)
122 {
123 int ret;
124 char server_path[BUFF_SIZE];
125
126 cwd = tst_get_tmpdir();
127
128 SAFE_MKDIR(SERV_PATH, DEFAULT_MODE);
129 SAFE_MKDIR(CLI_PATH, DEFAULT_MODE);
130 SAFE_CREAT(SERV_FORCE_SYNC, DEFAULT_MODE);
131 SAFE_CREAT(SERV_DONT_SYNC, DEFAULT_MODE);
132
133 snprintf(server_path, sizeof(server_path), ":%s/%s", cwd, SERV_PATH);
134
135 snprintf(cmd, sizeof(cmd),
136 "exportfs -i -o no_root_squash,rw,sync,no_subtree_check,fsid=%d *%.1024s",
137 getpid(), server_path);
138 exported = 1;
139
140 ret = tst_system(cmd);
141 if (WEXITSTATUS(ret) == 127)
142 tst_brk(TCONF | TST_ERR, "%s not found", cmd);
143 if (ret)
144 tst_brk(TBROK | TST_ERR, "failed to exportfs");
145
146 if (mount(server_path, CLI_PATH, "nfs", 0, "addr=127.0.0.1")) {
147 if (errno == EOPNOTSUPP || errno == ECONNREFUSED
148 || errno == ETIMEDOUT)
149 tst_brk(TCONF | TERRNO, "nfs server not set up?");
150 tst_brk(TBROK | TERRNO, "mount() nfs failed");
151 }
152 mounted = 1;
153 }
154
cleanup(void)155 static void cleanup(void)
156 {
157 if (!exported)
158 return;
159 snprintf(cmd, sizeof(cmd),
160 "exportfs -u *:%s/%s", cwd, SERV_PATH);
161
162 if (tst_system(cmd) == -1)
163 tst_res(TWARN | TST_ERR, "failed to clear exportfs");
164
165 if (mounted)
166 SAFE_UMOUNT(CLI_PATH);
167 }
168
169 static struct tst_test test = {
170 .tcnt = ARRAY_SIZE(tcases),
171 .test = test_statx,
172 .setup = setup,
173 .cleanup = cleanup,
174 .min_kver = "4.16",
175 .needs_tmpdir = 1,
176 .dev_fs_type = "nfs",
177 .needs_root = 1,
178 };
179