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/
30 * Lustre is a trademark of Sun Microsystems, Inc.
33 #include <sys/types.h>
47 #include <libcfs/util/param.h>
49 char *dir = NULL, *dir2 = NULL;
51 char mmap_sanity[256];
53 static void usage(void)
55 printf("Usage: mmap_sanity -d dir [-m dir2] [-e <test cases>]\n");
56 printf(" -d dir lustre mount point\n");
57 printf(" -m dir2 another mount point\n");
58 printf(" -e testcases skipped test cases, -e 1 -e 2 to exclude"
59 " test cases 1 and 2.\n");
63 static int remote_tst(int tc, char *mnt);
64 static int mmap_run(int tc)
76 rc = remote_tst(tc, dir2);
79 fprintf(stderr, "invalid argument!\n");
84 static int mmap_initialize(char *myself)
86 char buf[1024], *file;
87 int fdr, fdw, count, rc = 0;
89 page_size = sysconf(_SC_PAGESIZE);
90 if (page_size == -1) {
91 perror("sysconf(_SC_PAGESIZE)");
95 /* copy myself to lustre for another client */
96 fdr = open(myself, O_RDONLY);
101 file = strrchr(myself, '/');
103 fprintf(stderr, "can't get test filename\n");
108 sprintf(mmap_sanity, "%s/%s", dir, file);
110 fdw = open(mmap_sanity, O_CREAT|O_WRONLY, 0777);
116 while ((count = read(fdr, buf, sizeof(buf))) != 0) {
124 writes = write(fdw, buf, count);
125 if (writes != count) {
136 static void mmap_finalize()
141 /* basic mmap operation on single node */
142 static int mmap_tst1(char *mnt)
144 char *ptr, mmap_file[256];
145 int region, fd, rc = 0;
147 region = page_size * 10;
148 sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
150 if (unlink(mmap_file) && errno != ENOENT) {
155 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
160 if (ftruncate(fd, region) < 0) {
161 perror("ftruncate()");
166 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
167 if (ptr == MAP_FAILED) {
172 memset(ptr, 'a', region);
181 /* MAP_PRIVATE create a copy-on-write mmap */
182 static int mmap_tst2(char *mnt)
184 char *ptr, mmap_file[256], buf[256];
187 sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
189 if (unlink(mmap_file) && errno != ENOENT) {
194 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
199 if (ftruncate(fd, page_size) < 0) {
200 perror("ftruncate()");
205 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
206 if (ptr == MAP_FAILED) {
211 memcpy(ptr, "blah", strlen("blah"));
213 munmap(ptr, page_size);
219 fd = open(mmap_file, O_RDONLY);
224 rc = read(fd, buf, sizeof(buf));
232 if (strncmp("blah", buf, strlen("blah")) == 0) {
233 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
241 /* concurrent mmap operations on two nodes */
242 static int mmap_tst3(char *mnt)
244 char *ptr, mmap_file[256];
245 int region, fd, rc = 0;
247 region = page_size * 100;
248 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
250 if (unlink(mmap_file) && errno != ENOENT) {
255 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
260 if (ftruncate(fd, region) < 0) {
261 perror("ftruncate()");
266 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
267 if (ptr == MAP_FAILED) {
277 memset(ptr, 'a', region);
278 sleep(2); /* wait for remote test finish */
287 static int remote_tst3(char *mnt)
289 char *ptr, mmap_file[256];
290 int region, fd, rc = 0;
292 region = page_size * 100;
293 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
295 fd = open(mmap_file, O_RDWR, 0600);
301 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
302 if (ptr == MAP_FAILED) {
307 memset(ptr, 'b', region);
308 memset(ptr, 'c', region);
316 /* client1 write to file_4a from mmap()ed file_4b;
317 * 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);
379 sleep(2); /* wait for remote test finish */
392 static int remote_tst4(char *mnt)
394 char *ptr, filea[256], fileb[256];
395 int region, fdr, fdw, rc = 0;
397 region = page_size * 100;
398 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
399 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
402 fdr = open(filea, O_RDWR, 0600);
407 fdw = open(fileb, O_RDWR, 0600);
414 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
415 if (ptr == MAP_FAILED) {
421 memset(ptr, '2', region);
423 rc = write(fdw, ptr, region);
439 static int cancel_lru_locks(char *filter)
451 rc = waitpid(child, &status, WNOHANG);
458 rc = cfs_get_param_paths(&paths,
459 "ldlm/namespaces/*-%s-*/lru_size",
462 rc = cfs_get_param_paths(&paths,
463 "ldlm/namespaces/*/lru_size");
467 for (i = 0; i < paths.gl_pathc; i++) {
468 FILE *f = fopen(paths.gl_pathv[i], "r");
471 fprintf(stderr, "cannot open '%s': %s\n",
472 paths.gl_pathv[i], strerror(errno));
476 rc = fwrite("clear", strlen("clear") + 1, 1, f);
479 fprintf(stderr, "fwrite failed for '%s': %s\n",
480 paths.gl_pathv[i], strerror(errno));
487 cfs_free_param_data(&paths);
491 /* don't dead lock while read/write file to/from the buffer which
492 * mmaped to just this file */
493 static int mmap_tst5(char *mnt)
495 char *ptr, mmap_file[256];
496 int region, fd, off, rc = 0;
498 region = page_size * 40;
499 off = page_size * 10;
500 sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
502 if (unlink(mmap_file) && errno != ENOENT) {
507 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
512 if (ftruncate(fd, region) < 0) {
513 perror("ftruncate()");
518 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
519 if (ptr == MAP_FAILED) {
524 memset(ptr, 'a', region);
526 /* cancel unused locks */
527 rc = cancel_lru_locks("osc");
531 /* read/write region of file and buffer should be overlap */
532 rc = read(fd, ptr + off, off * 2);
538 rc = write(fd, ptr + off, off * 2);
552 /* mmap write to a file form client1 then mmap read from client2 */
553 static int mmap_tst6(char *mnt)
555 char mmap_file[256], mmap_file2[256];
556 char *ptr = NULL, *ptr2 = NULL;
557 int fd = 0, fd2 = 0, rc = 0;
559 sprintf(mmap_file, "%s/%s", mnt, "mmap_file6");
560 sprintf(mmap_file2, "%s/%s", dir2, "mmap_file6");
561 if (unlink(mmap_file) && errno != ENOENT) {
566 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
571 if (ftruncate(fd, page_size) < 0) {
572 perror("ftruncate()");
577 fd2 = open(mmap_file2, O_RDWR, 0600);
584 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
585 if (ptr == MAP_FAILED) {
591 ptr2 = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
592 if (ptr2 == MAP_FAILED) {
598 rc = cancel_lru_locks("osc");
602 memcpy(ptr, "blah", strlen("blah"));
603 if (strncmp(ptr, ptr2, strlen("blah"))) {
604 fprintf(stderr, "client2 mmap mismatch!\n");
608 memcpy(ptr2, "foo", strlen("foo"));
609 if (strncmp(ptr, ptr2, strlen("foo"))) {
610 fprintf(stderr, "client1 mmap mismatch!\n");
615 munmap(ptr2, page_size);
617 munmap(ptr, page_size);
626 static int mmap_tst7_func(char *mnt, int rw)
629 char *buf = MAP_FAILED;
634 if (snprintf(fname, 256, "%s/mmap_tst7.%s", mnt,
635 (rw == 0) ? "read" : "write") >= 256) {
636 fprintf(stderr, "dir name too long\n");
640 fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
646 if (ftruncate(fd, 2 * page_size) == -1) {
651 buf = mmap(NULL, page_size * 2,
652 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
653 if (buf == MAP_FAILED) {
658 /* ensure the second page isn't mapped */
659 munmap(buf + page_size, page_size);
660 bytes = (rw == 0) ? read(fd, buf, 2 * page_size) :
661 write(fd, buf, 2 * page_size);
662 /* Expected behavior */
663 if (bytes == page_size)
666 fprintf(stderr, "%s returned %zd, errno = %d\n",
667 (rw == 0) ? "read" : "write", bytes, errno);
670 if (buf != MAP_FAILED)
671 munmap(buf, page_size);
677 static int mmap_tst7(char *mnt)
681 rc = mmap_tst7_func(mnt, 0);
684 rc = mmap_tst7_func(mnt, 1);
688 static int mmap_tst8(char *mnt)
691 char *buf = MAP_FAILED;
695 char xyz[page_size * 2];
697 if (snprintf(fname, 256, "%s/mmap_tst8", mnt) >= 256) {
698 fprintf(stderr, "dir name too long\n");
702 fd = open(fname, O_RDWR | O_CREAT, 0644);
708 if (ftruncate(fd, page_size) == -1) {
713 buf = mmap(NULL, page_size * 2,
714 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
715 if (buf == MAP_FAILED) {
722 if (pid == 0) { /* child */
723 memcpy(xyz, buf, page_size * 2);
724 /* shouldn't reach here. */
726 } else if (pid > 0) { /* parent */
728 pid = waitpid(pid, &status, 0);
736 if (WIFSIGNALED(status) && SIGBUS == WTERMSIG(status))
744 if (buf != MAP_FAILED)
745 munmap(buf, page_size);
751 static int remote_tst(int tc, char *mnt)
756 rc = remote_tst3(mnt);
759 rc = remote_tst4(mnt);
762 fprintf(stderr, "wrong test case number %d\n", tc);
770 int tc; /* test case number */
771 char *desc; /* test description */
772 int (*test_fn)(char *mnt); /* test function */
773 int node_cnt; /* node count */
774 int skipped; /* skipped by caller */
777 struct test_case tests[] = {
780 .desc = "mmap test1: basic mmap operation",
781 .test_fn = mmap_tst1,
786 .desc = "mmap test2: MAP_PRIVATE not write back",
787 .test_fn = mmap_tst2,
792 .desc = "mmap test3: concurrent mmap ops on "
794 .test_fn = mmap_tst3,
799 .desc = "mmap test4: c1 write to f1 from mmapped f2, "
800 "c2 write to f1 from mmapped f1",
801 .test_fn = mmap_tst4,
806 .desc = "mmap test5: read/write file to/from the "
807 "buffer which mmapped to just this file",
808 .test_fn = mmap_tst5,
813 .desc = "mmap test6: check mmap write/read content "
815 .test_fn = mmap_tst6,
820 .desc = "mmap test7: file i/o with an unmapped "
822 .test_fn = mmap_tst7,
827 .desc = "mmap test8: SIGBUS for beyond file size",
828 .test_fn = mmap_tst8,
836 int main(int argc, char **argv)
838 struct test_case *test;
839 int nr_cases = sizeof(tests)/sizeof(*test);
842 while ((c = getopt(argc, argv, "d:m:e:")) != -1) {
852 rc = strtol(optarg, &endptr, 10);
853 if (endptr != NULL && *endptr != '\0')
855 if (rc > 0 && rc < nr_cases)
856 tests[rc - 1].skipped = 1;
868 if (mmap_initialize(argv[0]) != 0) {
869 fprintf(stderr, "mmap_initialize failed!\n");
874 for (test = tests; test->tc; test++) {
875 double duration = 0.0;
876 char *rs = "SKIPPED";
878 if (!test->skipped && (test->node_cnt == 1 || dir2 != NULL)) {
879 struct timeval start, end;
881 gettimeofday(&start, NULL);
882 rc = test->test_fn(dir);
883 gettimeofday(&end, NULL);
885 duration = (double)(end.tv_sec - start.tv_sec) +
886 (double)(end.tv_usec - start.tv_usec) / 1000000;
887 rs = rc ? "FAIL" : "PASS";
890 fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);