4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2012, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
32 #include <sys/types.h>
46 #include <libcfs/util/param.h>
48 char *dir = NULL, *dir2 = NULL;
50 char mmap_sanity[256];
52 static void usage(void)
54 printf("Usage: mmap_sanity -d dir [-m dir2] [-e <test cases>]\n");
55 printf(" -d dir lustre mount point\n");
56 printf(" -m dir2 another mount point\n");
57 printf(" -e testcases skipped test cases, -e 1 -e 2 to exclude test cases 1 and 2.\n");
61 static int remote_tst(int tc, char *mnt);
62 static int mmap_run(int tc)
74 rc = remote_tst(tc, dir2);
77 fprintf(stderr, "invalid argument!\n");
82 static int mmap_initialize(char *myself)
84 char buf[1024], *file;
85 int fdr, fdw, count, rc = 0;
87 page_size = sysconf(_SC_PAGESIZE);
88 if (page_size == -1) {
89 perror("sysconf(_SC_PAGESIZE)");
93 /* copy myself to lustre for another client */
94 fdr = open(myself, O_RDONLY);
99 file = strrchr(myself, '/');
101 fprintf(stderr, "can't get test filename\n");
106 sprintf(mmap_sanity, "%s/%s", dir, file);
108 fdw = open(mmap_sanity, O_CREAT | O_WRONLY, 0777);
114 while ((count = read(fdr, buf, sizeof(buf))) != 0) {
122 writes = write(fdw, buf, count);
123 if (writes != count) {
134 static void mmap_finalize()
139 /* basic mmap operation on single node */
140 static int mmap_tst1(char *mnt)
142 char *ptr, mmap_file[256];
143 int region, fd, rc = 0;
145 region = page_size * 10;
146 sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
148 if (unlink(mmap_file) && errno != ENOENT) {
153 fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
158 if (ftruncate(fd, region) < 0) {
159 perror("ftruncate()");
164 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
165 if (ptr == MAP_FAILED) {
170 memset(ptr, 'a', region);
179 /* MAP_PRIVATE create a copy-on-write mmap */
180 static int mmap_tst2(char *mnt)
182 char *ptr, mmap_file[256], buf[256];
185 sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
187 if (unlink(mmap_file) && errno != ENOENT) {
192 fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
197 if (ftruncate(fd, page_size) < 0) {
198 perror("ftruncate()");
203 ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
204 if (ptr == MAP_FAILED) {
209 memcpy(ptr, "blah", strlen("blah"));
211 munmap(ptr, page_size);
217 fd = open(mmap_file, O_RDONLY);
222 rc = read(fd, buf, sizeof(buf));
230 if (strncmp("blah", buf, strlen("blah")) == 0) {
231 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
239 /* concurrent mmap operations on two nodes */
240 static int mmap_tst3(char *mnt)
242 char *ptr, mmap_file[256];
243 int region, fd, rc = 0;
245 region = page_size * 100;
246 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
248 if (unlink(mmap_file) && errno != ENOENT) {
253 fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
258 if (ftruncate(fd, region) < 0) {
259 perror("ftruncate()");
264 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
265 if (ptr == MAP_FAILED) {
275 memset(ptr, 'a', region);
276 sleep(2); /* wait for remote test finish */
285 static int remote_tst3(char *mnt)
287 char *ptr, mmap_file[256];
288 int region, fd, rc = 0;
290 region = page_size * 100;
291 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
293 fd = open(mmap_file, O_RDWR, 0600);
299 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
300 if (ptr == MAP_FAILED) {
305 memset(ptr, 'b', region);
306 memset(ptr, 'c', region);
315 * client1 write to file_4a from mmap()ed file_4b;
316 * client2 write to file_4b from mmap()ed file_4a.
318 static int mmap_tst4(char *mnt)
320 char *ptr, filea[256], fileb[256];
321 int region, fdr, fdw, rc = 0;
323 region = page_size * 100;
324 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
325 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
327 if (unlink(filea) && errno != ENOENT) {
331 if (unlink(fileb) && errno != ENOENT) {
337 fdr = open(fileb, O_CREAT | O_RDWR, 0600);
342 if (ftruncate(fdr, region) < 0) {
343 perror("ftruncate()");
347 fdw = open(filea, O_CREAT | O_RDWR, 0600);
353 if (ftruncate(fdw, region) < 0) {
354 perror("ftruncate()");
359 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fdr, 0);
360 if (ptr == MAP_FAILED) {
370 memset(ptr, '1', region);
372 rc = write(fdw, ptr, region);
380 sleep(2); /* wait for remote test finish */
393 static int remote_tst4(char *mnt)
395 char *ptr, filea[256], fileb[256];
396 int region, fdr, fdw, rc = 0;
398 region = page_size * 100;
399 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
400 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
403 fdr = open(filea, O_RDWR, 0600);
408 fdw = open(fileb, O_RDWR, 0600);
415 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fdr, 0);
416 if (ptr == MAP_FAILED) {
422 memset(ptr, '2', region);
424 rc = write(fdw, ptr, region);
441 static int cancel_lru_locks(char *filter)
453 rc = waitpid(child, &status, WNOHANG);
460 rc = cfs_get_param_paths(&paths,
461 "ldlm/namespaces/*-%s-*/lru_size",
464 rc = cfs_get_param_paths(&paths,
465 "ldlm/namespaces/*/lru_size");
469 for (i = 0; i < paths.gl_pathc; i++) {
470 FILE *f = fopen(paths.gl_pathv[i], "r+");
474 fprintf(stderr, "cannot open '%s': %s\n",
475 paths.gl_pathv[i], strerror(errno));
479 rc = fwrite("clear", strlen("clear") + 1, 1, f);
482 fprintf(stderr, "fwrite failed for '%s': %s\n",
483 paths.gl_pathv[i], strerror(errno));
490 cfs_free_param_data(&paths);
495 * don't dead lock while read/write file to/from the buffer which
496 * mmaped to just this file
498 static int mmap_tst5(char *mnt)
500 char *ptr, mmap_file[256];
501 int region, fd, off, rc = 0;
503 region = page_size * 40;
504 off = page_size * 10;
505 sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
507 if (unlink(mmap_file) && errno != ENOENT) {
512 fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
517 if (ftruncate(fd, region) < 0) {
518 perror("ftruncate()");
523 ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
524 if (ptr == MAP_FAILED) {
529 memset(ptr, 'a', region);
531 /* cancel unused locks */
532 rc = cancel_lru_locks("osc");
536 /* read/write region of file and buffer should be overlap */
537 rc = read(fd, ptr + off, off * 2);
543 rc = write(fd, ptr + off, off * 2);
557 /* mmap write to a file form client1 then mmap read from client2 */
558 static int mmap_tst6(char *mnt)
560 char mmap_file[256], mmap_file2[256];
561 char *ptr = NULL, *ptr2 = NULL;
562 int fd = 0, fd2 = 0, rc = 0;
564 sprintf(mmap_file, "%s/%s", mnt, "mmap_file6");
565 sprintf(mmap_file2, "%s/%s", dir2, "mmap_file6");
566 if (unlink(mmap_file) && errno != ENOENT) {
571 fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
576 if (ftruncate(fd, page_size) < 0) {
577 perror("ftruncate()");
582 fd2 = open(mmap_file2, O_RDWR, 0600);
589 ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
590 if (ptr == MAP_FAILED) {
596 ptr2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
598 if (ptr2 == MAP_FAILED) {
604 rc = cancel_lru_locks("osc");
608 memcpy(ptr, "blah", strlen("blah"));
609 if (strncmp(ptr, ptr2, strlen("blah"))) {
610 fprintf(stderr, "client2 mmap mismatch!\n");
614 memcpy(ptr2, "foo", strlen("foo"));
615 if (strncmp(ptr, ptr2, strlen("foo"))) {
616 fprintf(stderr, "client1 mmap mismatch!\n");
621 munmap(ptr2, page_size);
623 munmap(ptr, page_size);
632 static int mmap_tst7_func(char *mnt, int rw)
635 char *buf = MAP_FAILED;
640 if (snprintf(fname, 256, "%s/mmap_tst7.%s", mnt,
641 (rw == 0) ? "read" : "write") >= 256) {
642 fprintf(stderr, "dir name too long\n");
646 fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
652 if (ftruncate(fd, 2 * page_size) == -1) {
657 buf = mmap(NULL, page_size * 2,
658 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
659 if (buf == MAP_FAILED) {
664 /* ensure the second page isn't mapped */
665 munmap(buf + page_size, page_size);
666 bytes = (rw == 0) ? read(fd, buf, 2 * page_size) :
667 write(fd, buf, 2 * page_size);
668 /* Expected behavior */
669 if (bytes == page_size)
672 fprintf(stderr, "%s returned %zd, errno = %d\n",
673 (rw == 0) ? "read" : "write", bytes, errno);
676 if (buf != MAP_FAILED)
677 munmap(buf, page_size);
683 static int mmap_tst7(char *mnt)
687 rc = mmap_tst7_func(mnt, 0);
690 rc = mmap_tst7_func(mnt, 1);
694 static int mmap_tst8(char *mnt)
697 char *buf = MAP_FAILED;
701 char xyz[page_size * 2];
703 if (snprintf(fname, 256, "%s/mmap_tst8", mnt) >= 256) {
704 fprintf(stderr, "dir name too long\n");
708 fd = open(fname, O_RDWR | O_CREAT, 0644);
714 if (ftruncate(fd, page_size) == -1) {
719 buf = mmap(NULL, page_size * 2,
720 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
721 if (buf == MAP_FAILED) {
728 if (pid == 0) { /* child */
729 memcpy(xyz, buf, page_size * 2);
730 /* shouldn't reach here. */
732 } else if (pid > 0) { /* parent */
735 pid = waitpid(pid, &status, 0);
743 if (WIFSIGNALED(status) && SIGBUS == WTERMSIG(status))
751 if (buf != MAP_FAILED)
752 munmap(buf, page_size);
758 static int mmap_tst9(char *mnt)
761 char *buf = MAP_FAILED;
765 if (snprintf(fname, 256, "%s/mmap_tst9", mnt) >= 256) {
766 fprintf(stderr, "dir name too long\n");
770 if (unlink(fname) == -1 && errno != ENOENT) {
775 fd = open(fname, O_RDWR | O_CREAT, 0644);
781 buf = mmap(NULL, page_size * 2,
782 PROT_READ, MAP_PRIVATE, fd, (loff_t)(-10 * page_size));
783 if (buf == MAP_FAILED) {
788 rc = write(STDOUT_FILENO, buf, 2 * page_size);
790 fprintf(stderr, "write succeded with %d instead of failing\n",
794 } else if (errno != EFAULT) {
795 fprintf(stderr, "write failed with %d instead of EFAULT(%d)\n",
802 if (buf != MAP_FAILED)
803 munmap(buf, page_size * 2);
809 static int mmap_tst10(char *mnt)
811 char *buf = MAP_FAILED;
813 struct stat st1, st2;
818 /* cancel unused locks */
819 rc = cancel_lru_locks("osc");
823 fd = open(mmap_sanity, O_RDONLY);
830 if (fstat(fd, &st1) != 0) {
838 buf = mmap(NULL, st1.st_size, PROT_READ | PROT_WRITE,
839 MAP_PRIVATE | MAP_NORESERVE, fd, 0);
840 if (buf == MAP_FAILED) {
847 for (off = 0; off + 256 <= st1.st_size; off += 256)
848 memcpy(buffer, off + buf, 256);
850 if (fstat(fd, &st2) != 0) {
856 if (st1.st_mtime != st2.st_mtime) {
857 fprintf(stderr, "before mmap read mtime(%ld) != after mtime=(%ld)\n",
858 st1.st_mtime, st2.st_mtime);
863 if (buf != MAP_FAILED)
864 munmap(buf, st1.st_size);
870 static int remote_tst(int tc, char *mnt)
876 rc = remote_tst3(mnt);
879 rc = remote_tst4(mnt);
882 fprintf(stderr, "wrong test case number %d\n", tc);
890 int tc; /* test case number */
891 char *desc; /* test description */
892 int (*test_fn)(char *mnt); /* test function */
893 int node_cnt; /* node count */
894 int skipped; /* skipped by caller */
897 struct test_case tests[] = {
900 .desc = "mmap test1: basic mmap operation",
901 .test_fn = mmap_tst1,
906 .desc = "mmap test2: MAP_PRIVATE not write back",
907 .test_fn = mmap_tst2,
912 .desc = "mmap test3: concurrent mmap ops on two nodes",
913 .test_fn = mmap_tst3,
918 .desc = "mmap test4: c1 write to f1 from mmapped f2, c2 write to f1 from mmapped f1",
919 .test_fn = mmap_tst4,
924 .desc = "mmap test5: read/write file to/from the buffer which mmapped to just this file",
925 .test_fn = mmap_tst5,
930 .desc = "mmap test6: check mmap write/read content on two nodes",
931 .test_fn = mmap_tst6,
936 .desc = "mmap test7: file i/o with an unmapped buffer",
937 .test_fn = mmap_tst7,
942 .desc = "mmap test8: SIGBUS for beyond file size",
943 .test_fn = mmap_tst8,
948 .desc = "mmap test9: SIGBUS for negative file offset",
949 .test_fn = mmap_tst9,
954 .desc = "mmap test10: mtime not change for readonly mmap access",
955 .test_fn = mmap_tst10,
963 int main(int argc, char **argv)
965 struct test_case *test;
966 int nr_cases = sizeof(tests) / sizeof(*test);
969 while ((c = getopt(argc, argv, "d:m:e:")) != -1) {
980 rc = strtol(optarg, &endptr, 10);
981 if (endptr && *endptr != '\0')
983 if (rc > 0 && rc < nr_cases)
984 tests[rc - 1].skipped = 1;
996 if (mmap_initialize(argv[0]) != 0) {
997 fprintf(stderr, "mmap_initialize failed!\n");
1002 for (test = tests; test->tc; test++) {
1003 double duration = 0.0;
1004 char *rs = "SKIPPED";
1006 if (!test->skipped && (test->node_cnt == 1 || dir2)) {
1007 struct timeval start, end;
1009 gettimeofday(&start, NULL);
1010 rc = test->test_fn(dir);
1011 gettimeofday(&end, NULL);
1013 duration = (double)(end.tv_sec - start.tv_sec) +
1014 (double)(end.tv_usec - start.tv_usec) / 1000000;
1015 rs = rc ? "FAIL" : "PASS";
1018 fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);