Whamcloud - gitweb
- many gcc4 compilation fixes (warnings)
[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 #include <stdio.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <sys/mman.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <netinet/in.h>
13 #include <sys/socket.h>
14 #include <netdb.h>
15 #include <string.h>
16
17 char *dir = NULL, *node = NULL, *dir2 = NULL;
18 long page_size;
19 char mmap_sanity[256];
20
21
22 static void usage(void)
23 {
24         printf("Usage: mmap_sanity -d dir [-n node | -m dir2]\n");
25         printf("       dir      lustre mount point\n");
26         printf("       node     another client\n");
27         printf("       dir2     another mount point\n");
28         exit(127);
29 }
30
31 #define MMAP_NOTIFY_PORT        7676
32 static int mmap_notify(char *target, char *str, int delay)
33 {
34         unsigned short port = MMAP_NOTIFY_PORT;
35         int socket_type = SOCK_DGRAM;
36         struct sockaddr_in server;
37         struct hostent *hp;
38         int len, sockfd, rc = 0;
39
40         if (target == NULL)
41                 return 0;
42
43         sockfd = socket(AF_INET, socket_type, 0);
44         if (sockfd < 0) {
45                 perror("socket()");
46                 return errno;
47         }
48
49         if ((hp = gethostbyname(target)) == NULL) {
50                 perror(target);
51                 rc = errno;
52                 goto out_close;
53         }
54
55         memset(&server,0,sizeof(server));
56         memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
57         server.sin_family = AF_INET;
58         server.sin_port = htons(port);
59         
60         len = sizeof(server);
61         if (delay)
62                 sleep(delay);
63         
64         rc = sendto(sockfd, str, strlen(str), 0, 
65                     (struct sockaddr *)&server, len);
66         if (rc < 0) {
67                 perror("sendto()");
68                 rc = errno;
69         } else
70                 rc = 0;
71
72 out_close:
73         close(sockfd);
74         return rc;
75 }
76
77 static int mmap_wait(char *str, int timeout)
78 {
79         unsigned short port = MMAP_NOTIFY_PORT;
80         int socket_type = SOCK_DGRAM;
81         struct sockaddr_in local, from;
82         char host[256];
83         struct hostent *hp;
84         fd_set rfds;
85         struct timeval tv;
86         int sockfd, rc = 0;
87
88         if (dir2 != NULL)
89                 return 0;
90         
91         memset(host, 0, sizeof(host));
92         if (gethostname(host, sizeof(host))) {
93                 perror("gethostname()");
94                 return errno;
95         }
96         
97         if ((hp = gethostbyname(host)) == NULL) {
98                 perror(host);
99                 return errno;
100         }
101
102         local.sin_family = AF_INET;
103         memcpy(&(local.sin_addr), hp->h_addr, hp->h_length);
104         local.sin_port = htons(port);
105         
106         sockfd = socket(AF_INET, socket_type, 0);
107         if (sockfd < 0) {
108                 perror("socket()");
109                 return errno;
110         }
111
112         rc = bind(sockfd, (struct sockaddr *)&local, sizeof(local));
113         if (rc < 0) {
114                 perror("bind()");
115                 rc = errno;
116                 goto out_close;
117         }
118
119         FD_ZERO(&rfds);
120         FD_SET(sockfd, &rfds);
121         tv.tv_sec = timeout ? timeout : 5;
122         tv.tv_usec = 0;
123
124         rc = select(sockfd + 1, &rfds, NULL, NULL, &tv);
125         if (rc) {       /* got data */
126                 char buffer[1024];
127                 int fromlen =sizeof(from);
128                 
129                 memset(buffer, 0, sizeof(buffer));
130                 rc = recvfrom(sockfd, buffer, sizeof(buffer),
131                               0, (struct sockaddr *)&from,
132                               (socklen_t *)&fromlen);
133                 if (rc <= 0) {
134                         perror("recvfrom()");
135                         rc = errno;
136                         goto out_close;
137                 }
138                 rc = 0;
139
140                 if (strncmp(str, buffer, strlen(str)) != 0) {
141                         fprintf(stderr, "expected string mismatch!\n");
142                         rc = EINVAL;
143                 }
144         } else {        /* timeout */
145                 fprintf(stderr, "timeout!\n");
146                 rc = ETIME;
147         }
148
149 out_close:
150         close(sockfd);
151         return rc;
152 }
153
154 static int remote_tst(int tc, char *mnt);
155 static int mmap_run(char *host, int tc)
156 {
157         pid_t child;
158         char nodearg[256], command[256];
159         int rc = 0;
160
161         child = fork();
162         if (child < 0)
163                 return errno;
164         else if (child)
165                 return 0;
166
167         if (dir2 != NULL) {
168                 rc = remote_tst(tc, dir2);
169         } else {
170                 sprintf(nodearg, "-w %s", node);
171                 sprintf(command, "%s -d %s -n %s -c %d", 
172                         mmap_sanity, dir, host, tc);
173                 rc = execlp("pdsh", "pdsh", "-S", nodearg, command, NULL);
174                 if (rc)
175                         perror("execlp()");
176         }
177         _exit(rc);
178 }
179
180 static int mmap_initialize(char *myself, int tc)
181 {
182         char buf[1024], *file;
183         int fdr, fdw, count, rc = 0;
184         
185         page_size = sysconf(_SC_PAGESIZE);
186         if (page_size == -1) {
187                 perror("sysconf(_SC_PAGESIZE)");
188                 return errno;
189         }
190         if (tc)
191                 return 0;
192
193         /* copy myself to lustre for another client */
194         fdr = open(myself, O_RDONLY);
195         if (fdr < 0) {
196                 perror(myself);
197                 return EINVAL;
198         }
199         file = strrchr(myself, '/');
200         if (file == NULL) {
201                 fprintf(stderr, "can't get test filename\n");
202                 close(fdr);
203                 return EINVAL;
204         }
205         file++;
206         sprintf(mmap_sanity, "%s/%s", dir, file);
207
208         fdw = open(mmap_sanity, O_CREAT|O_WRONLY, 0777);
209         if (fdw < 0) {
210                 perror(mmap_sanity);
211                 close(fdr);
212                 return EINVAL;
213         }
214         while ((count = read(fdr, buf, sizeof(buf))) != 0) {
215                 int writes;
216
217                 if (count < 0) {
218                         perror("read()");
219                         rc = errno;
220                         break;
221                 }
222                 writes = write(fdw, buf, count);
223                 if (writes != count) {
224                         perror("write()");
225                         rc = errno;
226                         break;
227                 }
228         }
229         close(fdr);
230         close(fdw);
231         return rc;
232 }
233
234 static void mmap_finalize(int tc)
235 {
236         if (tc)
237                 return;
238         unlink(mmap_sanity);
239 }
240
241 /* basic mmap operation on single node */
242 static int mmap_tst1(char *mnt)
243 {
244         char *ptr, mmap_file[256];
245         int i, j, region, fd, rc = 0;
246
247         region = page_size * 10;
248         sprintf(mmap_file, "%s/%s", mnt, "mmap_file1");
249         
250         if (unlink(mmap_file) && errno != ENOENT) {
251                 perror("unlink()");
252                 return errno;
253         }
254
255         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
256         if (fd < 0) {
257                 perror(mmap_file);
258                 return errno;
259         }
260         ftruncate(fd, region);
261
262         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
263         if (ptr == MAP_FAILED) {
264                 perror("mmap()");
265                 rc = errno;
266                 goto out_close;
267         }
268         memset(ptr, 'a', region);
269
270         /* mem write then sync */
271         for (i = 0; i < 5; i++) {
272                 for (j = 0; j < region; j += page_size)
273                         ptr[j] = i;
274                 sync();
275         }
276
277         munmap(ptr, region);
278 out_close:
279         close(fd);
280         unlink(mmap_file);
281         return rc;
282 }
283
284 /* MAP_PRIVATE create a copy-on-write mmap */
285 static int mmap_tst2(char *mnt)
286 {
287         char *ptr, mmap_file[256], buf[256];
288         int fd, rc = 0;
289
290         sprintf(mmap_file, "%s/%s", mnt, "mmap_file2");
291
292         if (unlink(mmap_file) && errno != ENOENT) {
293                 perror("unlink()");
294                 return errno;
295         }
296
297         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
298         if (fd < 0) {
299                 perror(mmap_file);
300                 return errno;
301         }
302         ftruncate(fd, page_size);
303
304         ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
305         if (ptr == MAP_FAILED) {
306                 perror("mmap()");
307                 rc = errno;
308                 goto out_close;
309         }
310         memcpy(ptr, "blah", strlen("blah"));
311
312         munmap(ptr, page_size);
313 out_close:
314         close(fd);
315         if (rc)
316                 return rc;
317
318         fd = open(mmap_file, O_RDONLY);
319         if (fd < 0) {
320                 perror(mmap_file);
321                 return errno;
322         }
323         rc = read(fd, buf, sizeof(buf));
324         if (rc < 0) {
325                 perror("read()");
326                 rc = errno;
327                 goto out_close;
328         }
329         rc = 0;
330         
331         if (strncmp("blah", buf, strlen("blah")) == 0) {
332                 fprintf(stderr, "mmap write back with MAP_PRIVATE!\n");
333                 rc = EFAULT;
334         }
335         close(fd);
336         unlink(mmap_file);
337         return rc;
338 }
339
340 /* cocurrent mmap operations on two nodes */
341 static int mmap_tst3(char *mnt)
342 {
343         char *ptr, mmap_file[256], host[256];
344         int region, fd, rc = 0;
345
346         region = page_size * 100;
347         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
348         
349         if (unlink(mmap_file) && errno != ENOENT) {
350                 perror("unlink()");
351                 return errno;
352         }
353
354         fd = open(mmap_file, O_CREAT|O_RDWR, 0600);
355         if (fd < 0) {
356                 perror(mmap_file);
357                 return errno;
358         }
359         ftruncate(fd, region);
360
361         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
362         if (ptr == MAP_FAILED) {
363                 perror("mmap()");
364                 rc = errno;
365                 goto out_close;
366         }
367
368         if (gethostname(host, sizeof(host))) {
369                 perror("gethostname()");
370                 rc = errno;
371                 goto out_unmap;
372         }
373         
374         rc = mmap_run(host, 3);
375         if (rc)
376                 goto out_unmap;
377         
378         rc = mmap_wait("mmap done", 10);
379         memset(ptr, 'a', region);
380
381         sleep(2);       /* wait for remote test finish */
382 out_unmap:
383         munmap(ptr, region);
384 out_close:
385         close(fd);
386         unlink(mmap_file);
387         return rc;
388 }       
389
390 static int remote_tst3(char *mnt)
391 {
392         char *ptr, mmap_file[256];
393         int region, fd, rc = 0;
394
395         region = page_size * 100;
396         sprintf(mmap_file, "%s/%s", mnt, "mmap_file3");
397
398         fd = open(mmap_file, O_RDWR, 0600);
399         if (fd < 0) {
400                 perror(mmap_file);
401                 return errno;
402         }
403
404         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
405         if (ptr == MAP_FAILED) {
406                 perror("mmap()");
407                 rc = errno;
408                 goto out_close;
409         }
410         memset(ptr, 'b', region);
411
412         rc = mmap_notify(node, "mmap done", 1);
413         if (rc)
414                 goto out_unmap;
415         
416         memset(ptr, 'c', region);
417         
418 out_unmap:
419         munmap(ptr, region);
420 out_close:
421         close(fd);
422         return rc;
423 }
424
425 /* client1 write to file_4a from mmap()ed file_4b;
426  * client2 write to file_4b from mmap()ed file_4a. */
427 static int mmap_tst4(char *mnt)
428 {
429         char *ptr, filea[256], fileb[256], host[256];
430         int region, fdr, fdw, rc = 0;
431
432         region = page_size * 100;
433         sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
434         sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
435
436         if (unlink(filea) && errno != ENOENT) {
437                 perror("unlink()");
438                 return errno;
439         }
440         if (unlink(fileb) && errno != ENOENT) {
441                 perror("unlink()");
442                 return errno;
443         }
444
445         fdr = fdw = -1;
446         fdr = open(fileb, O_CREAT|O_RDWR, 0600);
447         if (fdr < 0) {
448                 perror(fileb);
449                 return errno;
450         }
451         ftruncate(fdr, region);
452         fdw = open(filea, O_CREAT|O_RDWR, 0600);
453         if (fdw < 0) {
454                 perror(filea);
455                 rc = errno;
456                 goto out_close;
457         }
458         ftruncate(fdw, region);
459         
460         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
461         if (ptr == MAP_FAILED) {
462                 perror("mmap()");
463                 rc = errno;
464                 goto out_close;
465         }
466
467         if (gethostname(host, sizeof(host))) {
468                 perror("gethostname()");
469                 rc = errno;
470                 goto out_unmap;
471         }
472         
473         rc = mmap_run(host, 4);
474         if (rc)
475                 goto out_unmap;
476         
477         rc = mmap_wait("mmap done", 10);
478         if (rc)
479                 goto out_unmap;
480         
481         memset(ptr, '1', region);
482         
483         rc = write(fdw, ptr, region);
484         if (rc <= 0) {
485                 perror("write()");
486                 rc = errno;
487         } else
488                 rc = 0;
489
490         sleep(2);       /* wait for remote test finish */
491 out_unmap:
492         munmap(ptr, region);
493 out_close:
494         if (fdr >= 0)
495                 close(fdr);
496         if (fdw >= 0)
497                 close(fdw);
498         unlink(filea);
499         unlink(fileb);
500         return rc;
501 }
502
503 static int remote_tst4(char *mnt)
504 {
505         char *ptr, filea[256], fileb[256];
506         int region, fdr, fdw, rc = 0;
507
508         region = page_size * 100;
509         sprintf(filea, "%s/%s", mnt, "mmap_file_4a");
510         sprintf(fileb, "%s/%s", mnt, "mmap_file_4b");
511
512         fdr = fdw = -1;
513         fdr = open(filea, O_RDWR, 0600);
514         if (fdr < 0) {
515                 perror(filea);
516                 return errno;
517         }
518         fdw = open(fileb, O_RDWR, 0600);
519         if (fdw < 0) {
520                 perror(fileb);
521                 rc = errno;
522                 goto out_close;
523         }
524
525         ptr = mmap(NULL, region, PROT_READ|PROT_WRITE, MAP_SHARED, fdr, 0);
526         if (ptr == MAP_FAILED) {
527                 perror("mmap()");
528                 rc = errno;
529                 goto out_close;
530         }
531
532         rc = mmap_notify(node, "mmap done", 1);
533         if (rc)
534                 goto out_unmap;
535
536         memset(ptr, '2', region);
537
538         rc = write(fdw, ptr, region);
539         if (rc <= 0) {
540                 perror("write()");
541                 rc = errno;
542         } else
543                 rc = 0;
544      
545 out_unmap:
546         munmap(ptr, region);
547 out_close:
548         if (fdr >= 0)
549                 close(fdr);
550         if (fdw >= 0)
551                 close(fdw);
552         return rc;
553 }
554
555 static int remote_tst(int tc, char *mnt)
556 {
557         int rc = 0;
558         switch(tc) {
559         case 3:
560                 rc = remote_tst3(mnt);
561                 break;
562         case 4:
563                 rc = remote_tst4(mnt);
564                 break;
565         case 1:
566         case 2:
567         default:
568                 fprintf(stderr, "wrong test case number %d\n", tc);
569                 rc = EINVAL;
570                 break;
571         }
572         return rc;
573 }
574         
575 struct test_case {
576         int     tc;                     /* test case number */
577         char    *desc;                  /* test description */
578         int     (* test_fn)(char *mnt); /* test function */
579         int     node_cnt;               /* node count */
580 };
581
582 struct test_case tests[] = {
583         { 1, "mmap test1: basic mmap operation", mmap_tst1, 1 },
584         { 2, "mmap test2: MAP_PRIVATE not write back", mmap_tst2, 1 },
585         { 3, "mmap test3: cocurrent mmap ops on two nodes", mmap_tst3, 2 },
586         { 4, "mmap test4: c1 write to f1 from mmaped f2, " 
587              "c2 write to f1 from mmaped f1", mmap_tst4, 2 },
588         { 0, NULL, 0, 0 }
589 };
590
591 int main(int argc, char **argv)
592 {
593         extern char *optarg;
594         struct test_case *test;
595         int c, rc = 0, tc = 0;
596
597         for(;;) {
598                 c = getopt(argc, argv, "d:n:c:m:");
599                 if ( c == -1 )
600                         break;
601
602                 switch(c) {
603                         case 'd':
604                                 dir = optarg;
605                                 break;
606                         case 'n':
607                                 node = optarg;
608                                 break;
609                         case 'c':
610                                 tc = atoi(optarg);
611                                 break;
612                         case 'm':
613                                 dir2 = optarg;
614                                 break;
615                         default:
616                         case '?':
617                                 usage();
618                                 break;
619                 }
620         }
621
622         if (dir == NULL)
623                 usage();
624         if (dir2 != NULL && node != NULL)
625                 usage();
626
627         if (mmap_initialize(argv[0], tc) != 0) {
628                 fprintf(stderr, "mmap_initialize failed!\n");
629                 return EINVAL;
630         }
631
632         if (tc) {
633                 rc = remote_tst(tc, dir);
634                 goto out;
635         }
636         
637         for (test = tests; test->tc; test++) {
638                 char *rs = "skip";
639                 rc = 0;
640                 if (test->node_cnt == 1 || node != NULL || dir2 != NULL) {
641                         rc = test->test_fn(dir);
642                         rs = rc ? "fail" : "pass";
643                 }
644                 fprintf(stderr, "%s (%s)\n", test->desc, rs);
645                 if (rc)
646                         break;
647         }
648 out:
649         mmap_finalize(tc);
650         return rc;
651 }