Whamcloud - gitweb
LU-14739 quota: nodemap squashed root cannot bypass quota
[fs/lustre-release.git] / lustre / tests / flocks_test.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2014, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <pthread.h>
39 #include <sys/file.h>
40 #include <sys/wait.h>
41 #include <stdarg.h>
42
43 #define MAX_PATH_LENGTH 4096
44 /**
45  * helper functions
46  */
47 int t_fcntl(int fd, int cmd, ...)
48 {
49         va_list ap;
50         long arg;
51         struct flock *lock;
52         int rc = -1;
53
54         va_start(ap, cmd);
55         switch (cmd) {
56         case F_GETFL:
57                 va_end(ap);
58                 rc = fcntl(fd, cmd);
59                 if (rc == -1) {
60                         rc = -errno;
61                         fprintf(stderr, "fcntl GETFL failed: %s\n",
62                                 strerror(errno));
63                         return rc;
64                 }
65                 break;
66         case F_SETFL:
67                 arg = va_arg(ap, long);
68                 va_end(ap);
69                 rc = fcntl(fd, cmd, arg);
70                 if (rc == -1) {
71                         rc = -errno;
72                         fprintf(stderr, "fcntl SETFL %ld failed: %s\n",
73                                 arg, strerror(errno));
74                         return rc;
75                 }
76                 break;
77         case F_GETLK:
78         case F_SETLK:
79         case F_SETLKW:
80                 lock = va_arg(ap, struct flock *);
81                 va_end(ap);
82                 rc = fcntl(fd, cmd, lock);
83                 if (rc == -1) {
84                         rc = -errno;
85                         fprintf(stderr, "fcntl cmd %d failed: %s\n",
86                                 cmd, strerror(errno));
87                         return rc;
88                 }
89                 break;
90         case F_DUPFD:
91                 arg = va_arg(ap, long);
92                 va_end(ap);
93                 rc = fcntl(fd, cmd, arg);
94                 if (rc == -1) {
95                         rc = -errno;
96                         fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n",
97                                 (int)arg, strerror(errno));
98                         return rc;
99                 }
100                 break;
101         default:
102                 va_end(ap);
103                 fprintf(stderr, "fcntl cmd %d not supported\n", cmd);
104                 return rc;
105         }
106         return rc;
107 }
108
109 int t_unlink(const char *path)
110 {
111         int rc;
112
113         rc = unlink(path);
114         if (rc)
115                 fprintf(stderr,
116                         "unlink(%s) error: %s\n", path, strerror(errno));
117         return rc;
118 }
119
120 /** =================================================================
121  * test number 1
122  *
123  * normal flock test
124  */
125 void t1_usage(void)
126 {
127         fprintf(stderr,
128                 "usage: flocks_test 1 {on|off} {-c|-f|-l} /path/to/file\n");
129 }
130
131 int t1(int argc, char *argv[])
132 {
133         int fd;
134         int mount_with_flock = 0;
135         int error = 0;
136         int rc = 0;
137
138         if (argc != 5) {
139                 t1_usage();
140                 return EXIT_FAILURE;
141         }
142
143         if (!strncmp(argv[2], "on", 3)) {
144                 mount_with_flock = 1;
145         } else if (!strncmp(argv[2], "off", 4)) {
146                 mount_with_flock = 0;
147         } else {
148                 t1_usage();
149                 return EXIT_FAILURE;
150         }
151
152         fd = open(argv[4], O_RDWR);
153         if (fd < 0) {
154                 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[4],
155                         strerror(errno));
156                 return EXIT_FAILURE;
157         }
158
159         if (!strncmp(argv[3], "-c", 3)) {
160                 struct flock fl;
161
162                 fl.l_type = F_RDLCK;
163                 fl.l_whence = SEEK_SET;
164                 fl.l_start = 0;
165                 fl.l_len = 1;
166
167                 error = fcntl(fd, F_SETLK, &fl);
168         } else if (!strncmp(argv[3], "-l", 3)) {
169                 error = lockf(fd, F_LOCK, 1);
170         } else if (!strncmp(argv[3], "-f", 3)) {
171                 error = flock(fd, LOCK_EX);
172         } else {
173                 t1_usage();
174                 rc = EXIT_FAILURE;
175                 goto out;
176         }
177
178         if (mount_with_flock)
179                 rc = ((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
180         else
181                 rc = ((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS);
182
183 out:
184         if (fd >= 0)
185                 close(fd);
186         return rc;
187 }
188
189 /** ===============================================================
190  * test number 2
191  *
192  * 2 threads flock ops interweave
193  */
194 struct thread_info {
195         struct flock *lock;
196         int fd;
197         int rc;
198 } th_data;
199
200 void *t2_thread1(void *arg)
201 {
202         struct thread_info *ti = arg;
203         struct flock *lock = ti->lock;
204         int fd = ti->fd;
205
206         printf("thread 1: set write lock (blocking): rc = %d\n", ti->rc);
207         lock->l_type = F_WRLCK;
208         t_fcntl(fd, F_SETLKW, lock);
209         printf("thread 1: set write lock done: rc = %d\n", ti->rc);
210         (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
211         printf("thread 1: unlock: rc = %d\n", ti->rc);
212         lock->l_type = F_UNLCK;
213         ti->rc += t_fcntl(fd, F_SETLK, lock);
214         printf("thread 1: unlock done: rc = %d\n", ti->rc);
215
216         if (ti->rc)
217                 fprintf(stdout, "thread1 exiting with rc = %d\n", ti->rc);
218         return &ti->rc;
219 }
220
221 void *t2_thread2(void *arg)
222 {
223         struct thread_info *ti = arg;
224         struct flock *lock = ti->lock;
225         int fd = ti->fd;
226
227         sleep(2);
228         printf("thread 2: unlock: rc = %d\n", ti->rc);
229         lock->l_type = F_UNLCK;
230         ti->rc += t_fcntl(fd, F_SETLK, lock);
231         printf("thread 2: unlock done: rc = %d\n", ti->rc);
232         printf("thread 2: set write lock (non-blocking): rc = %d\n", ti->rc);
233         lock->l_type = F_WRLCK;
234         ti->rc += t_fcntl(fd, F_SETLK, lock);
235         printf("thread 2: set write lock done: rc = %d\n", ti->rc);
236         (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
237
238         if (ti->rc)
239                 fprintf(stdout, "thread2 exiting with rc = %d\n", ti->rc);
240         return &ti->rc;
241 }
242
243 int t2(int argc, char *argv[])
244 {
245         struct flock lock = {
246                 .l_type = F_RDLCK,
247                 .l_whence = SEEK_SET,
248         };
249         char file[MAX_PATH_LENGTH] = "";
250         int  fd, rc;
251         pthread_t th1, th2;
252         struct thread_info ti;
253
254         snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
255
256         fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
257         if (fd < 0) {
258                 fprintf(stderr, "error open file '%s': %s\n", file,
259                         strerror(errno));
260                 return EXIT_FAILURE;
261         }
262
263         t_fcntl(fd, F_SETFL, O_APPEND);
264         rc = t_fcntl(fd, F_GETFL);
265         if ((rc < 0) || (rc & O_APPEND) == 0) {
266                 fprintf(stderr, "error get flag: ret %x\n", rc);
267                 rc = EXIT_FAILURE;
268                 goto out;
269         }
270
271         ti.lock = &lock;
272         ti.fd   = fd;
273         ti.rc   = 0;
274         rc = pthread_create(&th1, NULL, t2_thread1, &ti);
275         if (rc) {
276                 fprintf(stderr, "error create thread 1\n");
277                 rc = EXIT_FAILURE;
278                 goto out;
279         }
280         rc = pthread_create(&th2, NULL, t2_thread2, &ti);
281         if (rc) {
282                 fprintf(stderr, "error create thread 2\n");
283                 rc = EXIT_FAILURE;
284                 goto out;
285         }
286         pthread_join(th1, NULL);
287         pthread_join(th2, NULL);
288         if (ti.rc)
289                 rc = EXIT_FAILURE;
290 out:
291         t_unlink(file);
292         close(fd);
293
294         return rc;
295 }
296
297 /** =================================================================
298  * test number 3
299  *
300  * Bug 24040: Two conflicting flocks from same process different fds should fail
301  *            two conflicting flocks from different processes but same fs
302  *            should succeed.
303  */
304 int t3(int argc, char *argv[])
305 {
306         int fd, fd2;
307         int pid;
308         int rc = EXIT_SUCCESS;
309
310         if (argc != 3) {
311                 fprintf(stderr, "usage: flocks_test 3 filename\n");
312                 return EXIT_FAILURE;
313         }
314
315         fd = open(argv[2], O_RDWR);
316         if (fd < 0) {
317                 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
318                         strerror(errno));
319                 return EXIT_FAILURE;
320         }
321         if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
322                 perror("first flock failed");
323                 rc = EXIT_FAILURE;
324                 goto out;
325         }
326         fd2 = open(argv[2], O_RDWR);
327         if (fd2 < 0) {
328                 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
329                         strerror(errno));
330                 rc = EXIT_FAILURE;
331                 goto out;
332         }
333         if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
334                 fprintf(stderr, "Second flock succeeded - FAIL\n");
335                 rc = EXIT_FAILURE;
336                 close(fd2);
337                 goto out;
338         }
339
340         close(fd2);
341
342         pid = fork();
343         if (pid == -1) {
344                 perror("fork");
345                 rc = EXIT_FAILURE;
346                 goto out;
347         }
348
349         if (pid == 0) {
350                 fd2 = open(argv[2], O_RDWR);
351                 if (fd2 < 0) {
352                         fprintf(stderr, "Couldn't open file '%s': %s\n",
353                                 argv[1], strerror(errno));
354                         rc = EXIT_FAILURE;
355                         goto out;
356                 }
357                 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
358                         fprintf(stderr, "Second flock succeeded - FAIL\n");
359                         rc = EXIT_FAILURE;
360                         goto out_child;
361                 }
362                 if (flock(fd, LOCK_UN) == -1) {
363                         fprintf(stderr, "Child unlock on parent fd failed\n");
364                         rc = EXIT_FAILURE;
365                         goto out_child;
366                 }
367                 if (flock(fd2, LOCK_EX | LOCK_NB) == -1) {
368                         fprintf(stderr, "Relock after parent unlock failed!\n");
369                         rc = EXIT_FAILURE;
370                         goto out_child;
371                 }
372         out_child:
373                 close(fd2);
374                 exit(rc);
375         }
376
377         waitpid(pid, &rc, 0);
378 out:
379         close(fd);
380         return rc;
381 }
382
383 int t4(int argc, char *argv[])
384 {
385         struct flock lock = {
386                 .l_type = F_WRLCK,
387                 .l_whence = SEEK_SET,
388                 .l_start = 0,
389                 .l_len = 10,
390         };
391
392         int fd, fd2;
393         pid_t child_pid;
394         int child_status;
395         int rc = EXIT_SUCCESS;
396
397         if (argc != 4) {
398                 fprintf(stderr, "usage: flocks_test 4 file1 file2\n");
399                 return EXIT_FAILURE;
400         }
401
402         fd = open(argv[2], O_RDWR);
403         if (fd < 0) {
404                 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
405                 return EXIT_FAILURE;
406         }
407         fd2 = open(argv[3], O_RDWR);
408         if (fd2 < 0) {
409                 fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
410                 rc = EXIT_FAILURE;
411                 goto out;
412         }
413
414         child_pid = fork();
415         if (child_pid < 0) {
416                 perror("fork");
417                 rc = EXIT_FAILURE;
418                 goto out;
419         }
420
421         if (child_pid == 0) {
422                 printf("%d: get lock1\n", getpid());
423                 fflush(stdout);
424                 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
425                         fprintf(stderr, "%d: cannot get lock1: %s\n",
426                                 getpid(), strerror(errno));
427                         rc = EXIT_FAILURE;
428                         goto out_child;
429                 }
430                 printf("%d: done\n", getpid());
431                 sleep(3);
432                 printf("%d: get lock2\n", getpid());
433                 fflush(stdout);
434                 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
435                         fprintf(stderr, "%d: cannot get lock2: %s\n",
436                                 getpid(), strerror(errno));
437
438                         if (errno == EDEADLK)
439                                 rc = EXIT_SUCCESS;
440                         else
441                                 rc = EXIT_FAILURE;
442
443                         goto out_child;
444                 }
445                 printf("%d: done\n", getpid());
446 out_child:
447                 printf("%d: exit rc=%d\n", getpid(), rc);
448                 exit(rc);
449         } else {
450                 printf("%d: get lock2\n", getpid());
451                 fflush(stdout);
452                 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
453                         fprintf(stderr, "%d: cannot get lock2: %s\n",
454                                 getpid(), strerror(errno));
455                         rc = EXIT_FAILURE;
456                         goto out;
457                 }
458                 printf("%d: done\n", getpid());
459                 sleep(3);
460                 printf("%d: get lock1\n", getpid());
461                 fflush(stdout);
462                 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
463                         fprintf(stderr, "%d: cannot get lock1: %s\n",
464                                 getpid(), strerror(errno));
465
466                         if (errno != EDEADLK) {
467                                 rc = EXIT_FAILURE;
468                                 goto out;
469                         }
470                 }
471                 printf("%d: done\n", getpid());
472         }
473
474         sleep(1);
475
476         if (close(fd) < 0) {
477                 fprintf(stderr, "%d: error closing file1: %s\n",
478                         getpid(), strerror(errno));
479                 rc = EXIT_FAILURE;
480         }
481
482         if (close(fd2) < 0) {
483                 fprintf(stderr, "%d: error closing file2: %s\n",
484                         getpid(), strerror(errno));
485                 rc = EXIT_FAILURE;
486         }
487
488         if (waitpid(child_pid, &child_status, 0) < 0) {
489                 fprintf(stderr, "%d: cannot get termination status of %d: %s\n",
490                         getpid(), child_pid, strerror(errno));
491                 rc = EXIT_FAILURE;
492         } else if (!WIFEXITED(child_status)) {
493                 fprintf(stderr, "%d: child %d terminated with status %d\n",
494                         getpid(), child_pid, child_status);
495                 rc = EXIT_FAILURE;
496         } else {
497                 rc = WEXITSTATUS(child_status);
498         }
499
500 out:
501         printf("%d: exit rc=%d\n", getpid(), rc);
502         return rc;
503 }
504
505 #define T5_USAGE                                                              \
506 "usage: flocks_test 5 {set|get|unlock} [read|write] [sleep N] file1\n"        \
507 "       set: F_SETLKW F_WRLCK\n"                                              \
508 "       get: F_GETLK F_WRLCK  (conflict)\n"                                   \
509 "       unlock: F_SETLKW F_UNLCK\n"                                           \
510 "       read|write: lock mode, write by default\n"                            \
511 "       sleep N: sleep for N secs after fcntl\n"                              \
512 "       file1: fcntl is called for this file\n"
513
514 int t5(int argc, char *argv[])
515 {
516         struct flock lock = {
517                 .l_type = F_WRLCK,
518                 .l_whence = SEEK_SET,
519         };
520
521         int setlk = 0, getlk = 0, unlk = 0, secs = 0;
522         int pos;
523         int fd;
524         int rc = 0;
525
526         if (argc < 4 || argc > 7) {
527                 fprintf(stderr, T5_USAGE);
528                 return EXIT_FAILURE;
529         }
530
531         if (!strncmp(argv[2], "set", 4))
532                 setlk = 1;
533         else if (!strncmp(argv[2], "get", 4))
534                 getlk = 1;
535         else if (!strncmp(argv[2], "unlock", 7))
536                 unlk = 1;
537         else {
538                 fprintf(stderr, "Wrong 2nd argument: %s\n", argv[2]);
539                 return EXIT_FAILURE;
540         }
541
542         pos = 3;
543
544         if (!strncmp(argv[pos], "read", 5)) {
545                 lock.l_type = F_RDLCK;
546                 pos++;
547         } else if (!strncmp(argv[pos], "write", 6)) {
548                 lock.l_type = F_WRLCK;
549                 pos++;
550         }
551
552         if (!strncmp(argv[pos], "sleep", 6)) {
553                 secs = atoi(argv[pos + 1]);
554                 if (secs < 0 || secs > 10) {
555                         fprintf(stderr, "Sleep argument is wrong: %s\n",
556                                 argv[pos + 1]);
557                         return EXIT_FAILURE;
558                 }
559                 pos += 2;
560         }
561
562         fd = open(argv[pos], O_RDWR);
563         if (fd < 0) {
564                 fprintf(stderr, "Couldn't open file: %s\n", argv[pos]);
565                 return EXIT_FAILURE;
566         }
567
568         fprintf(stderr, "\nFLOCKS_TEST 5: %s %s flock\n",
569                 setlk ? "SET" : getlk ? "GET" : "UNLOCK",
570                 lock.l_type == F_WRLCK ? "write" : "read");
571
572         if (setlk) {
573                 rc = t_fcntl(fd, F_SETLKW, &lock);
574         } else if (getlk) {
575                 rc = t_fcntl(fd, F_GETLK, &lock);
576         } else if (unlk) {
577                 lock.l_type = F_UNLCK;
578                 rc = t_fcntl(fd, F_SETLKW, &lock);
579         }
580
581         if (secs)
582                 sleep(secs);
583
584         close(fd);
585         return rc < 0 ? -rc : 0;
586
587 }
588
589 /** ==============================================================
590  * program entry
591  */
592 void usage(void)
593 {
594         fprintf(stderr,
595                 "usage: flocks_test test# [corresponding arguments]\n");
596 }
597
598 int main(int argc, char *argv[])
599 {
600         int rc = EXIT_SUCCESS;
601
602         if (argc < 2) {
603                 usage();
604                 exit(EXIT_FAILURE);
605         }
606
607         switch (atoi(argv[1])) {
608         case 1:
609                 rc = t1(argc, argv);
610                 break;
611         case 2:
612                 rc = t2(argc, argv);
613                 break;
614         case 3:
615                 rc = t3(argc, argv);
616                 break;
617         case 4:
618                 rc = t4(argc, argv);
619                 break;
620         case 5:
621                 rc = t5(argc, argv);
622                 break;
623         default:
624                 fprintf(stderr, "unknown test number '%s'\n", argv[1]);
625                 break;
626         }
627
628         if (rc)
629                 fprintf(stderr, "exiting with rc = %d\n", rc);
630         return rc;
631 }