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