4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2014, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
43 #define MAX_PATH_LENGTH 4096
47 int t_fcntl(int fd, int cmd, ...)
61 fprintf(stderr, "fcntl GETFL failed: %s\n",
67 arg = va_arg(ap, long);
69 rc = fcntl(fd, cmd, arg);
72 fprintf(stderr, "fcntl SETFL %ld failed: %s\n",
73 arg, strerror(errno));
80 lock = va_arg(ap, struct flock *);
82 rc = fcntl(fd, cmd, lock);
85 fprintf(stderr, "fcntl cmd %d failed: %s\n",
86 cmd, strerror(errno));
91 arg = va_arg(ap, long);
93 rc = fcntl(fd, cmd, arg);
96 fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n",
97 (int)arg, strerror(errno));
103 fprintf(stderr, "fcntl cmd %d not supported\n", cmd);
109 int t_unlink(const char *path)
116 "unlink(%s) error: %s\n", path, strerror(errno));
120 /** =================================================================
128 "usage: flocks_test 1 {on|off} {-c|-f|-l} /path/to/file\n");
131 int t1(int argc, char *argv[])
134 int mount_with_flock = 0;
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;
152 fd = open(argv[4], O_RDWR);
154 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[4],
159 if (!strncmp(argv[3], "-c", 3)) {
163 fl.l_whence = SEEK_SET;
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);
178 if (mount_with_flock)
179 rc = ((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
181 rc = ((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS);
189 /** ===============================================================
192 * 2 threads flock ops interweave
200 void *t2_thread1(void *arg)
202 struct thread_info *ti = arg;
203 struct flock *lock = ti->lock;
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);
217 fprintf(stdout, "thread1 exiting with rc = %d\n", ti->rc);
221 void *t2_thread2(void *arg)
223 struct thread_info *ti = arg;
224 struct flock *lock = ti->lock;
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 */
239 fprintf(stdout, "thread2 exiting with rc = %d\n", ti->rc);
243 int t2(int argc, char *argv[])
245 struct flock lock = {
247 .l_whence = SEEK_SET,
249 char file[MAX_PATH_LENGTH] = "";
252 struct thread_info ti;
254 snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
256 fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
258 fprintf(stderr, "error open file '%s': %s\n", file,
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);
274 rc = pthread_create(&th1, NULL, t2_thread1, &ti);
276 fprintf(stderr, "error create thread 1\n");
280 rc = pthread_create(&th2, NULL, t2_thread2, &ti);
282 fprintf(stderr, "error create thread 2\n");
286 pthread_join(th1, NULL);
287 pthread_join(th2, NULL);
297 /** =================================================================
300 * Bug 24040: Two conflicting flocks from same process different fds should fail
301 * two conflicting flocks from different processes but same fs
304 int t3(int argc, char *argv[])
308 int rc = EXIT_SUCCESS;
311 fprintf(stderr, "usage: flocks_test 3 filename\n");
315 fd = open(argv[2], O_RDWR);
317 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
321 if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
322 perror("first flock failed");
326 fd2 = open(argv[2], O_RDWR);
328 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
333 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
334 fprintf(stderr, "Second flock succeeded - FAIL\n");
350 fd2 = open(argv[2], O_RDWR);
352 fprintf(stderr, "Couldn't open file '%s': %s\n",
353 argv[1], strerror(errno));
357 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
358 fprintf(stderr, "Second flock succeeded - FAIL\n");
362 if (flock(fd, LOCK_UN) == -1) {
363 fprintf(stderr, "Child unlock on parent fd failed\n");
367 if (flock(fd2, LOCK_EX | LOCK_NB) == -1) {
368 fprintf(stderr, "Relock after parent unlock failed!\n");
377 waitpid(pid, &rc, 0);
383 int t4(int argc, char *argv[])
385 struct flock lock = {
387 .l_whence = SEEK_SET,
395 int rc = EXIT_SUCCESS;
398 fprintf(stderr, "usage: flocks_test 4 file1 file2\n");
402 fd = open(argv[2], O_RDWR);
404 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
407 fd2 = open(argv[3], O_RDWR);
409 fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
421 if (child_pid == 0) {
422 printf("%d: get lock1\n", getpid());
424 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
425 fprintf(stderr, "%d: cannot get lock1: %s\n",
426 getpid(), strerror(errno));
430 printf("%d: done\n", getpid());
432 printf("%d: get lock2\n", getpid());
434 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
435 fprintf(stderr, "%d: cannot get lock2: %s\n",
436 getpid(), strerror(errno));
438 if (errno == EDEADLK)
445 printf("%d: done\n", getpid());
447 printf("%d: exit rc=%d\n", getpid(), rc);
450 printf("%d: get lock2\n", getpid());
452 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
453 fprintf(stderr, "%d: cannot get lock2: %s\n",
454 getpid(), strerror(errno));
458 printf("%d: done\n", getpid());
460 printf("%d: get lock1\n", getpid());
462 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
463 fprintf(stderr, "%d: cannot get lock1: %s\n",
464 getpid(), strerror(errno));
466 if (errno != EDEADLK) {
471 printf("%d: done\n", getpid());
477 fprintf(stderr, "%d: error closing file1: %s\n",
478 getpid(), strerror(errno));
482 if (close(fd2) < 0) {
483 fprintf(stderr, "%d: error closing file2: %s\n",
484 getpid(), strerror(errno));
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));
492 } else if (!WIFEXITED(child_status)) {
493 fprintf(stderr, "%d: child %d terminated with status %d\n",
494 getpid(), child_pid, child_status);
497 rc = WEXITSTATUS(child_status);
501 printf("%d: exit rc=%d\n", getpid(), rc);
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"
514 int t5(int argc, char *argv[])
516 struct flock lock = {
518 .l_whence = SEEK_SET,
521 int setlk = 0, getlk = 0, unlk = 0, secs = 0;
526 if (argc < 4 || argc > 7) {
527 fprintf(stderr, T5_USAGE);
531 if (!strncmp(argv[2], "set", 4))
533 else if (!strncmp(argv[2], "get", 4))
535 else if (!strncmp(argv[2], "unlock", 7))
538 fprintf(stderr, "Wrong 2nd argument: %s\n", argv[2]);
544 if (!strncmp(argv[pos], "read", 5)) {
545 lock.l_type = F_RDLCK;
547 } else if (!strncmp(argv[pos], "write", 6)) {
548 lock.l_type = F_WRLCK;
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",
562 fd = open(argv[pos], O_RDWR);
564 fprintf(stderr, "Couldn't open file: %s\n", argv[pos]);
568 fprintf(stderr, "\nFLOCKS_TEST 5: %s %s flock\n",
569 setlk ? "SET" : getlk ? "GET" : "UNLOCK",
570 lock.l_type == F_WRLCK ? "write" : "read");
573 rc = t_fcntl(fd, F_SETLKW, &lock);
575 rc = t_fcntl(fd, F_GETLK, &lock);
577 lock.l_type = F_UNLCK;
578 rc = t_fcntl(fd, F_SETLKW, &lock);
585 return rc < 0 ? -rc : 0;
589 /** ==============================================================
595 "usage: flocks_test test# [corresponding arguments]\n");
598 int main(int argc, char *argv[])
600 int rc = EXIT_SUCCESS;
607 switch (atoi(argv[1])) {
624 fprintf(stderr, "unknown test number '%s'\n", argv[1]);
629 fprintf(stderr, "exiting with rc = %d\n", rc);