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
 |