Whamcloud - gitweb
LU-12795 tests: Prefer FAILF in mpi tests
[fs/lustre-release.git] / lustre / tests / mpi / parallel_grouplock.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 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  * Lustre is a trademark of Sun Microsystems, Inc.
29  *
30  * lustre/tests/parallel_grouplock.c
31  *
32  * Author: You Feng <youfeng@clusterfs.com>
33  */
34
35 #include <limits.h>
36 #include <mpi.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <asm/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <sys/ioctl.h>
45 #include <unistd.h>
46 #include <time.h>
47 #include <errno.h>
48 #include "lp_utils.h"
49
50 #define LPGL_BUF_LEN 8192
51 #define LPGL_TEST_ITEMS 12
52
53 #define MIN_GLHOST 5
54
55 #define MAX_WAIT_TRIES            10
56 #define WAIT_TIME                  1  /* secs */
57 #define ONE_MB               1048576  /*   1 MB */
58 #define MIN_LGBUF_SIZE     536870912  /* 512 MB */
59 #define MAX_LGBUF_SIZE     536870912  /* 512 MB */
60 // #define MAX_LGBUF_SIZE    1073741824  /*   1 GB */
61
62 #define READ    1
63 #define WRITE   2
64 #define IOCTL   3
65 #define CLOSE   4
66
67 int rank;
68 int size;
69
70 char *testdir;
71 int only_test;
72
73 char buf[LPGL_BUF_LEN];
74 char *lgbuf;
75 int lgbuf_size;
76 char filename[MAX_FILENAME_LEN];
77
78 static void
79 alloc_lgbuf()
80 {
81         if (lgbuf)
82                 return;
83
84         lgbuf_size = MAX_LGBUF_SIZE;
85         for (; lgbuf_size >= MIN_LGBUF_SIZE; lgbuf_size -= ONE_MB)
86                 if ((lgbuf = (char *)malloc(lgbuf_size)) != NULL)
87                         return;
88
89         FAIL("malloc of large buffer failed.\n");
90 }
91
92 static inline void
93 read_buf(int fd)
94 {
95         int pos, rc;
96
97         rc = read(fd, buf, sizeof(buf));
98         if (rc == -1) {
99                 pos = lseek(fd, 0, SEEK_CUR);
100                 FAILF("read of file %s at pos %d for %zu bytes returned %d: (%d) %s.\n",
101                       filename, pos, sizeof(buf), rc, errno, strerror(errno));
102         } else if (rc != sizeof(buf)) {
103                 pos = lseek(fd, 0, SEEK_CUR);
104                 FAILF("read of file %s at pos %d for %zu bytes returned %d.\n",
105                       filename, pos, sizeof(buf), rc);
106         }
107 }
108
109 static inline void
110 write_buf(int fd, int index)
111 {
112         int pos = index * sizeof(buf);
113         int rc;
114
115         memset(buf, index, sizeof(buf));
116         lseek(fd, pos, SEEK_SET);
117         rc = write(fd, buf, sizeof(buf));
118         if (rc == -1)
119                 FAILF("write of file %s at pos %d for %zu bytes returned %d: (%d) %s.\n",
120                       filename, pos, sizeof(buf), rc, errno, strerror(errno));
121         else if (rc != sizeof(buf))
122                 FAILF("write of file %s at pos %d for %zu bytes returned %d.\n",
123                       filename, pos, sizeof(buf), rc);
124 }
125
126 /*
127  * task0 attempts GR(gid=1) -- granted immediately
128  * task1 attempts PR|PW -- blocked, goes on waiting list
129  * task2 attempts GR(gid=1) -> should be granted
130  * task2 writes to file and releases GR(gid=1)
131  * task0 waits for task2 to complete its processing
132  * task0 writes to file and releases GR(gid=1)
133  * task1 PR|PW should be granted and reads the file
134  */
135 void grouplock_test1(char *filename, int fd, int blocking_op, int unlock_op)
136 {
137         MPI_Request req1, req2;
138         int iter, flag1, flag2, temp1, temp2;
139         int i, rc, gid = 1;
140
141         if (rank == 0) {
142                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
143                 if (rc == -1)
144                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
145                               filename, errno, strerror(errno));
146         }
147
148         MPI_Barrier(MPI_COMM_WORLD);
149
150         switch (rank) {
151         case 1:
152                 if (blocking_op == WRITE) {
153                         write_buf(fd, rank);
154                         lseek(fd, 0, SEEK_SET);
155                 }
156
157                 for (i = 0; i <= 2; i++)
158                         read_buf(fd);
159
160                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
161                 break;
162         case 2:
163                 /* Wait for task1 to progress. This could be racey. */
164                 sleep(WAIT_TIME);
165
166                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
167                 if (rc == -1)
168                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
169                               filename, errno, strerror(errno));
170
171                 write_buf(fd, rank);
172
173                 if (unlock_op == CLOSE)
174                         rc = close(fd);
175                 else
176                         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
177
178                 if (rc == -1)
179                         FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
180                               (unlock_op == CLOSE) ? "close" : "ioctl",
181                               filename, errno, strerror(errno));
182
183                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
184                 break;
185         case 0:
186                 /* PR|PW task will tell us when it completes */
187                 MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
188                 /* 2nd locking task will tell us when it completes */
189                 MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
190
191                 /* Wait for task2 to complete. */
192                 iter = MAX_WAIT_TRIES;
193                 do {
194                         iter--;
195                         if (!iter)
196                                 FAIL("2nd locking task is not progressing\n");
197
198                         sleep(WAIT_TIME);
199
200                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
201                         if (flag1)
202                                 FAIL("PR|PW task progressed even though GROUP lock is held\n");
203
204                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
205                 } while (!flag2);
206
207                 /* Make sure task1 is still waiting. */
208                 iter = MAX_WAIT_TRIES;
209                 do {
210                         iter--;
211                         sleep(WAIT_TIME);
212                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
213                         if (flag1)
214                                 FAIL("PR|PW task progressed even though GROUP lock is held\n");
215                 } while (iter);
216
217                 write_buf(fd, rank);
218
219                 /* Now we need to release the lock */
220                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
221                 if (rc == -1)
222                         FAILF("ioctl GROUP_UNLOCK of file %s: (%d) %s.\n",
223                               filename, errno, strerror(errno));
224
225                 /* Wait for task1 to complete. */
226                 iter = MAX_WAIT_TRIES;
227                 do {
228                         iter--;
229                         if (!iter) {
230                                 FAIL("PR|PW task is not progressing even though GROUP lock was released\n");
231                                 break;
232                         }
233                         sleep(WAIT_TIME);
234                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
235                 } while (!flag1);
236
237                 break;
238         }
239 }
240
241 /*
242  * task0 attempts GR(gid=1) -- granted immediately
243  * task1 attempts GR(gid=2) -- blocked
244  * task2 attempts PR|PW -- blocked
245  * task3 attempts GR(gid=2) -- blocked
246  * task4 attempts GR(gid=1) -- should be granted
247  * task0,4 writes to file and releases GR(gid=1) --
248  *       this allows task2 & 3's GR locks to be granted; task4 remains blocked.
249  * task1 & 3 write to file and release GR(gid=2)
250  * task2 PR|PW should be granted and reads the file.
251  */
252 void grouplock_test2(char *filename, int fd, int blocking_op, int unlock_op)
253 {
254         int i, iter, rc, gid = 1;
255         int flag1, flag2, flag3, flag4;
256         int temp1, temp2, temp3, temp4;
257         MPI_Request req1, req2, req3, req4;
258
259         if (rank == 0) {
260                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
261                 if (rc == -1)
262                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
263                               filename, errno, strerror(errno));
264         }
265
266         MPI_Barrier(MPI_COMM_WORLD);
267
268         switch (rank) {
269         case 3:
270                 /* Wait for task2 to issue its read request. */
271                 sleep(2 * WAIT_TIME);
272         case 1:
273                 gid = 2;
274                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
275                 if (rc == -1)
276                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
277                               filename, errno, strerror(errno));
278
279                 write_buf(fd, rank);
280
281                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
282
283                 /*
284                  * Do not release the locks until task 0 is ready to watch
285                  * for reading task only
286                  */
287                 MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
288                          MPI_STATUS_IGNORE);
289
290                 if (unlock_op == CLOSE)
291                         rc = close(fd);
292                 else
293                         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
294                 if (rc == -1)
295                         FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
296                               (unlock_op == CLOSE) ? "close" : "ioctl",
297                               filename, errno, strerror(errno));
298                 break;
299         case 2:
300                 /* Give task1 a chance to request its GR lock. */
301                 sleep(WAIT_TIME);
302
303                 if (blocking_op == WRITE) {
304                         write_buf(fd, rank);
305                         lseek(fd, 0, SEEK_SET);
306                 }
307
308                 for (i = 0; i <= 3; i++)
309                         read_buf(fd);
310
311                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
312                 break;
313         case 4:
314                 /* Give task1 & 3 a chance to queue their GR locks. */
315                 sleep(3 * WAIT_TIME);
316
317                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
318                 if (rc == -1)
319                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
320                               filename, errno, strerror(errno));
321
322                 write_buf(fd, rank);
323
324                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
325                 if (rc == -1)
326                         FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
327                               (unlock_op == CLOSE) ? "close" : "ioctl",
328                               filename, errno, strerror(errno));
329
330                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
331                 break;
332         case 0:
333                 /* locking tasks will tell us when they complete */
334                 MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
335                 MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
336                 MPI_Irecv(&temp3, 1, MPI_INT, 3, 1, MPI_COMM_WORLD, &req3);
337                 MPI_Irecv(&temp4, 1, MPI_INT, 4, 1, MPI_COMM_WORLD, &req4);
338
339                 /* Make sure all tasks that should be blocked are waiting. */
340                 iter = MAX_WAIT_TRIES;
341                 do {
342                         iter--;
343                         sleep(WAIT_TIME);
344                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
345                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
346                         MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
347                         if (flag1 || flag3)
348                                 FAIL("GROUP (gid=2) task progressed even though GROUP (gid=1) lock is held.\n");
349                         if (flag2)
350                                 FAIL("PR|PW task progressed even though GROUP (gid=1) lock is still held\n");
351                 } while (iter);
352
353                 /* Wait for task4 to signal it has completed. */
354                 iter = MAX_WAIT_TRIES;
355                 do {
356                         iter--;
357                         if (!iter)
358                                 FAIL("2nd task GROUP(gid=1) not progressing\n");
359
360                         sleep(WAIT_TIME);
361                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
362                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
363                         MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
364                         MPI_Test(&req4, &flag4, MPI_STATUS_IGNORE);
365                         if (flag1 || flag3)
366                                 FAIL("GROUP (gid=2) task progressed even though GROUP (gid=1) lock is held.\n");
367                         if (flag2)
368                                 FAIL("PR|PW task progressed even though GROUP (gid=1) lock is still held\n");
369                 } while (!flag4);
370
371                 write_buf(fd, rank);
372
373                 /* Now let's release first lock */
374                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
375                 if (rc == -1)
376                         FAILF("ioctl GROUP_UNLOCK of file %s returned %d",
377                               filename, rc);
378
379                 /* Wait for task1 & 3 to signal they have their lock. */
380                 iter = MAX_WAIT_TRIES;
381                 do {
382                         iter--;
383                         if (!iter)
384                                 FAIL("GROUP(gid=2) tasks not progressing\n");
385
386                         sleep(WAIT_TIME);
387                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
388                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
389                         MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
390                         if (flag2) {
391                                 fprintf(stderr, "task2 %d\n", flag2);
392                                 FAIL("PR task progressed even though GROUP lock was on the queue task\n");
393                         }
394                 } while (!(flag1 && flag3));
395
396                 /* Make sure task2 is still waiting. */
397                 iter = MAX_WAIT_TRIES;
398                 do {
399                         iter--;
400                         sleep(WAIT_TIME);
401                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
402                         if (flag2)
403                                 FAIL("PR task progressed even though GR(gid=2) lock was active.\n");
404                 } while (iter);
405
406                 /* Tell task1 & 3 to release their GR(gid=2) lock. */
407                 MPI_Send(&gid, 1, MPI_INT, 1, 1, MPI_COMM_WORLD);
408                 MPI_Send(&gid, 1, MPI_INT, 3, 1, MPI_COMM_WORLD);
409
410                 /* Wait for task2 (PR) to complete. */
411                 iter = MAX_WAIT_TRIES;
412                 do {
413                         iter--;
414                         if (!iter) {
415                                 FAIL("reading task is not progressing even though GROUP locks are released\n");
416                                 break;
417                         }
418                         sleep(WAIT_TIME);
419                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
420                 } while (!flag3);
421                 break;
422         }
423 }
424
425 /*
426  * Tests a bug that once existed in the group lock code;
427  * i.e. that a GR lock request on a O_NONBLOCK fd could fail even though
428  * there is no blocking GROUP lock ahead of it on the waitq.
429  *
430  * task0 starts a large write (PW). this test could be racey if this
431  *       write finishes too quickly.
432  * task1 attempts GR(gid=1) -- blocked
433  * task2 attempts GR(gid=2) with a O_NONBLOCK fs. should not fail.
434  */
435 void grouplock_test3(char *filename, int fd)
436 {
437         MPI_Request req1, req2;
438         int iter, flag1, flag2, temp1, temp2;
439         int rc, gid = 1;
440
441         if (rank == 0) {
442                 alloc_lgbuf();
443         } else if (rank == 2) {
444                 rc = fcntl(fd, F_SETFL, O_NONBLOCK);
445                 if (rc == -1)
446                         FAILF("fcntl(O_NONBLOCK) failed: (%d) %s.\n",
447                                 errno, strerror(errno));
448         }
449
450         MPI_Barrier(MPI_COMM_WORLD);
451
452         switch (rank) {
453         case 2:
454                 gid = 2;
455                 usleep(10000);
456                 usleep(10000);
457         case 1:
458                 /*
459                  * Racey, we have to sleep just long enough for
460                  * task0's write to start.
461                  */
462                 usleep(10000);
463
464                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
465                 if (rc == -1)
466                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
467                               filename, errno, strerror(errno));
468
469                 /* tell task0 we have the lock. */
470                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
471
472                 /* the close of fd will release the lock. */
473                 break;
474         case 0:
475                 rc = write(fd, lgbuf, lgbuf_size);
476                 if (rc == -1)
477                         FAILF("write of file %s for %d bytes returned %d: (%d) %s.\n",
478                               filename, lgbuf_size, rc, errno, strerror(errno));
479                 else if (rc != lgbuf_size)
480                         FAILF("write of file %s for %d bytes returned %d.\n",
481                               filename, lgbuf_size, rc);
482
483                 /* GR tasks will tell us when they complete */
484                 MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
485                 MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
486
487                 /* Wait for task1 & 2 to complete. */
488                 iter = MAX_WAIT_TRIES;
489                 do {
490                         iter--;
491                         if (!iter) {
492                                 FAIL("GR(gid=1) tasks are not progressing even no conflicting locks exist.\n");
493                                 break;
494                         }
495                         sleep(WAIT_TIME);
496                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
497                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
498                 } while (!(flag1 && flag2));
499                 break;
500         }
501 }
502
503 /*
504  * Tests a bug that once existed in the group lock code;
505  * i.e. extent locks without O_NONBLOCK that go on the waitq before a group
506  * lock request came in and was granted. The extent lock would timed out and
507  * produce an error.
508  *
509  * task0 starts a large write (PW). this test could be racey if this
510  *       write finishes too quickly.
511  * task1 attempts PR -- blocked
512  * task2 attempts GR(gid=1) -- blocked
513  * task0 completes write
514  * task1 should wakeup and complete its read
515  * task2 should wakeup and after task1 complete.
516  */
517 void grouplock_test4(char *filename, int fd)
518 {
519         MPI_Request req1;
520         int iter, flag1, temp1;
521         int rc, gid = 1;
522
523         if (rank == 0)
524                 alloc_lgbuf();
525
526         MPI_Barrier(MPI_COMM_WORLD);
527
528         switch (rank) {
529         case 1:
530                 /*
531                  * Racey, we have to sleep just long enough for
532                  * task0's write to start.
533                  */
534                 MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
535                          MPI_STATUS_IGNORE);
536
537                 /* tell task2 to go. */
538                 MPI_Send(&gid, 1, MPI_INT, 2, 1, MPI_COMM_WORLD);
539                 sleep(WAIT_TIME);
540
541                 read_buf(fd);
542                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
543                 break;
544         case 2:
545                 /* Give task0 & 1 a chance to start. */
546                 MPI_Recv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD,
547                          MPI_STATUS_IGNORE);
548                 sleep(2 * WAIT_TIME);
549
550                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
551                 if (rc == -1)
552                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
553                               filename, errno, strerror(errno));
554
555                 /* tell task0 we have the lock. */
556                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
557
558                 /*
559                  * Do not release the locks until task 0 tells us too.
560                  * for reading task only
561                  */
562                 MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
563                          MPI_STATUS_IGNORE);
564
565                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
566                 if (rc == -1)
567                         FAILF("ioctl GROUP_UNLOCK of file %s: (%d) %s.\n",
568                               filename, errno, strerror(errno));
569                 break;
570         case 0:
571                 /* tell task1 to go to avoid race */
572                 MPI_Send(&gid, 1, MPI_INT, 1, 1, MPI_COMM_WORLD);
573                 rc = write(fd, lgbuf, lgbuf_size);
574                 if (rc == -1)
575                         FAILF("write of file %s for %d bytes returned %d: (%d) %s.\n",
576                               filename, lgbuf_size,
577                               rc, errno, strerror(errno));
578                 else if (rc != lgbuf_size)
579                         FAILF("write of file %s for %d bytes returned %d.\n",
580                               filename, lgbuf_size, rc);
581
582                 /* wait for task2 to get its lock. */
583                 MPI_Recv(&temp1, 1, MPI_INT, 2, 1, MPI_COMM_WORLD,
584                          MPI_STATUS_IGNORE);
585
586                 /* Tell task2 it's ok to release its GR(gid=1) lock. */
587                 MPI_Send(&gid, 1, MPI_INT, 2, 1, MPI_COMM_WORLD);
588
589                 /* wait a really long time. */
590                 sleep(180 * WAIT_TIME);
591
592                 /* PR task will tell us when it completes */
593                 MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
594
595                 /*
596                  * Make sure the PR task is successful and doesn't hang.
597                  *
598                  * XXX - To test properly we need to make sure the read
599                  *       gets queued before task2's group lock request.
600                  *       You may need to increase lgbuf_size.
601                  */
602                 iter = MAX_WAIT_TRIES;
603                 do {
604                         iter--;
605                         if (!iter) {
606                                 FAIL("PR task is hung !\n");
607                                 break;
608                         }
609                         sleep(WAIT_TIME);
610                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
611                 } while (!flag1);
612
613                 break;
614         }
615 }
616
617 /*
618  * task0 attempts GR(gid=1) -- granted
619  * task1 attempts PR on non-blocking fd -> should return -EWOULDBLOCK
620  * task2 attempts PW on non-blocking fd -> should return -EWOULDBLOCK
621  * task3 attempts GR(gid=2) on non-blocking fd -> should return -EWOULDBLOCK
622  */
623 void grouplock_nonblock_test(char *filename, int fd)
624 {
625         MPI_Request req1, req2, req3;
626         int iter, flag1, flag2, flag3, temp1, temp2, temp3;
627         int rc, gid = 1;
628
629         if (rank == 0) {
630                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
631                 if (rc == -1)
632                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
633                               filename, errno, strerror(errno));
634         }
635
636         rc = fcntl(fd, F_SETFL, O_NONBLOCK);
637         if (rc == -1)
638                 FAILF("fcntl(O_NONBLOCK) failed: (%d) %s.\n",
639                       errno, strerror(errno));
640
641         MPI_Barrier(MPI_COMM_WORLD);
642
643         switch (rank) {
644         case 1:
645                 rc = read(fd, buf, sizeof(buf));
646                 if ((rc != -1) || (errno != EWOULDBLOCK))
647                         FAIL("PR lock succeeded while incompatible GROUP LOCK (gid=1) is still held\n");
648
649                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
650                 break;
651         case 2:
652                 rc = write(fd, buf, sizeof(buf));
653                 if ((rc != -1) || (errno != EWOULDBLOCK))
654                         FAIL("PW lock succeeded while incompatible GROUP LOCK (gid=1) is still held\n");
655
656                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
657                 break;
658         case 3:
659                 gid = 2;
660                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
661                 if ((rc != -1) || (errno != EWOULDBLOCK))
662                         FAIL("GROUP_LOCK (gid=2) succeeded while incompatible GROUP LOCK (gid=1) is still held.\n");
663
664                 MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
665                 break;
666         case 0:
667                 /* reading task will tell us when it completes */
668                 MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
669                 /* writing task will tell us when it completes */
670                 MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
671                 /* 2nd locking task will tell us when it completes */
672                 MPI_Irecv(&temp3, 1, MPI_INT, 3, 1, MPI_COMM_WORLD, &req3);
673
674                 iter = MAX_WAIT_TRIES;
675                 do {
676                         iter--;
677                         if (!iter)
678                                 FAIL("non-blocking tasks are not progressing\n");
679
680                         sleep(WAIT_TIME);
681                         MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
682                         MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
683                         MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
684                 } while (!(flag1 && flag2 && flag3));
685
686                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
687                 if (rc == -1)
688                         FAILF("ioctl GROUP_UNLOCK of file %s", filename);
689                 break;
690         }
691 }
692
693 /* Just test some error paths with invalid requests */
694 void grouplock_errorstest(char *filename, int fd)
695 {
696         int rc, gid = 1;
697
698         MPI_Barrier(MPI_COMM_WORLD);
699
700         switch (rank) {
701         case 0:
702                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
703                 if (rc == -1)
704                         FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
705                               filename, errno, strerror(errno));
706
707                 /* second group lock on same fd, same gid */
708                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
709                 if (rc == -1) {
710                         if (errno != EINVAL)
711                                 FAILF("Double GROUP lock failed with errno %d instead of EINVAL\n",
712                                       errno);
713                 } else {
714                         FAIL("Taking second GROUP lock on same fd succeed\n");
715                 }
716
717                 /* second group lock on same fd, different gid */
718                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid + 1);
719                 if (rc == -1) {
720                         if (errno != EINVAL)
721                                 FAILF("Double GROUP lock with different gid failed with errno %d instead of EINVAL\n",
722                                       errno);
723                 } else {
724                         FAIL("Taking second GROUP lock on same fd, with different gid, succeeded.\n");
725                 }
726
727                 /* GROUP unlock with wrong gid */
728                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid + 1);
729                 if (rc == -1) {
730                         if (errno != EINVAL)
731                                 FAILF("GROUP_UNLOCK with wrong gid failed with errno %d instead of EINVAL\n",
732                                       errno);
733                 } else {
734                         FAIL("GROUP unlock with wrong gid succeed\n");
735                 }
736
737                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
738                 if (rc == -1)
739                         FAILF("ioctl GROUP_UNLOCK of file %s returned %d.",
740                               filename, rc);
741                 break;
742
743         case 1:
744                 /* unlock of never locked fd */
745                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
746                 if (rc == -1) {
747                         if (errno != EINVAL)
748                                 FAILF("GROUP_UNLOCK on never locked fd failed with errno %d instead of EINVAL.\n",
749                                       errno);
750                 } else {
751                         FAIL("GROUP unlock on never locked fd succeed\n");
752                 }
753                 break;
754         }
755 }
756
757 void grouplock_file(char *name, int subtest)
758 {
759         int fd;
760         int flags = O_CREAT | O_RDWR | O_SYNC | O_TRUNC;
761         int mode = 0666;
762
763         sprintf(filename, "%s/%s", testdir, name);
764
765         fd = open(filename, flags, mode);
766         if (fd == -1)
767                 FAILF("open of file %s: (%d) %s.\n",
768                       filename, errno, strerror(errno));
769
770         MPI_Barrier(MPI_COMM_WORLD);
771
772         switch (subtest) {
773         case 1:
774                 grouplock_test1(filename, fd, READ, IOCTL);
775                 break;
776         case 2:
777                 grouplock_test1(filename, fd, READ, CLOSE);
778                 break;
779         case 3:
780                 grouplock_test1(filename, fd, WRITE, IOCTL);
781                 break;
782         case 4:
783                 grouplock_test1(filename, fd, WRITE, CLOSE);
784                 break;
785         case 5:
786                 grouplock_test2(filename, fd, READ, IOCTL);
787                 break;
788         case 6:
789                 grouplock_test2(filename, fd, READ, CLOSE);
790                 break;
791         case 7:
792                 grouplock_test2(filename, fd, WRITE, IOCTL);
793                 break;
794         case 8:
795                 grouplock_test2(filename, fd, WRITE, CLOSE);
796                 break;
797         case 9:
798                 grouplock_nonblock_test(filename, fd);
799                 break;
800         case 10:
801                 grouplock_errorstest(filename, fd);
802                 break;
803         case 11:
804                 grouplock_test3(filename, fd);
805                 break;
806         case 12:
807                 grouplock_test4(filename, fd);
808                 break;
809         default:
810                 FAILF("wrong subtest number %d (should be <= %d)",
811                       subtest, LPGL_TEST_ITEMS);
812         }
813
814         close(fd);
815
816         if (rank == 0)
817                 unlink(filename);
818
819         MPI_Barrier(MPI_COMM_WORLD);
820 }
821
822 void parallel_grouplock(void)
823 {
824         char teststr[16];
825         int i;
826
827         if (only_test) {
828                 sprintf(teststr, "subtest %d", only_test);
829                 begin(teststr);
830                 grouplock_file("parallel_grouplock", only_test);
831                 end(teststr);
832         } else {
833                 for (i = 1; i <= LPGL_TEST_ITEMS; i++) {
834                         sprintf(teststr, "subtest %d", i);
835                         begin(teststr);
836                         grouplock_file("parallel_grouplock", i);
837                         end(teststr);
838                 }
839         }
840 }
841
842 void usage(char *proc)
843 {
844         int i;
845
846         if (rank == 0) {
847                 printf("Usage: %s [-h] -d <testdir> [-n <num>]\n", proc);
848                 printf("           [-t <num>] [-v] [-V #] [-g]\n");
849                 printf("\t-h: prints this help message\n");
850                 printf("\t-d: the directory in which the tests will run\n");
851                 printf("\t-n: repeat test # times\n");
852                 printf("\t-t: run a particular test #\n");
853                 printf("\t-v: increase the verbositly level by 1\n");
854                 printf("\t-V: select a specific verbosity level\n");
855                 printf("\t-g: debug mode\n");
856         }
857
858         MPI_Initialized(&i);
859         if (i)
860                 MPI_Finalize();
861         exit(0);
862 }
863
864 int main(int argc, char *argv[])
865 {
866         int i, iterations = 1, c;
867
868         setbuf(stdout, 0);
869         setbuf(stderr, 0);
870
871         /*
872          * Check for -h parameter before MPI_Init so the binary can be
873          * called directly, without, for instance, mpirun
874          */
875         for (i = 1; i < argc; ++i) {
876                 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
877                         usage(argv[0]);
878         }
879
880         MPI_Init(&argc, &argv);
881         MPI_Comm_rank(MPI_COMM_WORLD, &rank);
882         MPI_Comm_size(MPI_COMM_WORLD, &size);
883
884         /* Parse command line options */
885         while (1) {
886                 c = getopt(argc, argv, "d:ghn:t:vV:");
887                 if (c == -1)
888                         break;
889
890                 switch (c) {
891                 case 'd':
892                         testdir = optarg;
893                         break;
894                 case 'g':
895                         debug = 1;
896                         break;
897                 case 'h':
898                         usage(argv[0]);
899                         break;
900                 case 'n':
901                         iterations = atoi(optarg);
902                         break;
903                 case 't':
904                         only_test = atoi(optarg);
905                         break;
906                 case 'v':
907                         verbose += 1;
908                         break;
909                 case 'V':
910                         verbose = atoi(optarg);
911                         break;
912                 }
913         }
914
915         if (rank == 0)
916                 printf("%s is running with %d task(es) %s\n",
917                        argv[0], size, debug ? "in DEBUG mode" : "\b\b");
918
919         if (size < MIN_GLHOST) {
920                 fprintf(stderr,
921                         "Error: %d tasks run, but should be at least %d tasks to run the test!\n",
922                         size, MIN_GLHOST);
923                 MPI_Abort(MPI_COMM_WORLD, 2);
924         }
925
926         if (!testdir && rank == 0) {
927                 fprintf(stderr,
928                         "Please specify a test directory! (\"%s -h\" for help)\n",
929                         argv[0]);
930                 MPI_Abort(MPI_COMM_WORLD, 2);
931         }
932
933         lp_gethostname();
934
935         for (i = 0; i < iterations; ++i) {
936                 if (rank == 0)
937                         printf("%s: Running test #%s(iter %d)\n",
938                                timestamp(), argv[0], i);
939
940                 parallel_grouplock();
941                 MPI_Barrier(MPI_COMM_WORLD);
942         }
943
944         if (rank == 0)
945                 printf("%s: All tests passed!\n", timestamp());
946
947         MPI_Finalize();
948         return 0;
949 }