• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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