1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2017 Fujitsu Ltd.
4f08c3bdfSopenharmony_ci * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*
8f08c3bdfSopenharmony_ci * This is a regression test for the race between getting an existing
9f08c3bdfSopenharmony_ci * xattr and setting/removing a large xattr.  This bug leads to that
10f08c3bdfSopenharmony_ci * getxattr() fails to get an existing xattr and returns ENOATTR in xfs
11f08c3bdfSopenharmony_ci * filesystem.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * Thie bug has been fixed in:
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci * commit 5a93790d4e2df73e30c965ec6e49be82fc3ccfce
16f08c3bdfSopenharmony_ci * Author: Brian Foster <bfoster@redhat.com>
17f08c3bdfSopenharmony_ci * Date:   Wed Jan 25 07:53:43 2017 -0800
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci * xfs: remove racy hasattr check from attr ops
20f08c3bdfSopenharmony_ci */
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci#include "config.h"
23f08c3bdfSopenharmony_ci#include <errno.h>
24f08c3bdfSopenharmony_ci#include <sys/types.h>
25f08c3bdfSopenharmony_ci#include <string.h>
26f08c3bdfSopenharmony_ci#include <stdlib.h>
27f08c3bdfSopenharmony_ci#include <signal.h>
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_XATTR_H
30f08c3bdfSopenharmony_ci# include <sys/xattr.h>
31f08c3bdfSopenharmony_ci#endif
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci#include "tst_test.h"
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_XATTR_H
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci#define MNTPOINT	"mntpoint"
38f08c3bdfSopenharmony_ci#define TEST_FILE	MNTPOINT "/file"
39f08c3bdfSopenharmony_ci#define TRUSTED_BIG	"trusted.big"
40f08c3bdfSopenharmony_ci#define TRUSTED_SMALL	"trusted.small"
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_cistatic volatile int end;
43f08c3bdfSopenharmony_cistatic char big_value[512];
44f08c3bdfSopenharmony_cistatic char small_value[32];
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_cistatic void sigproc(int sig)
47f08c3bdfSopenharmony_ci{
48f08c3bdfSopenharmony_ci	end = sig;
49f08c3bdfSopenharmony_ci}
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistatic void loop_getxattr(void)
52f08c3bdfSopenharmony_ci{
53f08c3bdfSopenharmony_ci	int res;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	while (!end) {
56f08c3bdfSopenharmony_ci		res = getxattr(TEST_FILE, TRUSTED_SMALL, NULL, 0);
57f08c3bdfSopenharmony_ci		if (res == -1) {
58f08c3bdfSopenharmony_ci			if (errno == ENODATA) {
59f08c3bdfSopenharmony_ci				tst_res(TFAIL, "getxattr() failed to get an "
60f08c3bdfSopenharmony_ci					"existing attribute");
61f08c3bdfSopenharmony_ci			} else {
62f08c3bdfSopenharmony_ci				tst_res(TFAIL | TERRNO,
63f08c3bdfSopenharmony_ci					"getxattr() failed without ENOATTR");
64f08c3bdfSopenharmony_ci			}
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci			exit(0);
67f08c3bdfSopenharmony_ci		}
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	tst_res(TPASS, "getxattr() succeeded to get an existing attribute");
71f08c3bdfSopenharmony_ci	exit(0);
72f08c3bdfSopenharmony_ci}
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_cistatic void verify_getxattr(void)
75f08c3bdfSopenharmony_ci{
76f08c3bdfSopenharmony_ci	pid_t pid;
77f08c3bdfSopenharmony_ci	int n;
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	end = 0;
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
82f08c3bdfSopenharmony_ci	if (!pid)
83f08c3bdfSopenharmony_ci		loop_getxattr();
84f08c3bdfSopenharmony_ci
85f08c3bdfSopenharmony_ci	for (n = 0; n < 99; n++) {
86f08c3bdfSopenharmony_ci		SAFE_SETXATTR(TEST_FILE, TRUSTED_BIG, big_value,
87f08c3bdfSopenharmony_ci				sizeof(big_value), XATTR_CREATE);
88f08c3bdfSopenharmony_ci		SAFE_REMOVEXATTR(TEST_FILE, TRUSTED_BIG);
89f08c3bdfSopenharmony_ci	}
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	kill(pid, SIGUSR1);
92f08c3bdfSopenharmony_ci	tst_reap_children();
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic void setup(void)
96f08c3bdfSopenharmony_ci{
97f08c3bdfSopenharmony_ci	SAFE_SIGNAL(SIGUSR1, sigproc);
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci	SAFE_TOUCH(TEST_FILE, 0644, NULL);
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	memset(big_value, 'a', sizeof(big_value));
102f08c3bdfSopenharmony_ci	memset(small_value, 'a', sizeof(small_value));
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	SAFE_SETXATTR(TEST_FILE, TRUSTED_SMALL, small_value,
105f08c3bdfSopenharmony_ci			sizeof(small_value), XATTR_CREATE);
106f08c3bdfSopenharmony_ci}
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_cistatic struct tst_test test = {
109f08c3bdfSopenharmony_ci	.needs_root = 1,
110f08c3bdfSopenharmony_ci	.mount_device = 1,
111f08c3bdfSopenharmony_ci	.dev_fs_type = "xfs",
112f08c3bdfSopenharmony_ci	.mntpoint = MNTPOINT,
113f08c3bdfSopenharmony_ci	.forks_child = 1,
114f08c3bdfSopenharmony_ci	.test_all = verify_getxattr,
115f08c3bdfSopenharmony_ci	.setup = setup,
116f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
117f08c3bdfSopenharmony_ci		{"linux-git", "5a93790d4e2d"},
118f08c3bdfSopenharmony_ci		{}
119f08c3bdfSopenharmony_ci	}
120f08c3bdfSopenharmony_ci};
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci#else /* HAVE_SYS_XATTR_H */
123f08c3bdfSopenharmony_ci	TST_TEST_TCONF("<sys/xattr.h> does not exist.");
124f08c3bdfSopenharmony_ci#endif
125