125 lines
2.4 KiB
C
125 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2017 Fujitsu Ltd.
|
|
* Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
|
|
*/
|
|
|
|
/*
|
|
* This is a regression test for the race between getting an existing
|
|
* xattr and setting/removing a large xattr. This bug leads to that
|
|
* getxattr() fails to get an existing xattr and returns ENOATTR in xfs
|
|
* filesystem.
|
|
*
|
|
* Thie bug has been fixed in:
|
|
*
|
|
* commit 5a93790d4e2df73e30c965ec6e49be82fc3ccfce
|
|
* Author: Brian Foster <bfoster@redhat.com>
|
|
* Date: Wed Jan 25 07:53:43 2017 -0800
|
|
*
|
|
* xfs: remove racy hasattr check from attr ops
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
|
|
#ifdef HAVE_SYS_XATTR_H
|
|
# include <sys/xattr.h>
|
|
#endif
|
|
|
|
#include "tst_test.h"
|
|
|
|
#ifdef HAVE_SYS_XATTR_H
|
|
|
|
#define MNTPOINT "mntpoint"
|
|
#define TEST_FILE MNTPOINT "/file"
|
|
#define TRUSTED_BIG "trusted.big"
|
|
#define TRUSTED_SMALL "trusted.small"
|
|
|
|
static volatile int end;
|
|
static char big_value[512];
|
|
static char small_value[32];
|
|
|
|
static void sigproc(int sig)
|
|
{
|
|
end = sig;
|
|
}
|
|
|
|
static void loop_getxattr(void)
|
|
{
|
|
int res;
|
|
|
|
while (!end) {
|
|
res = getxattr(TEST_FILE, TRUSTED_SMALL, NULL, 0);
|
|
if (res == -1) {
|
|
if (errno == ENODATA) {
|
|
tst_res(TFAIL, "getxattr() failed to get an "
|
|
"existing attribute");
|
|
} else {
|
|
tst_res(TFAIL | TERRNO,
|
|
"getxattr() failed without ENOATTR");
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
tst_res(TPASS, "getxattr() succeeded to get an existing attribute");
|
|
exit(0);
|
|
}
|
|
|
|
static void verify_getxattr(void)
|
|
{
|
|
pid_t pid;
|
|
int n;
|
|
|
|
end = 0;
|
|
|
|
pid = SAFE_FORK();
|
|
if (!pid)
|
|
loop_getxattr();
|
|
|
|
for (n = 0; n < 99; n++) {
|
|
SAFE_SETXATTR(TEST_FILE, TRUSTED_BIG, big_value,
|
|
sizeof(big_value), XATTR_CREATE);
|
|
SAFE_REMOVEXATTR(TEST_FILE, TRUSTED_BIG);
|
|
}
|
|
|
|
kill(pid, SIGUSR1);
|
|
tst_reap_children();
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
SAFE_SIGNAL(SIGUSR1, sigproc);
|
|
|
|
SAFE_TOUCH(TEST_FILE, 0644, NULL);
|
|
|
|
memset(big_value, 'a', sizeof(big_value));
|
|
memset(small_value, 'a', sizeof(small_value));
|
|
|
|
SAFE_SETXATTR(TEST_FILE, TRUSTED_SMALL, small_value,
|
|
sizeof(small_value), XATTR_CREATE);
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.needs_root = 1,
|
|
.mount_device = 1,
|
|
.dev_fs_type = "xfs",
|
|
.mntpoint = MNTPOINT,
|
|
.forks_child = 1,
|
|
.test_all = verify_getxattr,
|
|
.setup = setup,
|
|
.tags = (const struct tst_tag[]) {
|
|
{"linux-git", "5a93790d4e2d"},
|
|
{}
|
|
}
|
|
};
|
|
|
|
#else /* HAVE_SYS_XATTR_H */
|
|
TST_TEST_TCONF("<sys/xattr.h> does not exist.");
|
|
#endif
|