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;
59 static int t_fcntl(int fd, int cmd, ...)
73 fprintf(stderr, "fcntl GETFL failed: %s\n",
79 arg = va_arg(ap, long);
81 rc = fcntl(fd, cmd, arg);
84 fprintf(stderr, "fcntl SETFL %ld failed: %s\n",
85 arg, strerror(errno));
92 lock = va_arg(ap, struct flock *);
94 rc = fcntl(fd, cmd, lock);
97 fprintf(stderr, "fcntl cmd %d failed: %s\n",
98 cmd, strerror(errno));
103 arg = va_arg(ap, long);
105 rc = fcntl(fd, cmd, arg);
108 fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n",
109 (int)arg, strerror(errno));
115 fprintf(stderr, "fcntl cmd %d not supported\n", cmd);
121 static int t_unlink(const char *path)
128 "unlink(%s) error: %s\n", path, strerror(errno));
132 /** =================================================================
137 static void t1_usage(void)
140 "usage: flocks_test 1 {on|off} {-c|-f|-l} /path/to/file\n");
143 static int t1(int argc, char *argv[])
146 int mount_with_flock = 0;
155 if (!strncmp(argv[2], "on", 3)) {
156 mount_with_flock = 1;
157 } else if (!strncmp(argv[2], "off", 4)) {
158 mount_with_flock = 0;
164 fd = open(argv[4], O_RDWR);
166 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[4],
171 if (!strncmp(argv[3], "-c", 3)) {
175 fl.l_whence = SEEK_SET;
179 error = fcntl(fd, F_SETLK, &fl);
180 } else if (!strncmp(argv[3], "-l", 3)) {
181 error = lockf(fd, F_LOCK, 1);
182 } else if (!strncmp(argv[3], "-f", 3)) {
183 error = flock(fd, LOCK_EX);
190 if (mount_with_flock)
191 rc = ((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
193 rc = ((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS);
201 /** ===============================================================
204 * 2 threads flock ops interweave
212 static void *t2_thread1(void *arg)
214 struct thread_info *ti = arg;
215 struct flock *lock = ti->lock;
218 printf("thread 1: set write lock (blocking): rc = %d\n", ti->rc);
219 lock->l_type = F_WRLCK;
220 t_fcntl(fd, F_SETLKW, lock);
221 printf("thread 1: set write lock done: rc = %d\n", ti->rc);
222 (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
223 printf("thread 1: unlock: rc = %d\n", ti->rc);
224 lock->l_type = F_UNLCK;
225 ti->rc += t_fcntl(fd, F_SETLK, lock);
226 printf("thread 1: unlock done: rc = %d\n", ti->rc);
229 fprintf(stdout, "thread1 exiting with rc = %d\n", ti->rc);
233 static void *t2_thread2(void *arg)
235 struct thread_info *ti = arg;
236 struct flock *lock = ti->lock;
240 printf("thread 2: unlock: rc = %d\n", ti->rc);
241 lock->l_type = F_UNLCK;
242 ti->rc += t_fcntl(fd, F_SETLK, lock);
243 printf("thread 2: unlock done: rc = %d\n", ti->rc);
244 printf("thread 2: set write lock (non-blocking): rc = %d\n", ti->rc);
245 lock->l_type = F_WRLCK;
246 ti->rc += t_fcntl(fd, F_SETLK, lock);
247 printf("thread 2: set write lock done: rc = %d\n", ti->rc);
248 (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
251 fprintf(stdout, "thread2 exiting with rc = %d\n", ti->rc);
255 static int t2(int argc, char *argv[])
257 struct flock lock = {
259 .l_whence = SEEK_SET,
261 char file[MAX_PATH_LENGTH] = "";
264 struct thread_info ti;
266 snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
268 fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
270 fprintf(stderr, "error open file '%s': %s\n", file,
275 t_fcntl(fd, F_SETFL, O_APPEND);
276 rc = t_fcntl(fd, F_GETFL);
277 if ((rc < 0) || (rc & O_APPEND) == 0) {
278 fprintf(stderr, "error get flag: ret %x\n", rc);
286 rc = pthread_create(&th1, NULL, t2_thread1, &ti);
288 fprintf(stderr, "error create thread 1\n");
292 rc = pthread_create(&th2, NULL, t2_thread2, &ti);
294 fprintf(stderr, "error create thread 2\n");
298 pthread_join(th1, NULL);
299 pthread_join(th2, NULL);
309 /** =================================================================
312 * Bug 24040: Two conflicting flocks from same process different fds should fail
313 * two conflicting flocks from different processes but same fs
316 static int t3(int argc, char *argv[])
320 int rc = EXIT_SUCCESS;
323 fprintf(stderr, "usage: flocks_test 3 filename\n");
327 fd = open(argv[2], O_RDWR);
329 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
333 if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
334 perror("first flock failed");
338 fd2 = open(argv[2], O_RDWR);
340 fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
345 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
346 fprintf(stderr, "Second flock succeeded - FAIL\n");
362 fd2 = open(argv[2], O_RDWR);
364 fprintf(stderr, "Couldn't open file '%s': %s\n",
365 argv[1], strerror(errno));
369 if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
370 fprintf(stderr, "Second flock succeeded - FAIL\n");
374 if (flock(fd, LOCK_UN) == -1) {
375 fprintf(stderr, "Child unlock on parent fd failed\n");
379 if (flock(fd2, LOCK_EX | LOCK_NB) == -1) {
380 fprintf(stderr, "Relock after parent unlock failed!\n");
389 waitpid(pid, &rc, 0);
395 static int t4(int argc, char *argv[])
397 struct flock lock = {
399 .l_whence = SEEK_SET,
407 int rc = EXIT_SUCCESS;
410 fprintf(stderr, "usage: flocks_test 4 file1 file2\n");
414 fd = open(argv[2], O_RDWR);
416 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
419 fd2 = open(argv[3], O_RDWR);
421 fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
433 if (child_pid == 0) {
434 printf("%d: get lock1\n", getpid());
436 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
437 fprintf(stderr, "%d: cannot get lock1: %s\n",
438 getpid(), strerror(errno));
442 printf("%d: done\n", getpid());
444 printf("%d: get lock2\n", getpid());
446 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
447 fprintf(stderr, "%d: cannot get lock2: %s\n",
448 getpid(), strerror(errno));
450 if (errno == EDEADLK)
457 printf("%d: done\n", getpid());
459 printf("%d: exit rc=%d\n", getpid(), rc);
462 printf("%d: get lock2\n", getpid());
464 if (t_fcntl(fd2, F_SETLKW, &lock) < 0) {
465 fprintf(stderr, "%d: cannot get lock2: %s\n",
466 getpid(), strerror(errno));
470 printf("%d: done\n", getpid());
472 printf("%d: get lock1\n", getpid());
474 if (t_fcntl(fd, F_SETLKW, &lock) < 0) {
475 fprintf(stderr, "%d: cannot get lock1: %s\n",
476 getpid(), strerror(errno));
478 if (errno != EDEADLK) {
483 printf("%d: done\n", getpid());
489 fprintf(stderr, "%d: error closing file1: %s\n",
490 getpid(), strerror(errno));
494 if (close(fd2) < 0) {
495 fprintf(stderr, "%d: error closing file2: %s\n",
496 getpid(), strerror(errno));
500 if (waitpid(child_pid, &child_status, 0) < 0) {
501 fprintf(stderr, "%d: cannot get termination status of %d: %s\n",
502 getpid(), child_pid, strerror(errno));
504 } else if (!WIFEXITED(child_status)) {
505 fprintf(stderr, "%d: child %d terminated with status %d\n",
506 getpid(), child_pid, child_status);
509 rc = WEXITSTATUS(child_status);
513 printf("%d: exit rc=%d\n", getpid(), rc);
518 "usage: flocks_test 5 {set|get|unlock} [read|write] [sleep N] file1\n" \
519 " set: F_SETLKW F_WRLCK\n" \
520 " get: F_GETLK F_WRLCK (conflict)\n" \
521 " unlock: F_SETLKW F_UNLCK\n" \
522 " read|write: lock mode, write by default\n" \
523 " sleep N: sleep for N secs after fcntl\n" \
524 " file1: fcntl is called for this file\n"
526 static int t5(int argc, char *argv[])
528 struct flock lock = {
530 .l_whence = SEEK_SET,
533 int setlk = 0, getlk = 0, unlk = 0, secs = 0;
538 if (argc < 4 || argc > 7) {
539 fprintf(stderr, T5_USAGE);
543 if (!strncmp(argv[2], "set", 4))
545 else if (!strncmp(argv[2], "get", 4))
547 else if (!strncmp(argv[2], "unlock", 7))
550 fprintf(stderr, "Wrong 2nd argument: %s\n", argv[2]);
556 if (!strncmp(argv[pos], "read", 5)) {
557 lock.l_type = F_RDLCK;
559 } else if (!strncmp(argv[pos], "write", 6)) {
560 lock.l_type = F_WRLCK;
564 if (!strncmp(argv[pos], "sleep", 6)) {
565 secs = atoi(argv[pos + 1]);
566 if (secs < 0 || secs > 10) {
567 fprintf(stderr, "Sleep argument is wrong: %s\n",
574 fd = open(argv[pos], O_RDWR);
576 fprintf(stderr, "Couldn't open file: %s\n", argv[pos]);
580 fprintf(stderr, "\nFLOCKS_TEST 5: %s %s flock\n",
581 setlk ? "SET" : getlk ? "GET" : "UNLOCK",
582 lock.l_type == F_WRLCK ? "write" : "read");
585 rc = t_fcntl(fd, F_SETLKW, &lock);
587 rc = t_fcntl(fd, F_GETLK, &lock);
589 lock.l_type = F_UNLCK;
590 rc = t_fcntl(fd, F_SETLKW, &lock);
597 return rc < 0 ? -rc : 0;
601 #define T6BUF_SIZE 200
603 int set_lock(struct flock *lock, char *buf)
616 for (i = 0; isspace(buf[i]) && i < T6BUF_SIZE;)
618 for (v = 0; tags[v].tag && i < T6BUF_SIZE; v++) {
619 if (buf[i] == tags[v].tag) {
623 for (; buf[i] != ','; i++)
627 lock->l_start = atol(head);
628 if (lock->l_start < 0)
630 for (; !isdigit(buf[i]); i++)
633 lock->l_len = atol(buf + i);
634 if (lock->l_len <= 0)
636 lock->l_type = tags[v].mode;
640 fprintf(stderr, "Invalid line: %s\n", buf);
645 * Read command from stdin then enqueue a lock
648 * W: write R: read U: unlock
649 * sss: start of range
650 * lll: length of range
653 * W1,100 # add a write lock from 1 to 100
654 * R100,100 # add a read lock from 100 to 199
656 static int t6(int argc, char *argv[])
658 struct flock lock = {
659 .l_whence = SEEK_SET,
663 char buf[T6BUF_SIZE+1];
667 fprintf(stderr, "usage: flocks_test 6 file\n");
671 fd = open(argv[2], O_RDWR);
673 fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
677 memset(buf, '\0', T6BUF_SIZE + 1);
679 while (fgets(buf, T6BUF_SIZE, stdin)) {
680 if (set_lock(&lock, buf)) {
681 rc = t_fcntl(fd, F_SETLKW, &lock);
683 fprintf(stderr, "%d: cannot set lock: %s\n",
684 getpid(), strerror(errno));
691 printf("Time for processing %.03lfs\n", now() - stime);
695 /** ==============================================================
698 static void usage(void)
701 "usage: flocks_test test# [corresponding arguments]\n");
704 int main(int argc, char *argv[])
706 int rc = EXIT_SUCCESS;
713 switch (atoi(argv[1])) {
733 fprintf(stderr, "unknown test number '%s'\n", argv[1]);
738 fprintf(stderr, "exiting with rc = %d\n", rc);