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