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/
45 #define MAX_PATH_LENGTH 4096
48 static double now(void)
52 gettimeofday(&tv, NULL);
53 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
56 /* helper functions */
57 static int t_fcntl(int fd, int cmd, ...)
71 fprintf(stderr, "fcntl GETFL failed: %s\n",
77 arg = va_arg(ap, long);
79 rc = fcntl(fd, cmd, arg);
82 fprintf(stderr, "fcntl SETFL %ld failed: %s\n",
83 arg, strerror(errno));
90 lock = va_arg(ap, struct flock *);
92 rc = fcntl(fd, cmd, lock);
95 fprintf(stderr, "fcntl cmd %d failed: %s\n",
96 cmd, strerror(errno));
101 arg = va_arg(ap, long);
103 rc = fcntl(fd, cmd, arg);
106 fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n",
107 (int)arg, strerror(errno));
113 fprintf(stderr, "fcntl cmd %d not supported\n", cmd);
119 static int t_unlink(const char *path)
126 "unlink(%s) error: %s\n", path, strerror(errno));
134 static void t1_usage(void)
137 "usage: flocks_test 1 {on|off} {-c|-f|-l} /path/to/file\n");
140 static int t1(int argc, char *argv[])
143 int mount_with_flock = 0;
152 if (!strncmp(argv[2], "on", 3)) {
153 mount_with_flock = 1;
154 } else if (!strncmp(argv[2], "off", 4)) {
155 mount_with_flock = 0;
161 fd = open(argv[4], O_RDWR);
163 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[4],
168 if (!strncmp(argv[3], "-c", 3)) {
172 fl.l_whence = SEEK_SET;
176 error = fcntl(fd, F_SETLK, &fl);
177 } else if (!strncmp(argv[3], "-l", 3)) {
178 error = lockf(fd, F_LOCK, 1);
179 } else if (!strncmp(argv[3], "-f", 3)) {
180 error = flock(fd, LOCK_EX);
187 if (mount_with_flock)
188 rc = ((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
190 rc = ((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS);
200 * 2 threads flock ops interweave
208 static void *t2_thread1(void *arg)
210 struct thread_info *ti = arg;
211 struct flock *lock = ti->lock;
214 printf("thread 1: set write lock (blocking): rc = %d\n", ti->rc);
215 lock->l_type = F_WRLCK;
216 t_fcntl(fd, F_SETLKW, lock);
217 printf("thread 1: set write lock done: rc = %d\n", ti->rc);
218 (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
219 printf("thread 1: unlock: rc = %d\n", ti->rc);
220 lock->l_type = F_UNLCK;
221 ti->rc += t_fcntl(fd, F_SETLK, lock);
222 printf("thread 1: unlock done: rc = %d\n", ti->rc);
225 fprintf(stdout, "thread1 exiting with rc = %d\n", ti->rc);
229 static void *t2_thread2(void *arg)
231 struct thread_info *ti = arg;
232 struct flock *lock = ti->lock;
236 printf("thread 2: unlock: rc = %d\n", ti->rc);
237 lock->l_type = F_UNLCK;
238 ti->rc += t_fcntl(fd, F_SETLK, lock);
239 printf("thread 2: unlock done: rc = %d\n", ti->rc);
240 printf("thread 2: set write lock (non-blocking): rc = %d\n", ti->rc);
241 lock->l_type = F_WRLCK;
242 ti->rc += t_fcntl(fd, F_SETLK, lock);
243 printf("thread 2: set write lock done: rc = %d\n", ti->rc);
244 (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
247 fprintf(stdout, "thread2 exiting with rc = %d\n", ti->rc);
251 static int t2(int argc, char *argv[])
253 struct flock lock = {
255 .l_whence = SEEK_SET,
257 char file[MAX_PATH_LENGTH] = "";
260 struct thread_info ti;
262 snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
264 fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
266 fprintf(stderr, "error open file '%s': %s\n", file,
271 t_fcntl(fd, F_SETFL, O_APPEND);
272 rc = t_fcntl(fd, F_GETFL);
273 if ((rc < 0) || (rc & O_APPEND) == 0) {
274 fprintf(stderr, "error get flag: ret %x\n", rc);
282 rc = pthread_create(&th1, NULL, t2_thread1, &ti);
284 fprintf(stderr, "error create thread 1\n");
288 rc = pthread_create(&th2, NULL, t2_thread2, &ti);
290 fprintf(stderr, "error create thread 2\n");
294 pthread_join(th1, NULL);
295 pthread_join(th2, NULL);
308 * Bug 24040: Two conflicting flocks from same process different fds should fail
309 * two conflicting flocks from different processes but same fs
312 static int t3(int argc, char *argv[])
316 int rc = EXIT_SUCCESS;
319 fprintf(stderr, "usage: flocks_test 3 filename\n");
323 fd = open(argv[2], O_RDWR);
325 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
329 if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
330 perror("first flock failed");
334 fd2 = open(argv[2], O_RDWR);
336 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
341 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
342 fprintf(stderr, "Second flock succeeded - FAIL\n");
358 fd2 = open(argv[2], O_RDWR);
360 fprintf(stderr, "Couldn't open file '%s': %s\n",
361 argv[1], strerror(errno));
365 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
366 fprintf(stderr, "Second flock succeeded - FAIL\n");
370 if (flock(fd, LOCK_UN) == -1) {
371 fprintf(stderr, "Child unlock on parent fd failed\n");
375 if (flock(fd2, LOCK_EX | LOCK_NB) == -1) {
376 fprintf(stderr, "Relock after parent unlock failed!\n");
385 waitpid(pid, &rc, 0);
391 static int t4(int argc, char *argv[])
393 struct flock lock = {
395 .l_whence = SEEK_SET,
403 int rc = EXIT_SUCCESS;
406 fprintf(stderr, "usage: flocks_test 4 file1 file2\n");
410 fd = open(argv[2], O_RDWR);
412 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
415 fd2 = open(argv[3], O_RDWR);
417 fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
429 if (child_pid == 0) {
430 printf("%d: get lock1\n", getpid());
432 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
433 fprintf(stderr, "%d: cannot get lock1: %s\n",
434 getpid(), strerror(errno));
438 printf("%d: done\n", getpid());
440 printf("%d: get lock2\n", getpid());
442 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
443 fprintf(stderr, "%d: cannot get lock2: %s\n",
444 getpid(), strerror(errno));
446 if (errno == EDEADLK)
453 printf("%d: done\n", getpid());
455 printf("%d: exit rc=%d\n", getpid(), rc);
458 printf("%d: get lock2\n", getpid());
460 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
461 fprintf(stderr, "%d: cannot get lock2: %s\n",
462 getpid(), strerror(errno));
466 printf("%d: done\n", getpid());
468 printf("%d: get lock1\n", getpid());
470 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
471 fprintf(stderr, "%d: cannot get lock1: %s\n",
472 getpid(), strerror(errno));
474 if (errno != EDEADLK) {
479 printf("%d: done\n", getpid());
485 fprintf(stderr, "%d: error closing file1: %s\n",
486 getpid(), strerror(errno));
490 if (close(fd2) < 0) {
491 fprintf(stderr, "%d: error closing file2: %s\n",
492 getpid(), strerror(errno));
496 if (waitpid(child_pid, &child_status, 0) < 0) {
497 fprintf(stderr, "%d: cannot get termination status of %d: %s\n",
498 getpid(), child_pid, strerror(errno));
500 } else if (!WIFEXITED(child_status)) {
501 fprintf(stderr, "%d: child %d terminated with status %d\n",
502 getpid(), child_pid, child_status);
505 rc = WEXITSTATUS(child_status);
509 printf("%d: exit rc=%d\n", getpid(), rc);
514 "usage: flocks_test 5 {set|get|unlock} [read|write] [sleep N] file1\n" \
515 " set: F_SETLKW F_WRLCK\n" \
516 " get: F_GETLK F_WRLCK (conflict)\n" \
517 " unlock: F_SETLKW F_UNLCK\n" \
518 " read|write: lock mode, write by default\n" \
519 " sleep N: sleep for N secs after fcntl\n" \
520 " file1: fcntl is called for this file\n"
522 static int t5(int argc, char *argv[])
524 struct flock lock = {
526 .l_whence = SEEK_SET,
529 int setlk = 0, getlk = 0, unlk = 0, secs = 0;
534 if (argc < 4 || argc > 7) {
535 fprintf(stderr, T5_USAGE);
539 if (!strncmp(argv[2], "set", 4))
541 else if (!strncmp(argv[2], "get", 4))
543 else if (!strncmp(argv[2], "unlock", 7))
546 fprintf(stderr, "Wrong 2nd argument: %s\n", argv[2]);
552 if (!strncmp(argv[pos], "read", 5)) {
553 lock.l_type = F_RDLCK;
555 } else if (!strncmp(argv[pos], "write", 6)) {
556 lock.l_type = F_WRLCK;
560 if (!strncmp(argv[pos], "sleep", 6)) {
561 secs = atoi(argv[pos + 1]);
562 if (secs < 0 || secs > 10) {
563 fprintf(stderr, "Sleep argument is wrong: %s\n",
570 fd = open(argv[pos], O_RDWR);
572 fprintf(stderr, "Couldn't open file: %s\n", argv[pos]);
576 fprintf(stderr, "\nFLOCKS_TEST 5: %s %s flock\n",
577 setlk ? "SET" : getlk ? "GET" : "UNLOCK",
578 lock.l_type == F_WRLCK ? "write" : "read");
581 rc = t_fcntl(fd, F_SETLKW, &lock);
583 rc = t_fcntl(fd, F_GETLK, &lock);
585 lock.l_type = F_UNLCK;
586 rc = t_fcntl(fd, F_SETLKW, &lock);
593 return rc < 0 ? -rc : 0;
597 #define T6BUF_SIZE 200
599 int set_lock(struct flock *lock, char *buf)
612 for (i = 0; isspace(buf[i]) && i < T6BUF_SIZE;)
614 for (v = 0; tags[v].tag && i < T6BUF_SIZE; v++) {
615 if (buf[i] == tags[v].tag) {
619 for (; buf[i] != ','; i++)
623 lock->l_start = atol(head);
624 if (lock->l_start < 0)
626 for (; !isdigit(buf[i]); i++)
629 lock->l_len = atol(buf + i);
630 if (lock->l_len <= 0)
632 lock->l_type = tags[v].mode;
636 fprintf(stderr, "Invalid line: %s\n", buf);
641 * Read command from stdin then enqueue a lock
644 * W: write R: read U: unlock
645 * sss: start of range
646 * lll: length of range
649 * W1,100 # add a write lock from 1 to 100
650 * R100,100 # add a read lock from 100 to 199
652 static int t6(int argc, char *argv[])
654 struct flock lock = {
655 .l_whence = SEEK_SET,
659 char buf[T6BUF_SIZE+1];
663 fprintf(stderr, "usage: flocks_test 6 file\n");
667 fd = open(argv[2], O_RDWR);
669 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
673 memset(buf, '\0', T6BUF_SIZE + 1);
675 while (fgets(buf, T6BUF_SIZE, stdin)) {
676 if (set_lock(&lock, buf)) {
677 rc = t_fcntl(fd, F_SETLKW, &lock);
679 fprintf(stderr, "%d: cannot set lock: %s\n",
680 getpid(), strerror(errno));
687 printf("Time for processing %.03lfs\n", now() - stime);
691 static void usage(void)
694 "usage: flocks_test test# [corresponding arguments]\n");
698 int main(int argc, char *argv[])
700 int rc = EXIT_SUCCESS;
707 switch (atoi(argv[1])) {
727 fprintf(stderr, "unknown test number '%s'\n", argv[1]);
732 fprintf(stderr, "exiting with rc = %d\n", rc);