blob: e64f2a1f151bbfce71e32d17009e7bf4260df86d [file] [log] [blame]
// 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