1 /*
2 * Copyright (c) 2017 Fujitsu Ltd.
3 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.*
17 */
18
19 /*
20 * This is a regression test for the race between getting an existing
21 * xattr and setting/removing a large xattr. This bug leads to that
22 * getxattr() fails to get an existing xattr and returns ENOATTR in xfs
23 * filesystem.
24 *
25 * Thie bug has been fixed in:
26 *
27 * commit 5a93790d4e2df73e30c965ec6e49be82fc3ccfce
28 * Author: Brian Foster <bfoster@redhat.com>
29 * Date: Wed Jan 25 07:53:43 2017 -0800
30 *
31 * xfs: remove racy hasattr check from attr ops
32 */
33
34 #include "config.h"
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <signal.h>
40
41 #ifdef HAVE_SYS_XATTR_H
42 # include <sys/xattr.h>
43 #endif
44
45 #include "tst_test.h"
46
47 #ifdef HAVE_SYS_XATTR_H
48
49 #define MNTPOINT "mntpoint"
50 #define TEST_FILE MNTPOINT "/file"
51 #define TRUSTED_BIG "trusted.big"
52 #define TRUSTED_SMALL "trusted.small"
53
54 static volatile int end;
55 static char big_value[512];
56 static char small_value[32];
57
sigproc(int sig)58 static void sigproc(int sig)
59 {
60 end = sig;
61 }
62
loop_getxattr(void)63 static void loop_getxattr(void)
64 {
65 int res;
66
67 while (!end) {
68 res = getxattr(TEST_FILE, TRUSTED_SMALL, NULL, 0);
69 if (res == -1) {
70 if (errno == ENODATA) {
71 tst_res(TFAIL, "getxattr() failed to get an "
72 "existing attribute");
73 } else {
74 tst_res(TFAIL | TERRNO,
75 "getxattr() failed without ENOATTR");
76 }
77
78 exit(0);
79 }
80 }
81
82 tst_res(TPASS, "getxattr() succeeded to get an existing attribute");
83 exit(0);
84 }
85
verify_getxattr(void)86 static void verify_getxattr(void)
87 {
88 pid_t pid;
89 int n;
90
91 end = 0;
92
93 pid = SAFE_FORK();
94 if (!pid)
95 loop_getxattr();
96
97 for (n = 0; n < 99; n++) {
98 SAFE_SETXATTR(TEST_FILE, TRUSTED_BIG, big_value,
99 sizeof(big_value), XATTR_CREATE);
100 SAFE_REMOVEXATTR(TEST_FILE, TRUSTED_BIG);
101 }
102
103 kill(pid, SIGUSR1);
104 tst_reap_children();
105 }
106
setup(void)107 static void setup(void)
108 {
109 SAFE_SIGNAL(SIGUSR1, sigproc);
110
111 SAFE_TOUCH(TEST_FILE, 0644, NULL);
112
113 memset(big_value, 'a', sizeof(big_value));
114 memset(small_value, 'a', sizeof(small_value));
115
116 SAFE_SETXATTR(TEST_FILE, TRUSTED_SMALL, small_value,
117 sizeof(small_value), XATTR_CREATE);
118 }
119
120 static struct tst_test test = {
121 .needs_tmpdir = 1,
122 .needs_root = 1,
123 .mount_device = 1,
124 .dev_fs_type = "xfs",
125 .mntpoint = MNTPOINT,
126 .forks_child = 1,
127 .test_all = verify_getxattr,
128 .setup = setup
129 };
130
131 #else /* HAVE_SYS_XATTR_H */
132 TST_TEST_TCONF("<sys/xattr.h> does not exist.");
133 #endif
134