Whamcloud - gitweb
LU-13773 tests: subscript failure propagation
[fs/lustre-release.git] / lustre / tests / mmap_sanity.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 #include <sys/time.h>
37 #include <sys/mman.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <getopt.h>
44 #include <string.h>
45 #include <errno.h>
46
47 #include <libcfs/util/param.h>
48
49 char *dir = NULL, *dir2 = NULL;
50 long page_size;
51 char mmap_sanity[256];
52
53 static void usage(void)
54 {
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 test cases 1 and 2.\n");
59         exit(127);
60 }
61
62 static int remote_tst(int tc, char *mnt);
63 static int mmap_run(int tc)
64 {
65         pid_t child;
66         int rc = 0;
67
68         child = fork();
69         if (child < 0)
70                 return -errno;
71         else if (child)
72                 return 0;
73
74         if (dir2) {
75                 rc = remote_tst(tc, dir2);
76         } else {
77                 rc = -EINVAL;
78                 fprintf(stderr, "invalid argument!\n");
79         }
80         _exit(rc);
81 }
82
83 static int mmap_initialize(char *myself)
84 {
85         char buf[1024], *file;
86         int fdr, fdw, count, rc = 0;
87
88         page_size = sysconf(_SC_PAGESIZE);
89         if (page_size == -1) {
90                 perror("sysconf(_SC_PAGESIZE)");
91                 return -errno;
92         }
93
94         /* copy myself to lustre for another client */
95         fdr = open(myself, O_RDONLY);
96         if (fdr < 0) {
97                 perror(myself);
98                 return -EINVAL;
99         }
100         file = strrchr(myself, '/');
101         if (!file) {
102                 fprintf(stderr, "can't get test filename\n");
103                 close(fdr);
104                 return -EINVAL;
105         }
106         file++;
107         sprintf(mmap_sanity, "%s/%s", dir, file);
108
109         fdw = open(mmap_sanity, O_CREAT | O_WRONLY, 0777);
110         if (fdw < 0) {
111                 perror(mmap_sanity);
112                 close(fdr);
113                 return -EINVAL;
114         }
115         while ((count = read(fdr, buf, sizeof(buf))) != 0) {
116                 int writes;
117
118                 if (count < 0) {
119                         perror("read()");
120                         rc = -errno;
121                         break;
122                 }
123                 writes = write(fdw, buf, count);
124                 if (writes != count) {
125                         perror("write()");
126                         rc = -errno;
127                         break;
128                 }
129         }
130         close(fdr);
131         close(fdw);
132         return rc;
133 }
134
135 static void mmap_finalize()
136 {
137         unlink(mmap_sanity);
138 }
139
140 /* basic mmap operation on single node */
141 static int mmap_tst1(char *mnt)
142 {
143         char *ptr, mmap_file[256];
144         int region, fd, rc = 0;
145
146         region = page_size * 10;
147         sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
148
149         if (unlink(mmap_file) && errno != ENOENT) {
150                 perror("unlink()");
151                 return -errno;
152         }
153
154         fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
155         if (fd < 0) {
156                 perror(mmap_file);
157                 return -errno;
158         }
159         if (ftruncate(fd, region) < 0) {
160                 perror("ftruncate()");
161                 rc = -errno;
162                 goto out_close;
163         }
164
165         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
166         if (ptr == MAP_FAILED) {
167                 perror("mmap()");
168                 rc = -errno;
169                 goto out_close;
170         }
171         memset(ptr, 'a', region);
172
173         munmap(ptr, region);
174 out_close:
175         close(fd);
176         unlink(mmap_file);
177         return rc;
178 }
179
180 /* MAP_PRIVATE create a copy-on-write mmap */
181 static int mmap_tst2(char *mnt)
182 {
183         char *ptr, mmap_file[256], buf[256];
184         int fd, rc = 0;
185
186         sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
187
188         if (unlink(mmap_file) && errno != ENOENT) {
189                 perror("unlink()");
190                 return -errno;
191         }
192
193         fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
194         if (fd < 0) {
195                 perror(mmap_file);
196                 return -errno;
197         }
198         if (ftruncate(fd, page_size) < 0) {
199                 perror("ftruncate()");
200                 rc = -errno;
201                 goto out_close;
202         }
203
204         ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
205         if (ptr == MAP_FAILED) {
206                 perror("mmap()");
207                 rc = -errno;
208                 goto out_close;
209         }
210         memcpy(ptr, "blah", strlen("blah"));
211
212         munmap(ptr, page_size);
213 out_close:
214         close(fd);
215         if (rc)
216                 return -rc;
217
218         fd = open(mmap_file, O_RDONLY);
219         if (fd < 0) {
220                 perror(mmap_file);
221                 return -errno;
222         }
223         rc = read(fd, buf, sizeof(buf));
224         if (rc < 0) {
225                 perror("read()");
226                 rc = -errno;
227                 goto out_close;
228         }
229         rc = 0;
230
231         if (strncmp("blah", buf, strlen("blah")) == 0) {
232                 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
233                 rc = -EFAULT;
234         }
235         close(fd);
236         unlink(mmap_file);
237         return rc;
238 }
239
240 /* concurrent mmap operations on two nodes */
241 static int mmap_tst3(char *mnt)
242 {
243         char *ptr, mmap_file[256];
244         int region, fd, rc = 0;
245
246         region = page_size * 100;
247         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
248
249         if (unlink(mmap_file) && errno != ENOENT) {
250                 perror("unlink()");
251                 return -errno;
252         }
253
254         fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
255         if (fd < 0) {
256                 perror(mmap_file);
257                 return -errno;
258         }
259         if (ftruncate(fd, region) < 0) {
260                 perror("ftruncate()");
261                 rc = -errno;
262                 goto out_close;
263         }
264
265         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
266         if (ptr == MAP_FAILED) {
267                 perror("mmap()");
268                 rc = -errno;
269                 goto out_close;
270         }
271
272         rc = mmap_run(3);
273         if (rc)
274                 goto out_unmap;
275
276         memset(ptr, 'a', region);
277         sleep(2);       /* wait for remote test finish */
278 out_unmap:
279         munmap(ptr, region);
280 out_close:
281         close(fd);
282         unlink(mmap_file);
283         return rc;
284 }
285
286 static int remote_tst3(char *mnt)
287 {
288         char *ptr, mmap_file[256];
289         int region, fd, rc = 0;
290
291         region = page_size * 100;
292         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
293
294         fd = open(mmap_file, O_RDWR, 0600);
295         if (fd < 0) {
296                 perror(mmap_file);
297                 return -errno;
298         }
299
300         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
301         if (ptr == MAP_FAILED) {
302                 perror("mmap()");
303                 rc = -errno;
304                 goto out_close;
305         }
306         memset(ptr, 'b', region);
307         memset(ptr, 'c', region);
308
309         munmap(ptr, region);
310 out_close:
311         close(fd);
312         return rc;
313 }
314
315 /*
316  * client1 write to file_4a from mmap()ed file_4b;
317  * client2 write to file_4b from mmap()ed file_4a.
318  */
319 static int mmap_tst4(char *mnt)
320 {
321         char *ptr, filea[256], fileb[256];
322         int region, fdr, fdw, rc = 0;
323
324         region = page_size * 100;
325         sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
326         sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
327
328         if (unlink(filea) && errno != ENOENT) {
329                 perror("unlink()");
330                 return -errno;
331         }
332         if (unlink(fileb) && errno != ENOENT) {
333                 perror("unlink()");
334                 return -errno;
335         }
336
337         fdr = fdw = -1;
338         fdr = open(fileb, O_CREAT | O_RDWR, 0600);
339         if (fdr < 0) {
340                 perror(fileb);
341                 return -errno;
342         }
343         if (ftruncate(fdr, region) < 0) {
344                 perror("ftruncate()");
345                 rc = -errno;
346                 goto out_close;
347         }
348         fdw = open(filea, O_CREAT | O_RDWR, 0600);
349         if (fdw < 0) {
350                 perror(filea);
351                 rc = -errno;
352                 goto out_close;
353         }
354         if (ftruncate(fdw, region) < 0) {
355                 perror("ftruncate()");
356                 rc = -errno;
357                 goto out_close;
358         }
359
360         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fdr, 0);
361         if (ptr == MAP_FAILED) {
362                 perror("mmap()");
363                 rc = -errno;
364                 goto out_close;
365         }
366
367         rc = mmap_run(4);
368         if (rc)
369                 goto out_unmap;
370
371         memset(ptr, '1', region);
372
373         rc = write(fdw, ptr, region);
374         if (rc <= 0) {
375                 perror("write()");
376                 rc = -errno;
377         } else {
378                 rc = 0;
379         }
380
381         sleep(2);       /* wait for remote test finish */
382 out_unmap:
383         munmap(ptr, region);
384 out_close:
385         if (fdr >= 0)
386                 close(fdr);
387         if (fdw >= 0)
388                 close(fdw);
389         unlink(filea);
390         unlink(fileb);
391         return rc;
392 }
393
394 static int remote_tst4(char *mnt)
395 {
396         char *ptr, filea[256], fileb[256];
397         int region, fdr, fdw, rc = 0;
398
399         region = page_size * 100;
400         sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
401         sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
402
403         fdr = fdw = -1;
404         fdr = open(filea, O_RDWR, 0600);
405         if (fdr < 0) {
406                 perror(filea);
407                 return -errno;
408         }
409         fdw = open(fileb, O_RDWR, 0600);
410         if (fdw < 0) {
411                 perror(fileb);
412                 rc = -errno;
413                 goto out_close;
414         }
415
416         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fdr, 0);
417         if (ptr == MAP_FAILED) {
418                 perror("mmap()");
419                 rc = -errno;
420                 goto out_close;
421         }
422
423         memset(ptr, '2', region);
424
425         rc = write(fdw, ptr, region);
426         if (rc <= 0) {
427                 perror("write()");
428                 rc = -errno;
429         } else {
430                 rc = 0;
431         }
432
433         munmap(ptr, region);
434 out_close:
435         if (fdr >= 0)
436                 close(fdr);
437         if (fdw >= 0)
438                 close(fdw);
439         return rc;
440 }
441
442 static int cancel_lru_locks(char *filter)
443 {
444         glob_t paths;
445         pid_t child;
446         int rc, i;
447
448         child = fork();
449         if (child < 0) {
450                 return -errno;
451         } else if (child) {
452                 int status;
453
454                 rc = waitpid(child, &status, WNOHANG);
455                 if (rc == child)
456                         rc = 0;
457                 return rc;
458         }
459
460         if (filter)
461                 rc = cfs_get_param_paths(&paths,
462                                          "ldlm/namespaces/*-%s-*/lru_size",
463                                          filter);
464         else
465                 rc = cfs_get_param_paths(&paths,
466                                          "ldlm/namespaces/*/lru_size");
467         if (rc != 0)
468                 return -EINVAL;
469
470         for (i = 0; i < paths.gl_pathc; i++) {
471                 FILE *f = fopen(paths.gl_pathv[i], "r");
472
473                 if (!f) {
474                         rc = -errno;
475                         fprintf(stderr, "cannot open '%s': %s\n",
476                                 paths.gl_pathv[i], strerror(errno));
477                         break;
478                 }
479
480                 rc = fwrite("clear", strlen("clear") + 1, 1, f);
481                 if (rc < 1) {
482                         rc = -errno;
483                         fprintf(stderr, "fwrite failed for '%s': %s\n",
484                                 paths.gl_pathv[i], strerror(errno));
485                         fclose(f);
486                         break;
487                 }
488                 fclose(f);
489         }
490
491         cfs_free_param_data(&paths);
492         _exit(rc);
493 }
494
495 /*
496  * don't dead lock while read/write file to/from the buffer which
497  * mmaped to just this file
498  */
499 static int mmap_tst5(char *mnt)
500 {
501         char *ptr, mmap_file[256];
502         int region, fd, off, rc = 0;
503
504         region = page_size * 40;
505         off = page_size * 10;
506         sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
507
508         if (unlink(mmap_file) && errno != ENOENT) {
509                 perror("unlink()");
510                 return -errno;
511         }
512
513         fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
514         if (fd < 0) {
515                 perror(mmap_file);
516                 return -errno;
517         }
518         if (ftruncate(fd, region) < 0) {
519                 perror("ftruncate()");
520                 rc = -errno;
521                 goto out_close;
522         }
523
524         ptr = mmap(NULL, region, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
525         if (ptr == MAP_FAILED) {
526                 perror("mmap()");
527                 rc = -errno;
528                 goto out_close;
529         }
530         memset(ptr, 'a', region);
531
532         /* cancel unused locks */
533         rc = cancel_lru_locks("osc");
534         if (rc)
535                 goto out_unmap;
536
537         /* read/write region of file and buffer should be overlap */
538         rc = read(fd, ptr + off, off * 2);
539         if (rc != off * 2) {
540                 perror("read()");
541                 rc = -errno;
542                 goto out_unmap;
543         }
544         rc = write(fd, ptr + off, off * 2);
545         if (rc != off * 2) {
546                 perror("write()");
547                 rc = -errno;
548         }
549         rc = 0;
550 out_unmap:
551         munmap(ptr, region);
552 out_close:
553         close(fd);
554         unlink(mmap_file);
555         return rc;
556 }
557
558 /* mmap write to a file form client1 then mmap read from client2 */
559 static int mmap_tst6(char *mnt)
560 {
561         char mmap_file[256], mmap_file2[256];
562         char *ptr = NULL, *ptr2 = NULL;
563         int fd = 0, fd2 = 0, rc = 0;
564
565         sprintf(mmap_file, "%s/%s", mnt, "mmap_file6");
566         sprintf(mmap_file2, "%s/%s", dir2, "mmap_file6");
567         if (unlink(mmap_file) && errno != ENOENT) {
568                 perror("unlink()");
569                 return -errno;
570         }
571
572         fd = open(mmap_file, O_CREAT | O_RDWR, 0600);
573         if (fd < 0) {
574                 perror(mmap_file);
575                 return -errno;
576         }
577         if (ftruncate(fd, page_size) < 0) {
578                 perror("ftruncate()");
579                 rc = -errno;
580                 goto out;
581         }
582
583         fd2 = open(mmap_file2, O_RDWR, 0600);
584         if (fd2 < 0) {
585                 perror(mmap_file2);
586                 rc = -errno;
587                 goto out;
588         }
589
590         ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
591         if (ptr == MAP_FAILED) {
592                 perror("mmap()");
593                 rc = -errno;
594                 goto out;
595         }
596
597         ptr2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
598                     fd2, 0);
599         if (ptr2 == MAP_FAILED) {
600                 perror("mmap()");
601                 rc = -errno;
602                 goto out;
603         }
604
605         rc = cancel_lru_locks("osc");
606         if (rc)
607                 goto out;
608
609         memcpy(ptr, "blah", strlen("blah"));
610         if (strncmp(ptr, ptr2, strlen("blah"))) {
611                 fprintf(stderr, "client2 mmap mismatch!\n");
612                 rc = -EFAULT;
613                 goto out;
614         }
615         memcpy(ptr2, "foo", strlen("foo"));
616         if (strncmp(ptr, ptr2, strlen("foo"))) {
617                 fprintf(stderr, "client1 mmap mismatch!\n");
618                 rc = -EFAULT;
619         }
620 out:
621         if (ptr2)
622                 munmap(ptr2, page_size);
623         if (ptr)
624                 munmap(ptr, page_size);
625         if (fd2 > 0)
626                 close(fd2);
627         if (fd > 0)
628                 close(fd);
629         unlink(mmap_file);
630         return rc;
631 }
632
633 static int mmap_tst7_func(char *mnt, int rw)
634 {
635         char  fname[256];
636         char *buf = MAP_FAILED;
637         ssize_t bytes;
638         int fd = -1;
639         int rc = 0;
640
641         if (snprintf(fname, 256, "%s/mmap_tst7.%s", mnt,
642                      (rw == 0) ? "read" : "write") >= 256) {
643                 fprintf(stderr, "dir name too long\n");
644                 rc = -ENAMETOOLONG;
645                 goto out;
646         }
647         fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
648         if (fd == -1) {
649                 perror("open");
650                 rc = -errno;
651                 goto out;
652         }
653         if (ftruncate(fd, 2 * page_size) == -1) {
654                 perror("truncate");
655                 rc = -errno;
656                 goto out;
657         }
658         buf = mmap(NULL, page_size * 2,
659                    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
660         if (buf == MAP_FAILED) {
661                 perror("mmap");
662                 rc = -errno;
663                 goto out;
664         }
665         /* ensure the second page isn't mapped */
666         munmap(buf + page_size, page_size);
667         bytes = (rw == 0) ? read(fd, buf, 2 * page_size) :
668                 write(fd, buf, 2 * page_size);
669         /* Expected behavior */
670         if (bytes == page_size)
671                 goto out;
672
673         fprintf(stderr, "%s returned %zd, errno = %d\n",
674                 (rw == 0) ? "read" : "write", bytes, errno);
675         rc = -EIO;
676 out:
677         if (buf != MAP_FAILED)
678                 munmap(buf, page_size);
679         if (fd != -1)
680                 close(fd);
681         return rc;
682 }
683
684 static int mmap_tst7(char *mnt)
685 {
686         int rc;
687
688         rc = mmap_tst7_func(mnt, 0);
689         if (rc != 0)
690                 return rc;
691         rc = mmap_tst7_func(mnt, 1);
692         return rc;
693 }
694
695 static int mmap_tst8(char *mnt)
696 {
697         char  fname[256];
698         char *buf = MAP_FAILED;
699         int fd = -1;
700         int rc = 0;
701         pid_t pid;
702         char xyz[page_size * 2];
703
704         if (snprintf(fname, 256, "%s/mmap_tst8", mnt) >= 256) {
705                 fprintf(stderr, "dir name too long\n");
706                 rc = -ENAMETOOLONG;
707                 goto out;
708         }
709         fd = open(fname, O_RDWR | O_CREAT, 0644);
710         if (fd == -1) {
711                 perror("open");
712                 rc = -errno;
713                 goto out;
714         }
715         if (ftruncate(fd, page_size) == -1) {
716                 perror("truncate");
717                 rc = -errno;
718                 goto out;
719         }
720         buf = mmap(NULL, page_size * 2,
721                    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
722         if (buf == MAP_FAILED) {
723                 perror("mmap");
724                 rc = -errno;
725                 goto out;
726         }
727
728         pid = fork();
729         if (pid == 0) { /* child */
730                 memcpy(xyz, buf, page_size * 2);
731                 /* shouldn't reach here. */
732                 exit(0);
733         } else if (pid > 0) { /* parent */
734                 int status = 0;
735
736                 pid = waitpid(pid, &status, 0);
737                 if (pid < 0) {
738                         perror("wait");
739                         rc = -errno;
740                         goto out;
741                 }
742
743                 rc = -EFAULT;
744                 if (WIFSIGNALED(status) && SIGBUS == WTERMSIG(status))
745                         rc = 0;
746         } else {
747                 perror("fork");
748                 rc = -errno;
749         }
750
751 out:
752         if (buf != MAP_FAILED)
753                 munmap(buf, page_size);
754         if (fd != -1)
755                 close(fd);
756         return rc;
757 }
758
759 static int mmap_tst9(char *mnt)
760 {
761         char  fname[256];
762         char *buf = MAP_FAILED;
763         int fd = -1;
764         int rc = 0;
765
766         if (snprintf(fname, 256, "%s/mmap_tst9", mnt) >= 256) {
767                 fprintf(stderr, "dir name too long\n");
768                 rc = -ENAMETOOLONG;
769                 goto out;
770         }
771         if (unlink(fname) == -1 && errno != ENOENT) {
772                 perror("unlink");
773                 rc = -errno;
774                 goto out;
775         }
776         fd = open(fname, O_RDWR | O_CREAT, 0644);
777         if (fd == -1) {
778                 perror("open");
779                 rc = -errno;
780                 goto out;
781         }
782         buf = mmap(NULL, page_size * 2,
783                    PROT_READ, MAP_PRIVATE, fd, (loff_t)(-10 * page_size));
784         if (buf == MAP_FAILED) {
785                 perror("mmap");
786                 rc = -errno;
787                 goto out;
788         }
789         rc = write(STDOUT_FILENO, buf, 2 * page_size);
790         if (rc != -1) {
791                 fprintf(stderr, "write succeded with %d instead of failing\n",
792                         rc);
793                 rc = -EINVAL;
794                 goto out;
795         } else if (errno != EFAULT) {
796                 fprintf(stderr, "write failed with %d instead of EFAULT(%d)\n",
797                         errno, EFAULT);
798                 rc = -errno;
799                 goto out;
800         }
801         rc = 0;
802 out:
803         if (buf != MAP_FAILED)
804                 munmap(buf, page_size * 2);
805         if (fd != -1)
806                 close(fd);
807         return rc;
808 }
809
810 static int remote_tst(int tc, char *mnt)
811 {
812         int rc = 0;
813
814         switch (tc) {
815         case 3:
816                 rc = remote_tst3(mnt);
817                 break;
818         case 4:
819                 rc = remote_tst4(mnt);
820                 break;
821         default:
822                 fprintf(stderr, "wrong test case number %d\n", tc);
823                 rc = -EINVAL;
824                 break;
825         }
826         return rc;
827 }
828
829 struct test_case {
830         int tc;                     /* test case number */
831         char *desc;                 /* test description */
832         int (*test_fn)(char *mnt);  /* test function */
833         int node_cnt;               /* node count */
834         int skipped;                /* skipped by caller */
835 };
836
837 struct test_case tests[] = {
838         {
839                 .tc             = 1,
840                 .desc           = "mmap test1: basic mmap operation",
841                 .test_fn        = mmap_tst1,
842                 .node_cnt       = 1
843         },
844         {
845                 .tc             = 2,
846                 .desc           = "mmap test2: MAP_PRIVATE not write back",
847                 .test_fn        = mmap_tst2,
848                 .node_cnt       = 1
849         },
850         {
851                 .tc             = 3,
852                 .desc           = "mmap test3: concurrent mmap ops on two nodes",
853                 .test_fn        = mmap_tst3,
854                 .node_cnt       = 2
855         },
856         {
857                 .tc             = 4,
858                 .desc           = "mmap test4: c1 write to f1 from mmapped f2, c2 write to f1 from mmapped f1",
859                 .test_fn        = mmap_tst4,
860                 .node_cnt       = 2
861         },
862         {
863                 .tc             = 5,
864                 .desc           = "mmap test5: read/write file to/from the buffer which mmapped to just this file",
865                 .test_fn        = mmap_tst5,
866                 .node_cnt       = 1
867         },
868         {
869                 .tc             = 6,
870                 .desc           = "mmap test6: check mmap write/read content on two nodes",
871                 .test_fn        = mmap_tst6,
872                 .node_cnt       = 2
873         },
874         {
875                 .tc             = 7,
876                 .desc           = "mmap test7: file i/o with an unmapped buffer",
877                 .test_fn        = mmap_tst7,
878                 .node_cnt       = 1
879         },
880         {
881                 .tc             = 8,
882                 .desc           = "mmap test8: SIGBUS for beyond file size",
883                 .test_fn        = mmap_tst8,
884                 .node_cnt       = 1
885         },
886         {
887                 .tc             = 9,
888                 .desc           = "mmap test9: SIGBUS for negative file offset",
889                 .test_fn        = mmap_tst9,
890                 .node_cnt       = 1
891         },
892         {
893                 .tc             = 0
894         }
895 };
896
897 int main(int argc, char **argv)
898 {
899         struct test_case *test;
900         int nr_cases = sizeof(tests) / sizeof(*test);
901         int c, rc = 0;
902
903         while ((c = getopt(argc, argv, "d:m:e:")) != -1) {
904                 switch (c) {
905                 case 'd':
906                         dir = optarg;
907                         break;
908                 case 'm':
909                         dir2 = optarg;
910                         break;
911                 case 'e': {
912                         char *endptr = NULL;
913
914                         rc = strtol(optarg, &endptr, 10);
915                         if (endptr && *endptr != '\0')
916                                 usage();
917                         if (rc > 0 && rc < nr_cases)
918                                 tests[rc - 1].skipped = 1;
919                         break;
920                 }
921                 default:
922                         usage();
923                         break;
924                 }
925         }
926
927         if (!dir)
928                 usage();
929
930         if (mmap_initialize(argv[0]) != 0) {
931                 fprintf(stderr, "mmap_initialize failed!\n");
932                 return -EINVAL;
933         }
934
935         rc = 0;
936         for (test = tests; test->tc; test++) {
937                 double duration = 0.0;
938                 char *rs = "SKIPPED";
939
940                 if (!test->skipped && (test->node_cnt == 1 || dir2)) {
941                         struct timeval start, end;
942
943                         gettimeofday(&start, NULL);
944                         rc = test->test_fn(dir);
945                         gettimeofday(&end, NULL);
946
947                         duration = (double)(end.tv_sec - start.tv_sec) +
948                                 (double)(end.tv_usec - start.tv_usec) / 1000000;
949                         rs = rc ? "FAIL" : "PASS";
950                 }
951
952                 fprintf(stderr, "%s (%s, %.5gs)\n", test->desc, rs, duration);
953                 if (rc)
954                         break;
955         }
956
957         mmap_finalize();
958         return -rc;
959 }