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.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2012, 2015, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #include <sys/types.h>
51 #include <libcfs/util/param.h>
53 char *dir = NULL, *dir2 = NULL;
55 char mmap_sanity[256];
57 static void usage(void)
59 printf("Usage: mmap_sanity -d dir [-m dir2] [-e <test cases>]\n");
60 printf(" -d dir lustre mount point\n");
61 printf(" -m dir2 another mount point\n");
62 printf(" -e testcases skipped test cases, -e 1 -e 2 to exclude"
63 " test cases 1 and 2.\n");
67 static int remote_tst(int tc, char *mnt);
68 static int mmap_run(int tc)
80 rc = remote_tst(tc, dir2);
83 fprintf(stderr, "invalid argument!\n");
88 static int mmap_initialize(char *myself)
90 char buf[1024], *file;
91 int fdr, fdw, count, rc = 0;
93 page_size = sysconf(_SC_PAGESIZE);
94 if (page_size == -1) {
95 perror("sysconf(_SC_PAGESIZE)");
99 /* copy myself to lustre for another client */
100 fdr = open(myself, O_RDONLY);
105 file = strrchr(myself, '/');
107 fprintf(stderr, "can't get test filename\n");
112 sprintf(mmap_sanity, "%s/%s", dir, file);
114 fdw = open(mmap_sanity, O_CREAT|O_WRONLY, 0777);
120 while ((count = read(fdr, buf, sizeof(buf))) != 0) {
128 writes = write(fdw, buf, count);
129 if (writes != count) {
140 static void mmap_finalize()
145 /* basic mmap operation on single node */
146 static int mmap_tst1(char *mnt)
148 char *ptr, mmap_file[256];
149 int region, fd, rc = 0;
151 region = page_size * 10;
152 sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
154 if (unlink(mmap_file) && errno != ENOENT) {
159 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
164 if (ftruncate(fd, region) < 0) {
165 perror("ftruncate()");
170 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
171 if (ptr == MAP_FAILED) {
176 memset(ptr, 'a', region);
185 /* MAP_PRIVATE create a copy-on-write mmap */
186 static int mmap_tst2(char *mnt)
188 char *ptr, mmap_file[256], buf[256];
191 sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
193 if (unlink(mmap_file) && errno != ENOENT) {
198 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
203 if (ftruncate(fd, page_size) < 0) {
204 perror("ftruncate()");
209 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
210 if (ptr == MAP_FAILED) {
215 memcpy(ptr, "blah", strlen("blah"));
217 munmap(ptr, page_size);
223 fd = open(mmap_file, O_RDONLY);
228 rc = read(fd, buf, sizeof(buf));
236 if (strncmp("blah", buf, strlen("blah")) == 0) {
237 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
245 /* concurrent mmap operations on two nodes */
246 static int mmap_tst3(char *mnt)
248 char *ptr, mmap_file[256];
249 int region, fd, rc = 0;
251 region = page_size * 100;
252 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
254 if (unlink(mmap_file) && errno != ENOENT) {
259 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
264 if (ftruncate(fd, region) < 0) {
265 perror("ftruncate()");
270 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
271 if (ptr == MAP_FAILED) {
281 memset(ptr, 'a', region);
282 sleep(2); /* wait for remote test finish */
291 static int remote_tst3(char *mnt)
293 char *ptr, mmap_file[256];
294 int region, fd, rc = 0;
296 region = page_size * 100;
297 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
299 fd = open(mmap_file, O_RDWR, 0600);
305 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
306 if (ptr == MAP_FAILED) {
311 memset(ptr, 'b', region);
312 memset(ptr, 'c', region);
320 /* client1 write to file_4a from mmap()ed file_4b;
321 * client2 write to file_4b from mmap()ed file_4a. */
322 static int mmap_tst4(char *mnt)
324 char *ptr, filea[256], fileb[256];
325 int region, fdr, fdw, rc = 0;
327 region = page_size * 100;
328 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
329 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
331 if (unlink(filea) && errno != ENOENT) {
335 if (unlink(fileb) && errno != ENOENT) {
341 fdr = open(fileb, O_CREAT|O_RDWR, 0600);
346 if (ftruncate(fdr, region) < 0) {
347 perror("ftruncate()");
351 fdw = open(filea, O_CREAT|O_RDWR, 0600);
357 if (ftruncate(fdw, region) < 0) {
358 perror("ftruncate()");
363 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
364 if (ptr == MAP_FAILED) {
374 memset(ptr, '1', region);
376 rc = write(fdw, ptr, region);
383 sleep(2); /* wait for remote test finish */
396 static int remote_tst4(char *mnt)
398 char *ptr, filea[256], fileb[256];
399 int region, fdr, fdw, rc = 0;
401 region = page_size * 100;
402 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
403 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
406 fdr = open(filea, O_RDWR, 0600);
411 fdw = open(fileb, O_RDWR, 0600);
418 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
419 if (ptr == MAP_FAILED) {
425 memset(ptr, '2', region);
427 rc = write(fdw, ptr, region);
443 static int cancel_lru_locks(char *filter)
455 rc = waitpid(child, &status, WNOHANG);
462 rc = cfs_get_param_paths(&paths,
463 "ldlm/namespaces/*-%s-*/lru_size",
466 rc = cfs_get_param_paths(&paths,
467 "ldlm/namespaces/*/lru_size");
471 for (i = 0; i < paths.gl_pathc; i++) {
472 FILE *f = fopen(paths.gl_pathv[i], "r");
475 fprintf(stderr, "cannot open '%s': %s\n",
476 paths.gl_pathv[i], strerror(errno));
480 rc = fwrite("clear", strlen("clear") + 1, 1, f);
483 fprintf(stderr, "fwrite failed for '%s': %s\n",
484 paths.gl_pathv[i], strerror(errno));
491 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 */
497 static int mmap_tst5(char *mnt)
499 char *ptr, mmap_file[256];
500 int region, fd, off, rc = 0;
502 region = page_size * 40;
503 off = page_size * 10;
504 sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
506 if (unlink(mmap_file) && errno != ENOENT) {
511 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
516 if (ftruncate(fd, region) < 0) {
517 perror("ftruncate()");
522 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
523 if (ptr == MAP_FAILED) {
528 memset(ptr, 'a', region);
530 /* cancel unused locks */
531 rc = cancel_lru_locks("osc");
535 /* read/write region of file and buffer should be overlap */
536 rc = read(fd, ptr + off, off * 2);
542 rc = write(fd, ptr + off, off * 2);
556 /* mmap write to a file form client1 then mmap read from client2 */
557 static int mmap_tst6(char *mnt)
559 char mmap_file[256], mmap_file2[256];
560 char *ptr = NULL, *ptr2 = NULL;
561 int fd = 0, fd2 = 0, rc = 0;
563 sprintf(mmap_file, "%s/%s", mnt, "mmap_file6");
564 sprintf(mmap_file2, "%s/%s", dir2, "mmap_file6");
565 if (unlink(mmap_file) && errno != ENOENT) {
570 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
575 if (ftruncate(fd, page_size) < 0) {
576 perror("ftruncate()");
581 fd2 = open(mmap_file2, O_RDWR, 0600);
588 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
589 if (ptr == MAP_FAILED) {
595 ptr2 = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
596 if (ptr2 == MAP_FAILED) {
602 rc = cancel_lru_locks("osc");
606 memcpy(ptr, "blah", strlen("blah"));
607 if (strncmp(ptr, ptr2, strlen("blah"))) {
608 fprintf(stderr, "client2 mmap mismatch!\n");
612 memcpy(ptr2, "foo", strlen("foo"));
613 if (strncmp(ptr, ptr2, strlen("foo"))) {
614 fprintf(stderr, "client1 mmap mismatch!\n");
619 munmap(ptr2, page_size);
621 munmap(ptr, page_size);
630 static int mmap_tst7_func(char *mnt, int rw)
633 char *buf = MAP_FAILED;
638 if (snprintf(fname, 256, "%s/mmap_tst7.%s", mnt,
639 (rw == 0) ? "read" : "write") >= 256) {
640 fprintf(stderr, "dir name too long\n");
644 fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
650 if (ftruncate(fd, 2 * page_size) == -1) {
655 buf = mmap(NULL, page_size * 2,
656 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
657 if (buf == MAP_FAILED) {
662 /* ensure the second page isn't mapped */
663 munmap(buf + page_size, page_size);
664 bytes = (rw == 0) ? read(fd, buf, 2 * page_size) :
665 write(fd, buf, 2 * page_size);
666 /* Expected behavior */
667 if (bytes == page_size)
670 fprintf(stderr, "%s returned %zd, errno = %d\n",
671 (rw == 0) ? "read" : "write", bytes, errno);
674 if (buf != MAP_FAILED)
675 munmap(buf, page_size);
681 static int mmap_tst7(char *mnt)
685 rc = mmap_tst7_func(mnt, 0);
688 rc = mmap_tst7_func(mnt, 1);
692 static int mmap_tst8(char *mnt)
695 char *buf = MAP_FAILED;
699 char xyz[page_size * 2];
701 if (snprintf(fname, 256, "%s/mmap_tst8", mnt) >= 256) {
702 fprintf(stderr, "dir name too long\n");
706 fd = open(fname, O_RDWR | O_CREAT, 0644);
712 if (ftruncate(fd, page_size) == -1) {
717 buf = mmap(NULL, page_size * 2,
718 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
719 if (buf == MAP_FAILED) {
726 if (pid == 0) { /* child */
727 memcpy(xyz, buf, page_size * 2);
728 /* shouldn't reach here. */
730 } else if (pid > 0) { /* parent */
732 pid = waitpid(pid, &status, 0);
740 if (WIFSIGNALED(status) && SIGBUS == WTERMSIG(status))
748 if (buf != MAP_FAILED)
749 munmap(buf, page_size);
755 static int remote_tst(int tc, char *mnt)
760 rc = remote_tst3(mnt);
763 rc = remote_tst4(mnt);
766 fprintf(stderr, "wrong test case number %d\n", tc);
774 int tc; /* test case number */
775 char *desc; /* test description */
776 int (*test_fn)(char *mnt); /* test function */
777 int node_cnt; /* node count */
778 int skipped; /* skipped by caller */
781 struct test_case tests[] = {
782 { 1, "mmap test1: basic mmap operation", mmap_tst1, 1 },
783 { 2, "mmap test2: MAP_PRIVATE not write back", mmap_tst2, 1 },
784 { 3, "mmap test3: concurrent mmap ops on two nodes", mmap_tst3, 2 },
785 { 4, "mmap test4: c1 write to f1 from mmapped f2, "
786 "c2 write to f1 from mmapped f1", mmap_tst4, 2 },
787 { 5, "mmap test5: read/write file to/from the buffer "
788 "which mmapped to just this file", mmap_tst5, 1 },
789 { 6, "mmap test6: check mmap write/read content on two nodes",
791 { 7, "mmap test7: file i/o with an unmapped buffer", mmap_tst7, 1},
792 { 8, "mmap test8: SIGBUS for beyond file size", mmap_tst8, 1 },
796 int main(int argc, char **argv)
798 struct test_case *test;
799 int nr_cases = sizeof(tests)/sizeof(*test);
802 while ((c = getopt(argc, argv, "d:m:e:")) != -1) {
812 rc = strtol(optarg, &endptr, 10);
813 if (endptr != NULL && *endptr != '\0')
815 if (rc > 0 && rc < nr_cases)
816 tests[rc - 1].skipped = 1;
828 if (mmap_initialize(argv[0]) != 0) {
829 fprintf(stderr, "mmap_initialize failed!\n");
834 for (test = tests; test->tc; test++) {
835 double duration = 0.0;
836 char *rs = "SKIPPED";
838 if (!test->skipped && (test->node_cnt == 1 || dir2 != NULL)) {
839 struct timeval start, end;
841 gettimeofday(&start, NULL);
842 rc = test->test_fn(dir);
843 gettimeofday(&end, NULL);
845 duration = (double)(end.tv_sec - start.tv_sec) +
846 (double)(end.tv_usec - start.tv_usec) / 1000000;
847 rs = rc ? "FAIL" : "PASS";
850 fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);