Whamcloud - gitweb
b=23954 MGS device has stopped when we try to start the second mgs
[fs/lustre-release.git] / lustre / tests / mmap_sanity.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
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.
11  *
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).
17  *
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
21  *
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
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <sys/mman.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <netinet/in.h>
46 #include <sys/socket.h>
47 #include <netdb.h>
48 #include <string.h>
49 #include <sys/wait.h>
50
51 char *dir = NULL, *dir2 = NULL;
52 long page_size;
53 char mmap_sanity[256];
54
55
56 static void usage(void)
57 {
58         printf("Usage: mmap_sanity -d dir [-m dir2]\n");
59         printf("       dir      lustre mount point\n");
60         printf("       dir2     another mount point\n");
61         exit(127);
62 }
63
64 static int remote_tst(int tc, char *mnt);
65 static int mmap_run(int tc)
66 {
67         pid_t child;
68         int rc = 0;
69
70         child = fork();
71         if (child < 0)
72                 return errno;
73         else if (child)
74                 return 0;
75
76         if (dir2 != NULL) {
77                 rc = remote_tst(tc, dir2);
78         } else {
79                 rc = EINVAL;
80                 fprintf(stderr, "invalid argument!\n");
81         }
82         _exit(rc);
83 }
84
85 static int mmap_initialize(char *myself)
86 {
87         char buf[1024], *file;
88         int fdr, fdw, count, rc = 0;
89         
90         page_size = sysconf(_SC_PAGESIZE);
91         if (page_size == -1) {
92                 perror("sysconf(_SC_PAGESIZE)");
93                 return errno;
94         }
95
96         /* copy myself to lustre for another client */
97         fdr = open(myself, O_RDONLY);
98         if (fdr < 0) {
99                 perror(myself);
100                 return EINVAL;
101         }
102         file = strrchr(myself, '/');
103         if (file == NULL) {
104                 fprintf(stderr, "can't get test filename\n");
105                 close(fdr);
106                 return EINVAL;
107         }
108         file++;
109         sprintf(mmap_sanity, "%s/%s", dir, file);
110
111         fdw = open(mmap_sanity, O_CREAT|O_WRONLY, 0777);
112         if (fdw < 0) {
113                 perror(mmap_sanity);
114                 close(fdr);
115                 return EINVAL;
116         }
117         while ((count = read(fdr, buf, sizeof(buf))) != 0) {
118                 int writes;
119
120                 if (count < 0) {
121                         perror("read()");
122                         rc = errno;
123                         break;
124                 }
125                 writes = write(fdw, buf, count);
126                 if (writes != count) {
127                         perror("write()");
128                         rc = errno;
129                         break;
130                 }
131         }
132         close(fdr);
133         close(fdw);
134         return rc;
135 }
136
137 static void mmap_finalize()
138 {
139         unlink(mmap_sanity);
140 }
141
142 /* basic mmap operation on single node */
143 static int mmap_tst1(char *mnt)
144 {
145         char *ptr, mmap_file[256];
146         int region, fd, rc = 0;
147
148         region = page_size * 10;
149         sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
150         
151         if (unlink(mmap_file) && errno != ENOENT) {
152                 perror("unlink()");
153                 return errno;
154         }
155
156         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
157         if (fd < 0) {
158                 perror(mmap_file);
159                 return errno;
160         }
161         if (ftruncate(fd, region) < 0) {
162                 perror("ftruncate()");
163                 rc = errno;
164                 goto out_close;
165         }
166
167         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
168         if (ptr == MAP_FAILED) {
169                 perror("mmap()");
170                 rc = errno;
171                 goto out_close;
172         }
173         memset(ptr, 'a', region);
174
175         munmap(ptr, region);
176 out_close:
177         close(fd);
178         unlink(mmap_file);
179         return rc;
180 }
181
182 /* MAP_PRIVATE create a copy-on-write mmap */
183 static int mmap_tst2(char *mnt)
184 {
185         char *ptr, mmap_file[256], buf[256];
186         int fd, rc = 0;
187
188         sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
189
190         if (unlink(mmap_file) && errno != ENOENT) {
191                 perror("unlink()");
192                 return errno;
193         }
194
195         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
196         if (fd < 0) {
197                 perror(mmap_file);
198                 return errno;
199         }
200         if (ftruncate(fd, page_size) < 0) {
201                 perror("ftruncate()");
202                 rc = errno;
203                 goto out_close;
204         }
205
206         ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
207         if (ptr == MAP_FAILED) {
208                 perror("mmap()");
209                 rc = errno;
210                 goto out_close;
211         }
212         memcpy(ptr, "blah", strlen("blah"));
213
214         munmap(ptr, page_size);
215 out_close:
216         close(fd);
217         if (rc)
218                 return rc;
219
220         fd = open(mmap_file, O_RDONLY);
221         if (fd < 0) {
222                 perror(mmap_file);
223                 return errno;
224         }
225         rc = read(fd, buf, sizeof(buf));
226         if (rc < 0) {
227                 perror("read()");
228                 rc = errno;
229                 goto out_close;
230         }
231         rc = 0;
232         
233         if (strncmp("blah", buf, strlen("blah")) == 0) {
234                 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
235                 rc = EFAULT;
236         }
237         close(fd);
238         unlink(mmap_file);
239         return rc;
240 }
241
242 /* concurrent mmap operations on two nodes */
243 static int mmap_tst3(char *mnt)
244 {
245         char *ptr, mmap_file[256];
246         int region, fd, rc = 0;
247
248         region = page_size * 100;
249         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
250         
251         if (unlink(mmap_file) && errno != ENOENT) {
252                 perror("unlink()");
253                 return errno;
254         }
255
256         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
257         if (fd < 0) {
258                 perror(mmap_file);
259                 return errno;
260         }
261         if (ftruncate(fd, region) < 0) {
262                 perror("ftruncate()");
263                 rc = errno;
264                 goto out_close;
265         }
266
267         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
268         if (ptr == MAP_FAILED) {
269                 perror("mmap()");
270                 rc = errno;
271                 goto out_close;
272         }
273
274         rc = mmap_run(3);
275         if (rc)
276                 goto out_unmap;
277         
278         memset(ptr, 'a', region);
279         sleep(2);       /* wait for remote test finish */
280 out_unmap:
281         munmap(ptr, region);
282 out_close:
283         close(fd);
284         unlink(mmap_file);
285         return rc;
286 }       
287
288 static int remote_tst3(char *mnt)
289 {
290         char *ptr, mmap_file[256];
291         int region, fd, rc = 0;
292
293         region = page_size * 100;
294         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
295
296         fd = open(mmap_file, O_RDWR, 0600);
297         if (fd < 0) {
298                 perror(mmap_file);
299                 return errno;
300         }
301
302         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
303         if (ptr == MAP_FAILED) {
304                 perror("mmap()");
305                 rc = errno;
306                 goto out_close;
307         }
308         memset(ptr, 'b', region);
309         memset(ptr, 'c', region);
310         
311         munmap(ptr, region);
312 out_close:
313         close(fd);
314         return rc;
315 }
316
317 /* client1 write to file_4a from mmap()ed file_4b;
318  * client2 write to file_4b from mmap()ed file_4a. */
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         sleep(2);       /* wait for remote test finish */
381 out_unmap:
382         munmap(ptr, region);
383 out_close:
384         if (fdr >= 0)
385                 close(fdr);
386         if (fdw >= 0)
387                 close(fdw);
388         unlink(filea);
389         unlink(fileb);
390         return rc;
391 }
392
393 static int remote_tst4(char *mnt)
394 {
395         char *ptr, filea[256], fileb[256];
396         int region, fdr, fdw, rc = 0;
397
398         region = page_size * 100;
399         sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
400         sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
401
402         fdr = fdw = -1;
403         fdr = open(filea, O_RDWR, 0600);
404         if (fdr < 0) {
405                 perror(filea);
406                 return errno;
407         }
408         fdw = open(fileb, O_RDWR, 0600);
409         if (fdw < 0) {
410                 perror(fileb);
411                 rc = errno;
412                 goto out_close;
413         }
414
415         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
416         if (ptr == MAP_FAILED) {
417                 perror("mmap()");
418                 rc = errno;
419                 goto out_close;
420         }
421
422         memset(ptr, '2', region);
423
424         rc = write(fdw, ptr, region);
425         if (rc <= 0) {
426                 perror("write()");
427                 rc = errno;
428         } else
429                 rc = 0;
430      
431         munmap(ptr, region);
432 out_close:
433         if (fdr >= 0)
434                 close(fdr);
435         if (fdw >= 0)
436                 close(fdw);
437         return rc;
438 }
439
440 static int cancel_lru_locks(char *prefix)
441 {
442         char cmd[256], line[1024];
443         FILE *file;
444         pid_t child;
445         int len = 1024, rc = 0;
446
447         child = fork();
448         if (child < 0)
449                 return errno;
450         else if (child) {
451                 int status;
452                 rc = waitpid(child, &status, WNOHANG);
453                 if (rc == child)
454                         rc = 0;
455                 return rc;
456         }
457
458         if (prefix)
459                 sprintf(cmd, "ls /proc/fs/lustre/ldlm/namespaces/*-%s-*/lru_size", prefix);
460         else
461                 sprintf(cmd, "ls /proc/fs/lustre/ldlm/namespaces/*/lru_size");
462
463         file = popen(cmd, "r");
464         if (file == NULL) {
465                 perror("popen()");
466                 return errno;
467         }
468
469         while (fgets(line, len, file)) {
470                 FILE *f;
471
472                 if (!strlen(line))
473                         continue;
474                 /* trim newline character */
475                 *(line + strlen(line) - 1) = '\0';
476                 f = fopen(line, "w");
477                 if (f == NULL) {
478                         perror("fopen()");
479                         rc = errno;
480                         break;
481                 }
482                 rc = fwrite("clear", strlen("clear") + 1, 1, f);
483                 if (rc < 1) {
484                         perror("fwrite()");
485                         rc = errno;
486                         fclose(f);
487                         break;
488                 }
489                 fclose(f);
490         }
491
492         pclose(file);
493         _exit(rc);
494 }
495
496 /* don't dead lock while read/write file to/from the buffer which
497  * mmaped to just this file */
498 static int mmap_tst5(char *mnt)
499 {
500         char *ptr, mmap_file[256];
501         int region, fd, off, rc = 0;
502
503         region = page_size * 40;
504         off = page_size * 10;
505         sprintf(mmap_file, "%s/%s", mnt, "mmap_file5");
506
507         if (unlink(mmap_file) && errno != ENOENT) {
508                 perror("unlink()");
509                 return errno;
510         }
511
512         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
513         if (fd < 0) {
514                 perror(mmap_file);
515                 return errno;
516         }
517         if (ftruncate(fd, region) < 0) {
518                 perror("ftruncate()");
519                 rc = errno;
520                 goto out_close;
521         }
522
523         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
524         if (ptr == MAP_FAILED) {
525                 perror("mmap()");
526                 rc = errno;
527                 goto out_close;
528         }
529         memset(ptr, 'a', region);
530
531         /* cancel unused locks */
532         rc = cancel_lru_locks("osc");
533         if (rc)
534                 goto out_unmap;
535
536         /* read/write region of file and buffer should be overlap */
537         rc = read(fd, ptr + off, off * 2);
538         if (rc != off * 2) {
539                 perror("read()");
540                 rc = errno;
541                 goto out_unmap;
542         }
543         rc = write(fd, ptr + off, off * 2);
544         if (rc != off * 2) {
545                 perror("write()");
546                 rc = errno;
547         }
548         rc = 0;
549 out_unmap:
550         munmap(ptr, region);
551 out_close:
552         close(fd);
553         unlink(mmap_file);
554         return rc;
555 }
556
557 /* mmap write to a file form client1 then mmap read from client2 */
558 static int mmap_tst6(char *mnt)
559 {
560         char mmap_file[256], mmap_file2[256];
561         char *ptr = NULL, *ptr2 = NULL;
562         int fd = 0, fd2 = 0, rc = 0;
563
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) {
567                 perror("unlink()");
568                 return errno;
569         }
570
571         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
572         if (fd < 0) {
573                 perror(mmap_file);
574                 return errno;
575         }
576         if (ftruncate(fd, page_size) < 0) {
577                 perror("ftruncate()");
578                 rc = errno;
579                 goto out;
580         }
581
582         fd2 = open(mmap_file2, O_RDWR, 0600);
583         if (fd2 < 0) {
584                 perror(mmap_file2);
585                 goto out;
586         }
587
588         ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
589         if (ptr == MAP_FAILED) {
590                 perror("mmap()");
591                 rc = errno;
592                 goto out;
593         }
594         
595         ptr2 = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
596         if (ptr2 == MAP_FAILED) {
597                 perror("mmap()");
598                 rc = errno;
599                 goto out;
600         }
601
602         rc = cancel_lru_locks("osc");
603         if (rc)
604                 goto out;
605
606         memcpy(ptr, "blah", strlen("blah"));
607         if (strncmp(ptr, ptr2, strlen("blah"))) {
608                 fprintf(stderr, "client2 mmap mismatch!\n");
609                 rc = EFAULT;
610                 goto out;
611         }
612         memcpy(ptr2, "foo", strlen("foo"));
613         if (strncmp(ptr, ptr2, strlen("foo"))) {
614                 fprintf(stderr, "client1 mmap mismatch!\n");
615                 rc = EFAULT;
616         }
617 out:
618         if (ptr2)
619                 munmap(ptr2, page_size);
620         if (ptr)
621                 munmap(ptr, page_size);
622         if (fd2 > 0)
623                 close(fd2);
624         if (fd > 0)
625                 close(fd);
626         unlink(mmap_file);
627         return rc;
628 }
629
630 static int mmap_tst7_func(char *mnt, int rw)
631 {
632         char  fname[256];
633         char *buf = MAP_FAILED;
634         ssize_t bytes;
635         int fd = -1;
636         int rc = 0;
637
638         if (snprintf(fname, 256, "%s/mmap_tst7.%s",
639                      mnt, (rw == 0) ? "read":"write") >= 256) {
640                 fprintf(stderr, "dir name too long\n");
641                 rc = ENAMETOOLONG;
642                 goto out;
643         }
644         fd = open(fname, O_RDWR | O_DIRECT | O_CREAT, 0644);
645         if (fd == -1) {
646                 perror("open");
647                 rc = errno;
648                 goto out;
649         }
650         if (ftruncate(fd, 2 * page_size) == -1) {
651                 perror("truncate");
652                 rc = errno;
653                 goto out;
654         }
655         buf = mmap(NULL, page_size,
656                    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
657         if (buf == MAP_FAILED) {
658                 perror("mmap");
659                 rc = errno;
660                 goto out;
661         }
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)
668                 goto out;
669         fprintf(stderr, "%s returned %zd, errno = %d\n",
670                 (rw == 0)?"read":"write", bytes, errno);
671         rc = EIO;
672 out:
673         if (buf != MAP_FAILED)
674                 munmap(buf, page_size);
675         if (fd != -1)
676                 close(fd);
677         return rc;
678 }
679
680 static int mmap_tst7(char *mnt)
681 {
682         int rc;
683
684         rc = mmap_tst7_func(mnt, 0);
685         if (rc != 0)
686                 return rc;
687         rc = mmap_tst7_func(mnt, 1);
688         return rc;
689 }
690
691 static int remote_tst(int tc, char *mnt)
692 {
693         int rc = 0;
694         switch(tc) {
695         case 3:
696                 rc = remote_tst3(mnt);
697                 break;
698         case 4:
699                 rc = remote_tst4(mnt);
700                 break;
701         default:
702                 fprintf(stderr, "wrong test case number %d\n", tc);
703                 rc = EINVAL;
704                 break;
705         }
706         return rc;
707 }
708         
709 struct test_case {
710         int     tc;                     /* test case number */
711         char    *desc;                  /* test description */
712         int     (* test_fn)(char *mnt); /* test function */
713         int     node_cnt;               /* node count */
714 };
715
716 struct test_case tests[] = {
717         { 1, "mmap test1: basic mmap operation", mmap_tst1, 1 },
718         { 2, "mmap test2: MAP_PRIVATE not write back", mmap_tst2, 1 },
719         { 3, "mmap test3: concurrent mmap ops on two nodes", mmap_tst3, 2 },
720         { 4, "mmap test4: c1 write to f1 from mmapped f2, " 
721              "c2 write to f1 from mmapped f1", mmap_tst4, 2 },
722         { 5, "mmap test5: read/write file to/from the buffer "
723              "which mmapped to just this file", mmap_tst5, 1 },
724         { 6, "mmap test6: check mmap write/read content on two nodes", 
725                 mmap_tst6, 2 },
726         { 7, "mmap test7: file i/o with an unmapped buffer", mmap_tst7, 1},
727         { 0, NULL, 0, 0 }
728 };
729
730 int main(int argc, char **argv)
731 {
732         extern char *optarg;
733         struct test_case *test;
734         int c, rc = 0;
735
736         for(;;) {
737                 c = getopt(argc, argv, "d:m:");
738                 if ( c == -1 )
739                         break;
740
741                 switch(c) {
742                         case 'd':
743                                 dir = optarg;
744                                 break;
745                         case 'm':
746                                 dir2 = optarg;
747                                 break;
748                         default:
749                         case '?':
750                                 usage();
751                                 break;
752                 }
753         }
754
755         if (dir == NULL)
756                 usage();
757
758         if (mmap_initialize(argv[0]) != 0) {
759                 fprintf(stderr, "mmap_initialize failed!\n");
760                 return EINVAL;
761         }
762
763         for (test = tests; test->tc; test++) {
764                 char *rs = "skip";
765                 rc = 0;
766                 if (test->node_cnt == 1 || dir2 != NULL) {
767                         rc = test->test_fn(dir);
768                         rs = rc ? "fail" : "pass";
769                 }
770                 fprintf(stderr, "%s (%s)\n", test->desc, rs);
771                 if (rc)
772                         break;
773         }
774
775         mmap_finalize();
776         return rc;
777 }