1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
32 * Copyright (c) 2012, Whamcloud, Inc.
35 * This file is part of Lustre, http://www.lustre.org/
36 * Lustre is a trademark of Sun Microsystems, Inc.
44 #include <sys/types.h>
47 #include <netinet/in.h>
48 #include <sys/socket.h>
54 char *dir = NULL, *dir2 = NULL;
56 char mmap_sanity[256];
58 static void usage(void)
60 printf("Usage: mmap_sanity -d dir [-m dir2]\n");
61 printf(" dir lustre mount point\n");
62 printf(" dir2 another mount point\n");
66 static int remote_tst(int tc, char *mnt);
67 static int mmap_run(int tc)
79 rc = remote_tst(tc, dir2);
82 fprintf(stderr, "invalid argument!\n");
87 static int mmap_initialize(char *myself)
89 char buf[1024], *file;
90 int fdr, fdw, count, rc = 0;
92 page_size = sysconf(_SC_PAGESIZE);
93 if (page_size == -1) {
94 perror("sysconf(_SC_PAGESIZE)");
98 /* copy myself to lustre for another client */
99 fdr = open(myself, O_RDONLY);
104 file = strrchr(myself, '/');
106 fprintf(stderr, "can't get test filename\n");
111 sprintf(mmap_sanity, "%s/%s", dir, file);
113 fdw = open(mmap_sanity, O_CREAT|O_WRONLY, 0777);
119 while ((count = read(fdr, buf, sizeof(buf))) != 0) {
127 writes = write(fdw, buf, count);
128 if (writes != count) {
139 static void mmap_finalize()
144 /* basic mmap operation on single node */
145 static int mmap_tst1(char *mnt)
147 char *ptr, mmap_file[256];
148 int region, fd, rc = 0;
150 region = page_size * 10;
151 sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
153 if (unlink(mmap_file) && errno != ENOENT) {
158 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
163 if (ftruncate(fd, region) < 0) {
164 perror("ftruncate()");
169 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
170 if (ptr == MAP_FAILED) {
175 memset(ptr, 'a', region);
184 /* MAP_PRIVATE create a copy-on-write mmap */
185 static int mmap_tst2(char *mnt)
187 char *ptr, mmap_file[256], buf[256];
190 sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
192 if (unlink(mmap_file) && errno != ENOENT) {
197 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
202 if (ftruncate(fd, page_size) < 0) {
203 perror("ftruncate()");
208 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
209 if (ptr == MAP_FAILED) {
214 memcpy(ptr, "blah", strlen("blah"));
216 munmap(ptr, page_size);
222 fd = open(mmap_file, O_RDONLY);
227 rc = read(fd, buf, sizeof(buf));
235 if (strncmp("blah", buf, strlen("blah")) == 0) {
236 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
244 /* concurrent mmap operations on two nodes */
245 static int mmap_tst3(char *mnt)
247 char *ptr, mmap_file[256];
248 int region, fd, rc = 0;
250 region = page_size * 100;
251 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
253 if (unlink(mmap_file) && errno != ENOENT) {
258 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
263 if (ftruncate(fd, region) < 0) {
264 perror("ftruncate()");
269 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
270 if (ptr == MAP_FAILED) {
280 memset(ptr, 'a', region);
281 sleep(2); /* wait for remote test finish */
290 static int remote_tst3(char *mnt)
292 char *ptr, mmap_file[256];
293 int region, fd, rc = 0;
295 region = page_size * 100;
296 sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
298 fd = open(mmap_file, O_RDWR, 0600);
304 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
305 if (ptr == MAP_FAILED) {
310 memset(ptr, 'b', region);
311 memset(ptr, 'c', region);
319 /* client1 write to file_4a from mmap()ed file_4b;
320 * client2 write to file_4b from mmap()ed file_4a. */
321 static int mmap_tst4(char *mnt)
323 char *ptr, filea[256], fileb[256];
324 int region, fdr, fdw, rc = 0;
326 region = page_size * 100;
327 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
328 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
330 if (unlink(filea) && errno != ENOENT) {
334 if (unlink(fileb) && errno != ENOENT) {
340 fdr = open(fileb, O_CREAT|O_RDWR, 0600);
345 if (ftruncate(fdr, region) < 0) {
346 perror("ftruncate()");
350 fdw = open(filea, O_CREAT|O_RDWR, 0600);
356 if (ftruncate(fdw, region) < 0) {
357 perror("ftruncate()");
362 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
363 if (ptr == MAP_FAILED) {
373 memset(ptr, '1', region);
375 rc = write(fdw, ptr, region);
382 sleep(2); /* wait for remote test finish */
395 static int remote_tst4(char *mnt)
397 char *ptr, filea[256], fileb[256];
398 int region, fdr, fdw, rc = 0;
400 region = page_size * 100;
401 sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
402 sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
405 fdr = open(filea, O_RDWR, 0600);
410 fdw = open(fileb, O_RDWR, 0600);
417 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
418 if (ptr == MAP_FAILED) {
424 memset(ptr, '2', region);
426 rc = write(fdw, ptr, region);
442 static int cancel_lru_locks(char *prefix)
444 char cmd[256], line[1024];
447 int len = 1024, rc = 0;
454 rc = waitpid(child, &status, WNOHANG);
462 "ls /proc/fs/lustre/ldlm/namespaces/*-%s-*/lru_size",
465 sprintf(cmd, "ls /proc/fs/lustre/ldlm/namespaces/*/lru_size");
467 file = popen(cmd, "r");
473 while (fgets(line, len, file)) {
478 /* trim newline character */
479 *(line + strlen(line) - 1) = '\0';
480 f = fopen(line, "w");
486 rc = fwrite("clear", strlen("clear") + 1, 1, f);
500 /* don't dead lock while read/write file to/from the buffer which
501 * mmaped to just this file */
502 static int mmap_tst5(char *mnt)
504 char *ptr, mmap_file[256];
505 int region, fd, off, rc = 0;
507 region = page_size * 40;
508 off = page_size * 10;
509 sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
511 if (unlink(mmap_file) && errno != ENOENT) {
516 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
521 if (ftruncate(fd, region) < 0) {
522 perror("ftruncate()");
527 ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
528 if (ptr == MAP_FAILED) {
533 memset(ptr, 'a', region);
535 /* cancel unused locks */
536 rc = cancel_lru_locks("osc");
540 /* read/write region of file and buffer should be overlap */
541 rc = read(fd, ptr + off, off * 2);
547 rc = write(fd, ptr + off, off * 2);
561 /* mmap write to a file form client1 then mmap read from client2 */
562 static int mmap_tst6(char *mnt)
564 char mmap_file[256], mmap_file2[256];
565 char *ptr = NULL, *ptr2 = NULL;
566 int fd = 0, fd2 = 0, rc = 0;
568 sprintf(mmap_file, "%s/%s", mnt, "mmap_file6");
569 sprintf(mmap_file2, "%s/%s", dir2, "mmap_file6");
570 if (unlink(mmap_file) && errno != ENOENT) {
575 fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
580 if (ftruncate(fd, page_size) < 0) {
581 perror("ftruncate()");
586 fd2 = open(mmap_file2, O_RDWR, 0600);
593 ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
594 if (ptr == MAP_FAILED) {
600 ptr2 = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
601 if (ptr2 == MAP_FAILED) {
607 rc = cancel_lru_locks("osc");
611 memcpy(ptr, "blah", strlen("blah"));
612 if (strncmp(ptr, ptr2, strlen("blah"))) {
613 fprintf(stderr, "client2 mmap mismatch!\n");
617 memcpy(ptr2, "foo", strlen("foo"));
618 if (strncmp(ptr, ptr2, strlen("foo"))) {
619 fprintf(stderr, "client1 mmap mismatch!\n");
624 munmap(ptr2, page_size);
626 munmap(ptr, page_size);
635 static int mmap_tst7_func(char *mnt, int rw)
638 char *buf = MAP_FAILED;
643 if (snprintf(fname, 256, "%s/mmap_tst7.%s", mnt,
644 (rw == 0) ? "read" : "write") >= 256) {
645 fprintf(stderr, "dir name too long\n");
649 fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
655 if (ftruncate(fd, 2 * page_size) == -1) {
660 buf = mmap(NULL, page_size * 2,
661 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
662 if (buf == MAP_FAILED) {
667 /* ensure the second page isn't mapped */
668 munmap(buf + page_size, page_size);
669 bytes = (rw == 0) ? read(fd, buf, 2 * page_size) :
670 write(fd, buf, 2 * page_size);
671 /* Expected behavior */
672 if (bytes == page_size)
675 fprintf(stderr, "%s returned %zd, errno = %d\n",
676 (rw == 0) ? "read" : "write", bytes, errno);
679 if (buf != MAP_FAILED)
680 munmap(buf, page_size);
686 static int mmap_tst7(char *mnt)
690 rc = mmap_tst7_func(mnt, 0);
693 rc = mmap_tst7_func(mnt, 1);
697 static int mmap_tst8(char *mnt)
700 char *buf = MAP_FAILED;
704 char xyz[page_size * 2];
706 if (snprintf(fname, 256, "%s/mmap_tst8", mnt) >= 256) {
707 fprintf(stderr, "dir name too long\n");
711 fd = open(fname, O_RDWR | O_CREAT, 0644);
717 if (ftruncate(fd, page_size) == -1) {
722 buf = mmap(NULL, page_size * 2,
723 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
724 if (buf == MAP_FAILED) {
731 if (pid == 0) { /* child */
732 memcpy(xyz, buf, page_size * 2);
733 /* shouldn't reach here. */
735 } else if (pid > 0) { /* parent */
737 pid = waitpid(pid, &status, 0);
745 if (WIFSIGNALED(status) && SIGBUS == WTERMSIG(status))
753 if (buf != MAP_FAILED)
754 munmap(buf, page_size);
760 static int remote_tst(int tc, char *mnt)
765 rc = remote_tst3(mnt);
768 rc = remote_tst4(mnt);
771 fprintf(stderr, "wrong test case number %d\n", tc);
779 int tc; /* test case number */
780 char *desc; /* test description */
781 int (*test_fn)(char *mnt); /* test function */
782 int node_cnt; /* node count */
785 struct test_case tests[] = {
786 { 1, "mmap test1: basic mmap operation", mmap_tst1, 1 },
787 { 2, "mmap test2: MAP_PRIVATE not write back", mmap_tst2, 1 },
788 { 3, "mmap test3: concurrent mmap ops on two nodes", mmap_tst3, 2 },
789 { 4, "mmap test4: c1 write to f1 from mmapped f2, "
790 "c2 write to f1 from mmapped f1", mmap_tst4, 2 },
791 { 5, "mmap test5: read/write file to/from the buffer "
792 "which mmapped to just this file", mmap_tst5, 1 },
793 { 6, "mmap test6: check mmap write/read content on two nodes",
795 { 7, "mmap test7: file i/o with an unmapped buffer", mmap_tst7, 1},
796 { 8, "mmap test8: SIGBUS for beyond file size", mmap_tst8, 1},
800 int main(int argc, char **argv)
802 struct test_case *test;
805 while ((c = getopt(argc, argv, "d:m:")) != -1) {
822 if (mmap_initialize(argv[0]) != 0) {
823 fprintf(stderr, "mmap_initialize failed!\n");
827 for (test = tests; test->tc; test++) {
831 if (test->node_cnt == 1 || dir2 != NULL) {
832 struct timeval start, end;
834 gettimeofday(&start, NULL);
835 rc = test->test_fn(dir);
836 gettimeofday(&end, NULL);
838 duration = (double)(end.tv_sec - start.tv_sec) +
839 (double)(end.tv_usec - start.tv_usec) / 1000000;
840 rs = rc ? "FAIL" : "PASS";
845 fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);