1 /* *************************************************
2 * *********** README ******************************
3 * *************************************************
4 *
5 * COMPILE : make
6 * RUN : ./locktests -n <number of concurent process> -f <test file> [-P]
7 *
8 * GOAL : This test tries to stress the fcntl locking functions. A
9 * master process sets a lock on a file region (this is called "byte
10 * range locking"). Some slave processes try to perform operations on
11 * this region, such as read, write, set a new lock ... The expected
12 * results of these operations are known. If the operation result is
13 * the same as the expected one, the test suceeds, else it fails.
14 *
15 *
16 *
17 * Slaves are concurent processes or thread.
18 * -n <num> : Number of threads to use (mandatory).
19 * -f <file> : Run the test on given test file defined by the -f option (mandatory).
20 * -c <num> : Number of clients to connect before starting the tests.
21 *
22 * HISTORY : This program was written to stress NFSv4 locks.
23 * EXAMPLE : ./locktests -n 50 -f /file/system/to/test
24 *
25 *
26 * Vincent ROQUETA 2005 - vincent.roqueta@ext.bull.net
27 * BULL S.A.
28 */
29
30 #include "locktests.h"
31
32 int MAXLEN = 64;
33 int MAXTEST = 10;
34 extern int maxClients;
35 extern int fdServer;
36
37 char message[M_SIZE];
38 int slaveReader;
39 int masterReader;
40 int slaveWriter;
41
42 /* Which lock will be applied by the master process on test startup */
43 int LIST_LOCKS[] = { READLOCK, WRITELOCK,
44 READLOCK, WRITELOCK,
45 READLOCK, WRITELOCK,
46 READLOCK, WRITELOCK,
47 BYTELOCK_READ, BYTELOCK_WRITE
48 };
49
50 /* The operations the slave processes will try to perform */
51 int LIST_TESTS[] = { WRONLY, WRONLY,
52 RDONLY, RDONLY,
53 READLOCK, WRITELOCK,
54 WRITELOCK, READLOCK,
55 BYTELOCK_READ, BYTELOCK_WRITE
56 };
57
58 /* List of test names */
59 char *LIST_NAMES_TESTS[] = { "WRITE ON A READ LOCK",
60 "WRITE ON A WRITE LOCK",
61 "READ ON A READ LOCK",
62 "READ ON A WRITE LOCK",
63 "SET A READ LOCK ON A READ LOCK",
64 "SET A WRITE LOCK ON A WRITE LOCK",
65 "SET A WRITE LOCK ON A READ LOCK",
66 "SET A READ LOCK ON A WRITE LOCK",
67 "READ LOCK THE WHOLE FILE BYTE BY BYTE",
68 "WRITE LOCK THE WHOLE FILE BYTE BY BYTE"
69 };
70
71 /* List of expected test results, when slaves are processes */
72 int LIST_RESULTS_PROCESS[] = { SUCCES, SUCCES,
73 SUCCES, SUCCES,
74 SUCCES, ECHEC,
75 ECHEC, ECHEC,
76 SUCCES, SUCCES
77 };
78
79 /* List of expected test results, when slaves are threads */
80 int LIST_RESULTS_THREADS[] = { SUCCES, SUCCES,
81 SUCCES, SUCCES,
82 SUCCES, SUCCES,
83 SUCCES, SUCCES,
84 ECHEC, ECHEC
85 };
86
87 int *LIST_RESULTS = NULL;
88 char *eType = NULL;
89
90 int TOTAL_RESULT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
91
92 void *slave(void *data);
93 int (*finish) (int a);
94
finishProcess(int a)95 int finishProcess(int a)
96 {
97 exit(a);
98 }
99
100 int (*load) (void);
101
102 struct dataPub dp;
103
104 /* Functions to access tests/tests names/tests results*/
testSuiv(int n)105 int testSuiv(int n)
106 {
107 return LIST_TESTS[n];
108 }
109
resAttSuiv(int n)110 int resAttSuiv(int n)
111 {
112 return LIST_RESULTS[n];
113 }
114
nomTestSuiv(int n)115 char *nomTestSuiv(int n)
116 {
117 return LIST_NAMES_TESTS[n];
118 }
119
lockSuiv(int n)120 int lockSuiv(int n)
121 {
122 return LIST_LOCKS[n];
123 }
124
125 /* Verify the test result is the expected one */
matchResult(int r,int n)126 int matchResult(int r, int n)
127 {
128
129 P("r=%d\n", r);
130 if (r == LIST_RESULTS[n])
131 return 1;
132 else
133 return 0;
134 }
135
136 /* Increments the number of process which have successfully passed the test */
counter(int r,int n)137 void counter(int r, int n)
138 {
139 TOTAL_RESULT_OK[n] += matchResult(r, n);
140 }
141
142 /* Special case for test 'lock file byte byte by byte'.
143 * We ensure each byte is correctly locked.
144 */
validationResults(int n)145 void validationResults(int n)
146 {
147 int i, u, l, fsize;
148 struct flock request;
149
150 fsize = dp.nclnt * (maxClients + 1);
151 TOTAL_RESULT_OK[n] = 0;
152 l = FALSE;
153 u = TRUE;
154
155 /* If the expected operation result is a success, we will have to increase the number of correct results */
156 if (LIST_RESULTS[n]) {
157 l = TRUE;
158 u = FALSE;
159 }
160
161 for (i = 0; i < fsize; i++) {
162 request.l_type = F_WRLCK;
163 request.l_whence = SEEK_SET;
164 request.l_start = i;
165 request.l_len = 1;
166 fcntl(dp.fd, F_GETLK, &request);
167 /* Ensure the lock is correctly set */
168 if (request.l_type != F_UNLCK)
169 TOTAL_RESULT_OK[n] += l;
170 else
171 TOTAL_RESULT_OK[n] += u;
172 }
173 }
174
initTest(void)175 int initTest(void)
176 {
177
178 P("Master opens %s\n", dp.fname);
179 dp.fd = open(dp.fname, OPENFLAGS, MANDMODES);
180 if (dp.fd < 0) {
181 perror("lock test : can't open test file :");
182 finish(1);
183 }
184 P("fd=%d\n", dp.fd);
185 return 0;
186 }
187
initClientFork(int i)188 struct dataChild *initClientFork(int i)
189 {
190 struct dataPriv *dpr;
191 struct dataChild *df;
192
193 /* Initialize private data fields */
194 dpr = malloc(sizeof(struct dataPriv));
195 df = malloc(sizeof(struct dataChild));
196 dpr->whoami = i;
197 df->dp = &dp;
198 df->dpr = dpr;
199 /* Initialize master to client pipe */
200 dp.lclnt[i] = malloc(sizeof(int) * 2);
201 if (pipe(dp.lclnt[i]) < 0) {
202 perror("Impossible to create pipe\n");
203 exit(1);
204 }
205 P("Initialization %d\n", i);
206 write(0, ".", 1);
207 return df;
208 }
209
initialize(int clnt)210 int initialize(int clnt)
211 {
212
213 /* Initialize private data fields */
214 printf("Init\n");
215 dp.nclnt = clnt;
216 dp.lclnt = malloc(sizeof(int *) * clnt);
217 dp.lthreads = malloc(sizeof(pthread_t) * clnt);
218
219 /* Initialize client to master pipe */
220 if (pipe(dp.master) < 0) {
221 perror("Master pipe creation error\n");
222 exit(1);
223 }
224 printf("%s initialization\n", eType);
225 load();
226 initTest();
227
228 return 0;
229 }
230
cleanClient(struct dataChild * df)231 void cleanClient(struct dataChild *df)
232 {
233 int i;
234 i = df->dpr->whoami;
235 free(dp.lclnt[i]);
236 free(df->dpr);
237 free(df);
238 }
239
clean(void)240 void clean(void)
241 {
242 free(dp.lthreads);
243 free(dp.lclnt);
244 }
245
loadProcess(void)246 int loadProcess(void)
247 {
248 int i;
249 struct dataChild *df;
250 for (i = 0; i < dp.nclnt; i++) {
251 df = initClientFork(i);
252 if (!fork()) {
253 P("Running slave num: %d\n", df->dpr->whoami);
254 write(0, ".", 1);
255 slave((void *)df);
256 cleanClient(df);
257 exit(0);
258 }
259 }
260 return 0;
261 }
262
lockWholeFile(struct flock * request)263 void lockWholeFile(struct flock *request)
264 {
265 request->l_whence = SEEK_SET;
266 request->l_start = 0;
267 /* Lock the whole file */
268 request->l_len = 0;
269 }
270
selectTest(int n,struct s_test * test)271 void selectTest(int n, struct s_test *test)
272 {
273
274 test->test = testSuiv(n);
275 test->resAtt = resAttSuiv(n);
276 test->nom = nomTestSuiv(n);
277 test->type = lockSuiv(n);
278 }
279
280 /* Final test report */
report(int clnt)281 int report(int clnt)
282 {
283 int rc = 0;
284 int i;
285 int totalClients;
286 totalClients = clnt * (maxClients + 1);
287 printf
288 ("\n%s number : %d - Remote clients: %d local client 1 - Total client %d - Total concurent tests: %d\n",
289 eType, clnt, maxClients, maxClients + 1, totalClients);
290 printf("%s number running test successfully :\n", eType);
291 for (i = 0; i < MAXTEST; i++) {
292 if (TOTAL_RESULT_OK[i] != totalClients)
293 rc = 1;
294
295 printf("%d %s of %d successfully ran test : %s\n",
296 TOTAL_RESULT_OK[i], eType, totalClients,
297 LIST_NAMES_TESTS[i]);
298 }
299 return rc;
300 }
301
serverSendLocal(void)302 int serverSendLocal(void)
303 {
304 int i;
305 /* Synchronize slave processes */
306 /* Configure slaves for test */
307
308 for (i = 0; i < dp.nclnt; i++)
309 write(dp.lclnt[i][1], message, M_SIZE);
310 return 0;
311
312 }
313
serverSendNet(void)314 void serverSendNet(void)
315 {
316 writeToAllClients(message);
317 }
318
serverReceiveNet(void)319 int serverReceiveNet(void)
320 {
321 int i, c;
322 for (c = 0; c < maxClients; c++) {
323 for (i = 0; i < dp.nclnt; i++) {
324 serverReceiveClient(c);
325 }
326 }
327 return 0;
328 }
329
serverReceiveLocal(void)330 int serverReceiveLocal(void)
331 {
332 int i;
333 for (i = 0; i < dp.nclnt; i++)
334 read(masterReader, message, M_SIZE);
335 return 0;
336 }
337
clientReceiveLocal(void)338 int clientReceiveLocal(void)
339 {
340 read(slaveReader, message, M_SIZE);
341 return 0;
342 }
343
clientSend(void)344 int clientSend(void)
345 {
346 write(slaveWriter, message, M_SIZE);
347 return 0;
348 }
349
serverSend(void)350 int serverSend(void)
351 {
352 serverSendNet();
353 serverSendLocal();
354 return 0;
355 }
356
serverReceive(void)357 int serverReceive(void)
358 {
359 serverReceiveNet();
360 serverReceiveLocal();
361 return 0;
362 }
363
364 /* binary structure <-> ASCII functions used to ensure data will be correctly used over
365 * the network, especially when multiples clients do not use the same hardware architecture.
366 */
serializeTLock(struct s_test * tLock)367 int serializeTLock(struct s_test *tLock)
368 {
369 memset(message, 0, M_SIZE);
370 sprintf(message, "T:%d:%d:%d::", tLock->test, tLock->type,
371 tLock->resAtt);
372 return 0;
373 }
374
unSerializeTLock(struct s_test * tLock)375 void unSerializeTLock(struct s_test *tLock)
376 {
377 sscanf(message, "T:%d:%d:%d::", &(tLock->test), &(tLock->type),
378 &(tLock->resAtt));
379 memset(message, 0, M_SIZE);
380
381 }
382
serializeFLock(struct flock * request)383 void serializeFLock(struct flock *request)
384 {
385 int len, pid, start;
386 memset(message, 0, M_SIZE);
387 len = (int)request->l_len;
388 pid = (int)request->l_pid;
389 start = (int)request->l_start;
390 /* Beware to length of integer conversions ... */
391 sprintf(message, "L:%hd:%hd:%d:%d:%d::",
392 request->l_type, request->l_whence, start, len, pid);
393 }
394
serializeResult(int result)395 void serializeResult(int result)
396 {
397 memset(message, 0, M_SIZE);
398 sprintf(message, "R:%d::", result);
399
400 }
401
unSerializeResult(int * result)402 void unSerializeResult(int *result)
403 {
404 sscanf(message, "R:%d::", result);
405 }
406
unSerializeFLock(struct flock * request)407 void unSerializeFLock(struct flock *request)
408 {
409 int len, pid, start;
410 sscanf(message, "L:%hd:%hd:%d:%d:%d::",
411 &(request->l_type), &(request->l_whence), &start, &len, &pid);
412 request->l_start = (off_t) start;
413 request->l_len = (off_t) len;
414 request->l_pid = (pid_t) pid;
415 }
416
serverSendLockClient(struct flock * request,int client)417 int serverSendLockClient(struct flock *request, int client)
418 {
419 serializeFLock(request);
420 return serverSendClient(client);
421 }
422
serverSendLockLocal(struct flock * request,int slave)423 int serverSendLockLocal(struct flock *request, int slave)
424 {
425 serializeFLock(request);
426 return write(dp.lclnt[slave][1], message, M_SIZE);
427 }
428
getLockSection(struct flock * request)429 int getLockSection(struct flock *request)
430 {
431 memset(message, 0, M_SIZE);
432 clientReceiveLocal();
433 unSerializeFLock(request);
434 return 0;
435 }
436
sendLockTest(struct s_test * tLock)437 int sendLockTest(struct s_test *tLock)
438 {
439 serializeTLock(tLock);
440 serverSend();
441 return 0;
442 }
443
getLockTest(struct s_test * tLock)444 int getLockTest(struct s_test *tLock)
445 {
446 clientReceiveLocal();
447 unSerializeTLock(tLock);
448 return 0;
449 }
450
sendResult(int result)451 int sendResult(int result)
452 {
453 serializeResult(result);
454 clientSend();
455 return 0;
456 }
457
getResults(int ntest)458 int getResults(int ntest)
459 {
460 int i, c;
461 int result = 0;
462 /* Add remote test results */
463 for (c = 0; c < maxClients; c++) {
464 for (i = 0; i < dp.nclnt; i++) {
465 serverReceiveClient(c);
466 unSerializeResult(&result);
467 counter(result, ntest);
468
469 }
470 }
471 /* Add local test results */
472 for (i = 0; i < dp.nclnt; i++) {
473 read(masterReader, message, M_SIZE);
474 unSerializeResult(&result);
475 counter(result, ntest);
476 }
477
478 return 0;
479 }
480
481 #ifdef DEBUG
482 #define P(a,b) memset(dbg,0,16);sprintf(dbg,a,b);write(0,dbg,16);
483 #endif
484
485 /* In the case of a network use, the master of the client application si only
486 * a 'repeater' of information. It resends server-master instructions to its own slaves.
487 */
masterClient(void)488 void masterClient(void)
489 {
490 fd_set fdread;
491 struct timeval tv;
492 int n, i, r, m, start;
493 #ifdef DEBUG
494 char dbg[16];
495 #endif
496 struct flock lock;
497 int t;
498
499 masterReader = dp.master[0];
500 FD_ZERO(&fdread);
501 tv.tv_sec = 50;
502 tv.tv_usec = 0;
503 n = fdServer > masterReader ? fdServer : masterReader;
504 printf("Master Client - fdServer=%d\n", fdServer);
505 while (1) {
506 /* Add slave and server pipe file descriptors */
507 FD_ZERO(&fdread);
508 FD_SET(fdServer, &fdread);
509 FD_SET(masterReader, &fdread);
510 r = select(n + 1, &fdread, NULL, NULL, &tv);
511 if (r < 0) {
512 perror("select:\n");
513 continue;
514 }
515 if (r == 0) {
516 exit(0);
517 }
518
519 if (FD_ISSET(fdServer, &fdread)) {
520 /* We just have received information from the server.
521 * We repeat it to slaves.
522 */
523 i = readFromServer(message);
524 t = message[0];
525 switch (t) {
526 case 'L':
527 /* Lock instruction. We need to send a different section to lock to each process */
528 unSerializeFLock(&lock);
529 start = lock.l_start;
530 for (i = 0; i < dp.nclnt; i++) {
531 lock.l_start = start + i;
532 serializeFLock(&lock);
533 write(dp.lclnt[i][1], message, M_SIZE);
534 }
535 printf("\n");
536 continue;
537 case 'T':
538 /* Test instruction. Ensure server is not sending the END(ish) instruction to end tests */
539 /* To be rewritten asap */
540 m = atoi(&(message[2]));
541 if (m == END)
542 break;
543 if (m == CLEAN)
544 printf("\n");
545
546 serverSendLocal();
547 continue;
548 }
549 break;
550 } else {
551 /* Else, we read information from slaves and repeat them to the server */
552 for (i = 0; i < dp.nclnt; i++) {
553 r = read(masterReader, message, M_SIZE);
554 r = write(fdServer, message, M_SIZE);
555 if (r < 0)
556 perror("write : ");
557
558 }
559 continue;
560 }
561 }
562
563 /* Receive the END(ish) instruction */
564
565 /* Repeat it to the slaves */
566 printf("Exitting...\n");
567 serverSendLocal();
568
569 /* Ok, we can quit */
570 printf("Bye :)\n");
571
572 }
573
master(void)574 int master(void)
575 {
576 int i, n, bl;
577 int clnt;
578 char tmp[MAXLEN], *buf;
579 #ifdef DEBUG
580 char dbg[16];
581 #endif
582 struct flock request;
583 struct s_test tLock;
584 enum state_t state;
585 int offset;
586 /* A test sentence written in the file */
587 char phraseTest[] =
588 "Ceci est une phrase test ecrite par le maitre dans le fichier";
589 bl = -1;
590 clnt = dp.nclnt;
591 masterReader = dp.master[0];
592 state = SELECT;
593 /* Start with the first test ;) */
594 n = 0;
595 printf("\n--------------------------------------\n");
596 while (1) {
597 switch (state) {
598 case SELECT:
599 /* Select the test to perform */
600 printf("\n");
601 E("Master: SELECT");
602 selectTest(n, &tLock);
603 state = tLock.type;
604 bl = 0;
605 if (n < MAXTEST) {
606 memset(tmp, 0, MAXLEN);
607 sprintf(tmp, "TEST : TRY TO %s:",
608 LIST_NAMES_TESTS[n]);
609 write(0, tmp, strlen(tmp));
610 } else
611 state = END;
612 P("state=%d\n", state);
613 n += 1;
614 continue;
615
616 case RDONLY:
617 case WRONLY:
618
619 case READLOCK:
620 P("Read lock :%d\n", state);
621 request.l_type = F_RDLCK;
622 state = LOCK;
623 continue;
624
625 case WRITELOCK:
626 P("Write lock :%d\n", state);
627 request.l_type = F_WRLCK;
628 state = LOCK;
629 continue;
630
631 case LOCK:
632 /* Apply the wanted lock */
633 E("Master: LOCK");
634 write(dp.fd, phraseTest, strlen(phraseTest));
635 lockWholeFile(&request);
636 if (fcntl(dp.fd, F_SETLK, &request) < 0) {
637 perror("Master: can't set lock\n");
638 perror("Echec\n");
639 exit(0);
640 }
641 E("Master");
642 state = SYNC;
643 continue;
644
645 case BYTELOCK_READ:
646 bl = 1;
647 request.l_type = F_RDLCK;
648 state = SYNC;
649 continue;
650
651 case BYTELOCK_WRITE:
652 bl = 1;
653 request.l_type = F_WRLCK;
654 state = SYNC;
655 continue;
656
657 case BYTELOCK:
658 /* The main idea is to lock all the bytes in a file. Each slave process locks one byte.
659 *
660 * We need :
661 * - To create a file of a length equal to the total number of slave processes
662 * - send the exact section to lock to each slave
663 * - ensure locks have been correctly set
664 */
665
666 /* Create a string to record in the test file. Length is exactly the number of sub process */
667 P("Master: BYTELOCK: %d\n", state);
668 buf = malloc(clnt * (maxClients + 1));
669 memset(buf, '*', clnt);
670 write(dp.fd, buf, clnt);
671 free(buf);
672
673 /* Each slave process re-writes its own field to lock */
674 request.l_whence = SEEK_SET;
675 request.l_start = 0;
676 request.l_len = 1;
677
678 /* Start to send sections to lock to remote process (network clients) */
679 for (i = 0; i < maxClients; i++) {
680 /* Set the correct byte to lock */
681 offset = (i + 1) * clnt;
682 request.l_start = (off_t) offset;
683 serverSendLockClient(&request, i);
684 }
685
686 /* Now send sections to local processes */
687 for (i = 0; i < clnt; i++) {
688 request.l_start = i;
689 serverSendLockLocal(&request, i);
690 }
691 state = RESULT;
692 continue;
693
694 case SYNC:
695 sendLockTest(&tLock);
696 if (bl) {
697 state = BYTELOCK;
698 continue;
699 }
700
701 if (n < MAXTEST + 1)
702 state = RESULT;
703 else
704 state = END;
705 continue;
706
707 case RESULT:
708 /* Read results by one */
709 getResults(n - 1);
710 if (bl)
711 validationResults(n - 1);
712 state = CLEAN;
713 continue;
714
715 case CLEAN:
716 /* Ask the clients to stop testing ... */
717 tLock.test = CLEAN;
718 serializeTLock(&tLock);
719 serverSend();
720 /* ... and wait for an ack before closing */
721 serverReceive();
722 /* Ignore message content : that is only an ack */
723
724 /* close and open file */
725 close(dp.fd);
726 initTest();
727 state = SELECT;
728 continue;
729 case END:
730 tLock.test = END;
731 serializeTLock(&tLock);
732 serverSend();
733 sleep(2);
734 break;
735
736 printf("(end)\n");
737 exit(0);
738
739 }
740 break;
741 }
742
743 return report(clnt);
744 }
745
746 /* Slave process/thread */
747
slave(void * data)748 void *slave(void *data)
749 {
750 struct dataChild *df;
751 int i, a, result, ftest;
752 struct s_test tLock;
753 struct flock request;
754 char tmp[16];
755 #ifdef DEBUG
756 char dbg[16];
757 #endif
758 char *phraseTest = "L'ecriture a reussi";
759 int len;
760 enum state_t state;
761
762 result = -1;
763 ftest = -1;
764 len = strlen(phraseTest);
765 df = (struct dataChild *)data;
766 i = df->dpr->whoami;
767 P("Slave n=%d\n", i);
768 slaveReader = dp.lclnt[i][0];
769 slaveWriter = dp.master[1];
770 state = SYNC;
771 errno = 0;
772 memset(tmp, 0, 16);
773 while (1) {
774 switch (state) {
775 case SELECT:
776 case SYNC:
777 getLockTest(&tLock);
778 state = tLock.test;
779 P("Slave State=%d\n", state);
780
781 continue;
782 case RDONLY:
783 /* Try to read a file */
784 P("TEST READ ONLY %d\n", RDONLY);
785 if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
786 result = ECHEC;
787 state = RESULT;
788 if (dp.verbose)
789 perror("Open:");
790 continue;
791 }
792 P("fd=%d\n", ftest);
793 a = read(ftest, tmp, 16);
794 if (a < 16)
795 result = ECHEC;
796 else
797 result = SUCCES;
798 state = RESULT;
799 continue;
800
801 case WRONLY:
802 /* Try to write a file */
803 P("TEST WRITE ONLY %d\n", WRONLY);
804 if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
805 result = ECHEC;
806 state = RESULT;
807 if (dp.verbose)
808 perror("Open read only:");
809 continue;
810 }
811 P("fd=%d\n", ftest);
812 if (write(ftest, phraseTest, len) < len)
813 result = ECHEC;
814 else
815 result = SUCCES;
816 state = RESULT;
817 continue;
818
819 case LOCK:
820
821 case READLOCK:
822 /* Try to read a read-locked section */
823 P("READ LOCK %d\n", F_RDLCK);
824 if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
825 result = ECHEC;
826 state = RESULT;
827 if (dp.verbose)
828 perror("Open read-write:");
829 continue;
830 }
831
832 P("fd=%d\n", ftest);
833 /* Lock the whole file */
834 request.l_type = F_RDLCK;
835 request.l_whence = SEEK_SET;
836 request.l_start = 0;
837 request.l_len = 0;
838
839 if (fcntl(ftest, F_SETLK, &request) < 0) {
840 if (dp.verbose || errno != EAGAIN)
841 perror("RDONLY: fcntl");
842 result = ECHEC;
843 } else
844 result = SUCCES;
845 state = RESULT;
846 continue;
847
848 case WRITELOCK:
849 /* Try to write a file */
850 P("WRITE LOCK %d\n", F_WRLCK);
851 if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
852 result = ECHEC;
853 state = RESULT;
854 if (dp.verbose)
855 perror("\nOpen:");
856 continue;
857 }
858 /* Lock the whole file */
859 P("fd=%d\n", ftest);
860 request.l_type = F_WRLCK;
861 request.l_whence = SEEK_SET;
862 request.l_start = 0;
863 request.l_len = 0;
864
865 if (fcntl(ftest, F_SETLK, &request) < 0) {
866 if (dp.verbose || errno != EAGAIN)
867 perror("\nWRONLY: fcntl");
868 result = ECHEC;
869 } else
870 result = SUCCES;
871 state = RESULT;
872 continue;
873
874 case BYTELOCK_READ:
875 P("BYTE LOCK READ: %d\n", state);
876 state = BYTELOCK;
877 continue;
878
879 case BYTELOCK_WRITE:
880 P("BYTE LOCK WRITE: %d\n", state);
881 state = BYTELOCK;
882 continue;
883
884 case BYTELOCK:
885 /* Wait for the exact section to lock. The whole file is sent by the master */
886 P("BYTE LOCK %d\n", state);
887 getLockSection(&request);
888 if ((ftest = open(dp.fname, O_RDWR | O_NONBLOCK)) < 0) {
889 result = ECHEC;
890 state = RESULT;
891 if (dp.verbose)
892 perror("\nOpen:");
893 continue;
894 }
895
896 if (fcntl(ftest, F_SETLK, &request) < 0) {
897 if (dp.verbose || errno != EAGAIN)
898 perror("\nBTLOCK: fcntl");
899 result = ECHEC;
900 state = RESULT;
901 continue;
902 }
903 /* Change the character at the given position for an easier verification */
904 a = lseek(ftest, request.l_start, SEEK_SET);
905 write(ftest, "=", 1);
906 result = SUCCES;
907 state = RESULT;
908 continue;
909
910 case RESULT:
911 if (result == SUCCES)
912 write(0, "=", 1);
913 else
914 write(0, "x", 1);
915 P("RESULT: %d\n", result);
916 sendResult(result);
917 state = SYNC;
918 continue;
919
920 case CLEAN:
921 close(ftest);
922 /* Send CLEAN Ack */
923 sendResult(result);
924 state = SYNC;
925 continue;
926
927 case END:
928 E("(End)\n");
929 finish(0);
930 printf("Unknown command\n");
931 finish(1);
932
933 }
934 }
935
936 }
937
nextArg(int argc,char ** argv,int * i)938 char *nextArg(int argc, char **argv, int *i)
939 {
940 if (((*i) + 1) < argc) {
941 (*i) += 1;
942 return argv[(*i)];
943 }
944 return NULL;
945 }
946
usage(void)947 int usage(void)
948 {
949 printf("locktest -n <number of process> -f <test file> [-T]\n");
950 printf("Number of child process must be higher than 1\n");
951 exit(0);
952 return 0;
953 }
954
main(int argc,char ** argv)955 int main(int argc, char **argv)
956 {
957 int rc = 0;
958 int i, nThread = 0;
959 char *tmp;
960 int type = 0;
961 int clients;
962 type = PROCESS;
963 dp.fname = NULL;
964 dp.verbose = 0;
965 int server = 1;
966 char *host;
967
968 host = NULL;
969 clients = 0;
970
971 for (i = 1; i < argc; i++) {
972
973 if (!strcmp("-n", argv[i])) {
974 if (!(tmp = nextArg(argc, argv, &i)))
975 usage();
976 nThread = atoi(tmp);
977 continue;
978 }
979
980 if (!strcmp("-f", argv[i])) {
981 if (!(dp.fname = nextArg(argc, argv, &i)))
982 usage();
983 continue;
984 }
985 if (!strcmp("-v", argv[i])) {
986 dp.verbose = TRUE;
987 continue;
988 }
989 if (!strcmp("-c", argv[i])) {
990 if (!(clients = atoi(nextArg(argc, argv, &i))))
991 usage();
992 continue;
993 }
994
995 if (!strcmp("--server", argv[i])) {
996 if (!(host = nextArg(argc, argv, &i)))
997 usage();
998 server = 0;
999 continue;
1000 }
1001 printf("Ignoring unknown option: %s\n", argv[i]);
1002 }
1003
1004 if (server) {
1005 if (!(dp.fname && nThread))
1006 usage();
1007 if (clients > 0) {
1008 configureServer(clients);
1009 setupClients(type, dp.fname, nThread);
1010 }
1011 } else {
1012 configureClient(host);
1013 dp.fname = malloc(512);
1014 memset(dp.fname, 0, 512);
1015 getConfiguration(&type, dp.fname, &nThread);
1016 }
1017
1018 if (dp.verbose)
1019 printf("By process.\n");
1020 load = loadProcess;
1021 eType = "process";
1022 finish = finishProcess;
1023 LIST_RESULTS = LIST_RESULTS_PROCESS;
1024 initialize(nThread);
1025 if (server) {
1026 rc = master();
1027 } else {
1028 masterClient();
1029 free(dp.fname);
1030 }
1031 clean();
1032
1033 return rc;
1034 }
1035