-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
* GPL HEADER START
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
*
* GPL HEADER END
*/
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Whamcloud, Inc.
+ * Copyright (c) 2012, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* Lustre is a trademark of Sun Microsystems, Inc.
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <netdb.h>
+#include <getopt.h>
#include <string.h>
-#include <sys/wait.h>
-#include <sys/time.h>
+#include <errno.h>
+
+#include <libcfs/util/param.h>
char *dir = NULL, *dir2 = NULL;
long page_size;
static void usage(void)
{
- printf("Usage: mmap_sanity -d dir [-m dir2]\n");
- printf(" dir lustre mount point\n");
- printf(" dir2 another mount point\n");
+ printf("Usage: mmap_sanity -d dir [-m dir2] [-e <test cases>]\n");
+ printf(" -d dir lustre mount point\n");
+ printf(" -m dir2 another mount point\n");
+ printf(" -e testcases skipped test cases, -e 1 -e 2 to exclude"
+ " test cases 1 and 2.\n");
exit(127);
}
return rc;
}
-static int cancel_lru_locks(char *prefix)
+static int cancel_lru_locks(char *filter)
{
- char cmd[256], line[1024];
- FILE *file;
- pid_t child;
- int len = 1024, rc = 0;
-
- child = fork();
- if (child < 0)
- return -errno;
- else if (child) {
- int status;
- rc = waitpid(child, &status, WNOHANG);
- if (rc == child)
- rc = 0;
- return rc;
- }
-
- if (prefix)
- sprintf(cmd,
- "ls /proc/fs/lustre/ldlm/namespaces/*-%s-*/lru_size",
- prefix);
- else
- sprintf(cmd, "ls /proc/fs/lustre/ldlm/namespaces/*/lru_size");
-
- file = popen(cmd, "r");
- if (file == NULL) {
- perror("popen()");
- return -errno;
- }
-
- while (fgets(line, len, file)) {
- FILE *f;
-
- if (!strlen(line))
- continue;
- /* trim newline character */
- *(line + strlen(line) - 1) = '\0';
- f = fopen(line, "w");
- if (f == NULL) {
- perror("fopen()");
- rc = -errno;
- break;
- }
- rc = fwrite("clear", strlen("clear") + 1, 1, f);
- if (rc < 1) {
- perror("fwrite()");
- rc = -errno;
- fclose(f);
- break;
- }
- fclose(f);
- }
-
- pclose(file);
- _exit(rc);
+ glob_t paths;
+ pid_t child;
+ int rc, i;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+ else if (child) {
+ int status;
+
+ rc = waitpid(child, &status, WNOHANG);
+ if (rc == child)
+ rc = 0;
+ return rc;
+ }
+
+ if (filter != NULL)
+ rc = cfs_get_param_paths(&paths,
+ "ldlm/namespaces/*-%s-*/lru_size",
+ filter);
+ else
+ rc = cfs_get_param_paths(&paths,
+ "ldlm/namespaces/*/lru_size");
+ if (rc != 0)
+ return -EINVAL;
+
+ for (i = 0; i < paths.gl_pathc; i++) {
+ FILE *f = fopen(paths.gl_pathv[i], "r");
+ if (f == NULL) {
+ rc = -errno;
+ fprintf(stderr, "cannot open '%s': %s\n",
+ paths.gl_pathv[i], strerror(errno));
+ break;
+ }
+
+ rc = fwrite("clear", strlen("clear") + 1, 1, f);
+ if (rc < 1) {
+ rc = -errno;
+ fprintf(stderr, "fwrite failed for '%s': %s\n",
+ paths.gl_pathv[i], strerror(errno));
+ fclose(f);
+ break;
+ }
+ fclose(f);
+ }
+
+ cfs_free_param_data(&paths);
+ _exit(rc);
}
/* don't dead lock while read/write file to/from the buffer which
return rc;
}
+static int mmap_tst9(char *mnt)
+{
+ char fname[256];
+ char *buf = MAP_FAILED;
+ int fd = -1;
+ int rc = 0;
+
+ if (snprintf(fname, 256, "%s/mmap_tst9", mnt) >= 256) {
+ fprintf(stderr, "dir name too long\n");
+ rc = -ENAMETOOLONG;
+ goto out;
+ }
+ if (unlink(fname) == -1 && errno != ENOENT) {
+ perror("unlink");
+ rc = -errno;
+ goto out;
+ }
+ fd = open(fname, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) {
+ perror("open");
+ rc = -errno;
+ goto out;
+ }
+ buf = mmap(NULL, page_size * 2,
+ PROT_READ , MAP_PRIVATE, fd, (loff_t)(-10 * page_size));
+ if (buf == MAP_FAILED) {
+ perror("mmap");
+ rc = -errno;
+ goto out;
+ }
+ rc = write(STDOUT_FILENO, buf, 2 * page_size);
+ if (rc != -1) {
+ fprintf(stderr, "write succeded with %d instead of failing\n", rc);
+ rc = -EINVAL;
+ goto out;
+ } else if (errno != EFAULT) {
+ fprintf(stderr, "write failed with %d instead of EFAULT(%d)\n",
+ errno, EFAULT);
+ rc = -errno;
+ goto out;
+ }
+ rc = 0;
+out:
+ if (buf != MAP_FAILED)
+ munmap(buf, page_size * 2);
+ if (fd != -1)
+ close(fd);
+ return rc;
+}
+
static int remote_tst(int tc, char *mnt)
{
int rc = 0;
char *desc; /* test description */
int (*test_fn)(char *mnt); /* test function */
int node_cnt; /* node count */
+ int skipped; /* skipped by caller */
};
struct test_case tests[] = {
- { 1, "mmap test1: basic mmap operation", mmap_tst1, 1 },
- { 2, "mmap test2: MAP_PRIVATE not write back", mmap_tst2, 1 },
- { 3, "mmap test3: concurrent mmap ops on two nodes", mmap_tst3, 2 },
- { 4, "mmap test4: c1 write to f1 from mmapped f2, "
- "c2 write to f1 from mmapped f1", mmap_tst4, 2 },
- { 5, "mmap test5: read/write file to/from the buffer "
- "which mmapped to just this file", mmap_tst5, 1 },
- { 6, "mmap test6: check mmap write/read content on two nodes",
- mmap_tst6, 2 },
- { 7, "mmap test7: file i/o with an unmapped buffer", mmap_tst7, 1},
- { 8, "mmap test8: SIGBUS for beyond file size", mmap_tst8, 1},
- { 0, NULL, 0, 0 }
+ {
+ .tc = 1,
+ .desc = "mmap test1: basic mmap operation",
+ .test_fn = mmap_tst1,
+ .node_cnt = 1
+ },
+ {
+ .tc = 2,
+ .desc = "mmap test2: MAP_PRIVATE not write back",
+ .test_fn = mmap_tst2,
+ .node_cnt = 1
+ },
+ {
+ .tc = 3,
+ .desc = "mmap test3: concurrent mmap ops on "
+ "two nodes",
+ .test_fn = mmap_tst3,
+ .node_cnt = 2
+ },
+ {
+ .tc = 4,
+ .desc = "mmap test4: c1 write to f1 from mmapped f2, "
+ "c2 write to f1 from mmapped f1",
+ .test_fn = mmap_tst4,
+ .node_cnt = 2
+ },
+ {
+ .tc = 5,
+ .desc = "mmap test5: read/write file to/from the "
+ "buffer which mmapped to just this file",
+ .test_fn = mmap_tst5,
+ .node_cnt = 1
+ },
+ {
+ .tc = 6,
+ .desc = "mmap test6: check mmap write/read content "
+ "on two nodes",
+ .test_fn = mmap_tst6,
+ .node_cnt = 2
+ },
+ {
+ .tc = 7,
+ .desc = "mmap test7: file i/o with an unmapped "
+ "buffer",
+ .test_fn = mmap_tst7,
+ .node_cnt = 1
+ },
+ {
+ .tc = 8,
+ .desc = "mmap test8: SIGBUS for beyond file size",
+ .test_fn = mmap_tst8,
+ .node_cnt = 1
+ },
+ {
+ .tc = 9,
+ .desc = "mmap test9: SIGBUS for negative file offset",
+ .test_fn = mmap_tst9,
+ .node_cnt = 1
+ },
+ {
+ .tc = 0
+ }
};
int main(int argc, char **argv)
{
struct test_case *test;
+ int nr_cases = sizeof(tests)/sizeof(*test);
int c, rc = 0;
- while ((c = getopt(argc, argv, "d:m:")) != -1) {
+ while ((c = getopt(argc, argv, "d:m:e:")) != -1) {
switch (c) {
case 'd':
dir = optarg;
case 'm':
dir2 = optarg;
break;
+ case 'e': {
+ char *endptr = NULL;
+ rc = strtol(optarg, &endptr, 10);
+ if (endptr != NULL && *endptr != '\0')
+ usage();
+ if (rc > 0 && rc < nr_cases)
+ tests[rc - 1].skipped = 1;
+ break;
+ }
default:
usage();
break;
return -EINVAL;
}
+ rc = 0;
for (test = tests; test->tc; test++) {
- double duration;
- char *rs;
+ double duration = 0.0;
+ char *rs = "SKIPPED";
- if (test->node_cnt == 1 || dir2 != NULL) {
+ if (!test->skipped && (test->node_cnt == 1 || dir2 != NULL)) {
struct timeval start, end;
gettimeofday(&start, NULL);
duration = (double)(end.tv_sec - start.tv_sec) +
(double)(end.tv_usec - start.tv_usec) / 1000000;
rs = rc ? "FAIL" : "PASS";
- } else {
- duration = 0.0;
- rs = "SKIP";
}
+
fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);
if (rc)
break;