mirror_zfs/tests/zfs-tests/cmd/xattrtest/xattrtest.c
Brian Behlendorf 02730c333c Use cstyle -cpP in make cstyle check
Enable picky cstyle checks and resolve the new warnings.  The vast
majority of the changes needed were to handle minor issues with
whitespace formatting.  This patch contains no functional changes.

Non-whitespace changes are as follows:

* 8 times ; to { } in for/while loop
* fix missing ; in cmd/zed/agents/zfs_diagnosis.c
* comment (confim -> confirm)
* change endline , to ; in cmd/zpool/zpool_main.c
* a number of /* BEGIN CSTYLED */ /* END CSTYLED */ blocks
* /* CSTYLED */ markers
* change == 0 to !
* ulong to unsigned long in module/zfs/dsl_scan.c
* rearrangement of module_param lines in module/zfs/metaslab.c
* add { } block around statement after for_each_online_node

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Håkan Johansson <f96hajo@chalmers.se>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #5465
2016-12-12 10:46:26 -08:00

703 lines
15 KiB
C

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2016 Lawrence Livermore National Security, LLC.
*/
/*
* An extended attribute (xattr) correctness test. This program creates
* N files and sets M attrs on them of size S. Optionally is will verify
* a pattern stored in the xattr.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <attr/xattr.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <linux/limits.h>
extern char *program_invocation_short_name;
#define ERROR(fmt, ...) \
fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \
program_invocation_short_name, __FILE__, __LINE__, \
__func__, ## __VA_ARGS__);
static const char shortopts[] = "hvycdn:f:x:s:p:t:e:rRko:";
static const struct option longopts[] = {
{ "help", no_argument, 0, 'h' },
{ "verbose", no_argument, 0, 'v' },
{ "verify", no_argument, 0, 'y' },
{ "nth", required_argument, 0, 'n' },
{ "files", required_argument, 0, 'f' },
{ "xattrs", required_argument, 0, 'x' },
{ "size", required_argument, 0, 's' },
{ "path", required_argument, 0, 'p' },
{ "synccaches", no_argument, 0, 'c' },
{ "dropcaches", no_argument, 0, 'd' },
{ "script", required_argument, 0, 't' },
{ "seed", required_argument, 0, 'e' },
{ "random", no_argument, 0, 'r' },
{ "randomvalue", no_argument, 0, 'R' },
{ "keep", no_argument, 0, 'k' },
{ "only", required_argument, 0, 'o' },
{ 0, 0, 0, 0 }
};
enum phases {
PHASE_ALL = 0,
PHASE_CREATE,
PHASE_SETXATTR,
PHASE_GETXATTR,
PHASE_UNLINK,
PHASE_INVAL
};
static int verbose = 0;
static int verify = 0;
static int synccaches = 0;
static int dropcaches = 0;
static int nth = 0;
static int files = 1000;
static int xattrs = 1;
static int size = 6;
static int size_is_random = 0;
static int value_is_random = 0;
static int keep_files = 0;
static int phase = PHASE_ALL;
static char path[PATH_MAX] = "/tmp/xattrtest";
static char script[PATH_MAX] = "/bin/true";
static char xattrbytes[XATTR_SIZE_MAX];
static int
usage(int argc, char **argv) {
fprintf(stderr,
"usage: %s [-hvycdrRk] [-n <nth>] [-f <files>] [-x <xattrs>]\n"
" [-s <bytes>] [-p <path>] [-t <script> ] [-o <phase>]\n",
argv[0]);
fprintf(stderr,
" --help -h This help\n"
" --verbose -v Increase verbosity\n"
" --verify -y Verify xattr contents\n"
" --nth -n <nth> Print every nth file\n"
" --files -f <files> Set xattrs on N files\n"
" --xattrs -x <xattrs> Set N xattrs on each file\n"
" --size -s <bytes> Set N bytes per xattr\n"
" --path -p <path> Path to files\n"
" --synccaches -c Sync caches between phases\n"
" --dropcaches -d Drop caches between phases\n"
" --script -t <script> Exec script between phases\n"
" --seed -e <seed> Random seed value\n"
" --random -r Randomly sized xattrs [16-size]\n"
" --randomvalue -R Random xattr values\n"
" --keep -k Don't unlink files\n"
" --only -o <num> Only run phase N\n"
" 0=all, 1=create, 2=setxattr,\n"
" 3=getxattr, 4=unlink\n\n");
return (1);
}
static int
parse_args(int argc, char **argv)
{
long seed = time(NULL);
int c;
int rc = 0;
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch (c) {
case 'h':
return (usage(argc, argv));
case 'v':
verbose++;
break;
case 'y':
verify = 1;
if (phase != PHASE_ALL) {
fprintf(stderr,
"Error: -y and -o are incompatible.\n");
rc = 1;
}
break;
case 'n':
nth = strtol(optarg, NULL, 0);
break;
case 'f':
files = strtol(optarg, NULL, 0);
break;
case 'x':
xattrs = strtol(optarg, NULL, 0);
break;
case 's':
size = strtol(optarg, NULL, 0);
if (size > XATTR_SIZE_MAX) {
fprintf(stderr, "Error: the -s value may not "
"be greater than %d\n", XATTR_SIZE_MAX);
rc = 1;
}
break;
case 'p':
strncpy(path, optarg, PATH_MAX);
path[PATH_MAX - 1] = '\0';
break;
case 'c':
synccaches = 1;
break;
case 'd':
dropcaches = 1;
break;
case 't':
strncpy(script, optarg, PATH_MAX);
script[PATH_MAX - 1] = '\0';
break;
case 'e':
seed = strtol(optarg, NULL, 0);
break;
case 'r':
size_is_random = 1;
break;
case 'R':
value_is_random = 1;
break;
case 'k':
keep_files = 1;
break;
case 'o':
phase = strtol(optarg, NULL, 0);
if (phase <= PHASE_ALL || phase >= PHASE_INVAL) {
fprintf(stderr, "Error: the -o value must be "
"greater than %d and less than %d\n",
PHASE_ALL, PHASE_INVAL);
rc = 1;
}
if (verify == 1) {
fprintf(stderr,
"Error: -y and -o are incompatible.\n");
rc = 1;
}
break;
default:
rc = 1;
break;
}
}
if (rc != 0)
return (rc);
srandom(seed);
if (verbose) {
fprintf(stdout, "verbose: %d\n", verbose);
fprintf(stdout, "verify: %d\n", verify);
fprintf(stdout, "nth: %d\n", nth);
fprintf(stdout, "files: %d\n", files);
fprintf(stdout, "xattrs: %d\n", xattrs);
fprintf(stdout, "size: %d\n", size);
fprintf(stdout, "path: %s\n", path);
fprintf(stdout, "synccaches: %d\n", synccaches);
fprintf(stdout, "dropcaches: %d\n", dropcaches);
fprintf(stdout, "script: %s\n", script);
fprintf(stdout, "seed: %ld\n", seed);
fprintf(stdout, "random size: %d\n", size_is_random);
fprintf(stdout, "random value: %d\n", value_is_random);
fprintf(stdout, "keep: %d\n", keep_files);
fprintf(stdout, "only: %d\n", phase);
fprintf(stdout, "%s", "\n");
}
return (rc);
}
static int
drop_caches(void)
{
char file[] = "/proc/sys/vm/drop_caches";
int fd, rc;
fd = open(file, O_WRONLY);
if (fd == -1) {
ERROR("Error %d: open(\"%s\", O_WRONLY)\n", errno, file);
return (errno);
}
rc = write(fd, "3", 1);
if ((rc == -1) || (rc != 1)) {
ERROR("Error %d: write(%d, \"3\", 1)\n", errno, fd);
(void) close(fd);
return (errno);
}
rc = close(fd);
if (rc == -1) {
ERROR("Error %d: close(%d)\n", errno, fd);
return (errno);
}
return (0);
}
static int
run_process(const char *path, char *argv[])
{
pid_t pid;
int rc, devnull_fd;
pid = vfork();
if (pid == 0) {
devnull_fd = open("/dev/null", O_WRONLY);
if (devnull_fd < 0)
_exit(-1);
(void) dup2(devnull_fd, STDOUT_FILENO);
(void) dup2(devnull_fd, STDERR_FILENO);
close(devnull_fd);
(void) execvp(path, argv);
_exit(-1);
} else if (pid > 0) {
int status;
while ((rc = waitpid(pid, &status, 0)) == -1 &&
errno == EINTR) { }
if (rc < 0 || !WIFEXITED(status))
return (-1);
return (WEXITSTATUS(status));
}
return (-1);
}
static int
post_hook(char *phase)
{
char *argv[3] = { script, phase, (char *)0 };
int rc;
if (synccaches)
sync();
if (dropcaches) {
rc = drop_caches();
if (rc)
return (rc);
}
rc = run_process(script, argv);
if (rc)
return (rc);
return (0);
}
#define USEC_PER_SEC 1000000
static void
timeval_normalize(struct timeval *tv, time_t sec, suseconds_t usec)
{
while (usec >= USEC_PER_SEC) {
usec -= USEC_PER_SEC;
sec++;
}
while (usec < 0) {
usec += USEC_PER_SEC;
sec--;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
static void
timeval_sub(struct timeval *delta, struct timeval *tv1, struct timeval *tv2)
{
timeval_normalize(delta,
tv1->tv_sec - tv2->tv_sec,
tv1->tv_usec - tv2->tv_usec);
}
static double
timeval_sub_seconds(struct timeval *tv1, struct timeval *tv2)
{
struct timeval delta;
timeval_sub(&delta, tv1, tv2);
return ((double)delta.tv_usec / USEC_PER_SEC + delta.tv_sec);
}
static int
create_files(void)
{
int i, rc;
char *file = NULL;
struct timeval start, stop;
double seconds;
file = malloc(PATH_MAX);
if (file == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
PATH_MAX);
goto out;
}
(void) gettimeofday(&start, NULL);
for (i = 1; i <= files; i++) {
(void) sprintf(file, "%s/file-%d", path, i);
if (nth && ((i % nth) == 0))
fprintf(stdout, "create: %s\n", file);
rc = unlink(file);
if ((rc == -1) && (errno != ENOENT)) {
ERROR("Error %d: unlink(%s)\n", errno, file);
rc = errno;
goto out;
}
rc = open(file, O_CREAT, 0644);
if (rc == -1) {
ERROR("Error %d: open(%s, O_CREATE, 0644)\n",
errno, file);
rc = errno;
goto out;
}
rc = close(rc);
if (rc == -1) {
ERROR("Error %d: close(%d)\n", errno, rc);
rc = errno;
goto out;
}
}
(void) gettimeofday(&stop, NULL);
seconds = timeval_sub_seconds(&stop, &start);
fprintf(stdout, "create: %f seconds %f creates/second\n",
seconds, files / seconds);
rc = post_hook("post");
out:
if (file)
free(file);
return (rc);
}
static int
get_random_bytes(char *buf, size_t bytes)
{
int rand;
ssize_t bytes_read = 0;
rand = open("/dev/urandom", O_RDONLY);
if (rand < 0)
return (rand);
while (bytes_read < bytes) {
ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read);
if (rc < 0)
break;
bytes_read += rc;
}
(void) close(rand);
return (bytes_read);
}
static int
setxattrs(void)
{
int i, j, rnd_size = size, shift, rc = 0;
char name[XATTR_NAME_MAX];
char *value = NULL;
char *file = NULL;
struct timeval start, stop;
double seconds;
value = malloc(XATTR_SIZE_MAX);
if (value == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
XATTR_SIZE_MAX);
goto out;
}
file = malloc(PATH_MAX);
if (file == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
PATH_MAX);
goto out;
}
(void) gettimeofday(&start, NULL);
for (i = 1; i <= files; i++) {
(void) sprintf(file, "%s/file-%d", path, i);
if (nth && ((i % nth) == 0))
fprintf(stdout, "setxattr: %s\n", file);
for (j = 1; j <= xattrs; j++) {
if (size_is_random)
rnd_size = (random() % (size - 16)) + 16;
(void) sprintf(name, "user.%d", j);
shift = sprintf(value, "size=%d ", rnd_size);
memcpy(value + shift, xattrbytes,
sizeof (xattrbytes) - shift);
rc = lsetxattr(file, name, value, rnd_size, 0);
if (rc == -1) {
ERROR("Error %d: lsetxattr(%s, %s, ..., %d)\n",
errno, file, name, rnd_size);
goto out;
}
}
}
(void) gettimeofday(&stop, NULL);
seconds = timeval_sub_seconds(&stop, &start);
fprintf(stdout, "setxattr: %f seconds %f setxattrs/second\n",
seconds, (files * xattrs) / seconds);
rc = post_hook("post");
out:
if (file)
free(file);
if (value)
free(value);
return (rc);
}
static int
getxattrs(void)
{
int i, j, rnd_size, shift, rc = 0;
char name[XATTR_NAME_MAX];
char *verify_value = NULL;
char *verify_string;
char *value = NULL;
char *value_string;
char *file = NULL;
struct timeval start, stop;
double seconds;
verify_value = malloc(XATTR_SIZE_MAX);
if (verify_value == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for xattr verify\n", rc,
XATTR_SIZE_MAX);
goto out;
}
value = malloc(XATTR_SIZE_MAX);
if (value == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
XATTR_SIZE_MAX);
goto out;
}
verify_string = value_is_random ? "<random>" : verify_value;
value_string = value_is_random ? "<random>" : value;
file = malloc(PATH_MAX);
if (file == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
PATH_MAX);
goto out;
}
(void) gettimeofday(&start, NULL);
for (i = 1; i <= files; i++) {
(void) sprintf(file, "%s/file-%d", path, i);
if (nth && ((i % nth) == 0))
fprintf(stdout, "getxattr: %s\n", file);
for (j = 1; j <= xattrs; j++) {
(void) sprintf(name, "user.%d", j);
rc = lgetxattr(file, name, value, XATTR_SIZE_MAX);
if (rc == -1) {
ERROR("Error %d: lgetxattr(%s, %s, ..., %d)\n",
errno, file, name, XATTR_SIZE_MAX);
goto out;
}
if (!verify)
continue;
sscanf(value, "size=%d [a-z]", &rnd_size);
shift = sprintf(verify_value, "size=%d ",
rnd_size);
memcpy(verify_value + shift, xattrbytes,
sizeof (xattrbytes) - shift);
if (rnd_size != rc ||
memcmp(verify_value, value, rnd_size)) {
ERROR("Error %d: verify failed\n "
"verify: %s\n value: %s\n", EINVAL,
verify_string, value_string);
rc = 1;
goto out;
}
}
}
(void) gettimeofday(&stop, NULL);
seconds = timeval_sub_seconds(&stop, &start);
fprintf(stdout, "getxattr: %f seconds %f getxattrs/second\n",
seconds, (files * xattrs) / seconds);
rc = post_hook("post");
out:
if (file)
free(file);
if (value)
free(value);
if (verify_value)
free(verify_value);
return (rc);
}
static int
unlink_files(void)
{
int i, rc;
char *file = NULL;
struct timeval start, stop;
double seconds;
file = malloc(PATH_MAX);
if (file == NULL) {
rc = ENOMEM;
ERROR("Error %d: malloc(%d) bytes for file name\n",
rc, PATH_MAX);
goto out;
}
(void) gettimeofday(&start, NULL);
for (i = 1; i <= files; i++) {
(void) sprintf(file, "%s/file-%d", path, i);
if (nth && ((i % nth) == 0))
fprintf(stdout, "unlink: %s\n", file);
rc = unlink(file);
if ((rc == -1) && (errno != ENOENT)) {
ERROR("Error %d: unlink(%s)\n", errno, file);
free(file);
return (errno);
}
}
(void) gettimeofday(&stop, NULL);
seconds = timeval_sub_seconds(&stop, &start);
fprintf(stdout, "unlink: %f seconds %f unlinks/second\n",
seconds, files / seconds);
rc = post_hook("post");
out:
if (file)
free(file);
return (rc);
}
int
main(int argc, char **argv)
{
int rc;
rc = parse_args(argc, argv);
if (rc)
return (rc);
if (value_is_random) {
size_t rndsz = sizeof (xattrbytes);
rc = get_random_bytes(xattrbytes, rndsz);
if (rc < rndsz) {
ERROR("Error %d: get_random_bytes() wanted %zd "
"got %d\n", errno, rndsz, rc);
return (rc);
}
} else {
memset(xattrbytes, 'x', sizeof (xattrbytes));
}
if (phase == PHASE_ALL || phase == PHASE_CREATE) {
rc = create_files();
if (rc)
return (rc);
}
if (phase == PHASE_ALL || phase == PHASE_SETXATTR) {
rc = setxattrs();
if (rc)
return (rc);
}
if (phase == PHASE_ALL || phase == PHASE_GETXATTR) {
rc = getxattrs();
if (rc)
return (rc);
}
if (!keep_files && (phase == PHASE_ALL || phase == PHASE_UNLINK)) {
rc = unlink_files();
if (rc)
return (rc);
}
return (0);
}