X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Ftests%2Fflocks_test.c;h=9ce5a0c9b260709278b5a2dbf95fe92483b59c71;hb=fabf3fe7ac06d916d8c433a99f1f4a4bd3632638;hp=fe2f0456dbe51dec81635254f33c184624fa3c3d;hpb=0f8dca08a4f68cba82c2c822998ecc309d3b7aaf;p=fs%2Flustre-release.git diff --git a/lustre/tests/flocks_test.c b/lustre/tests/flocks_test.c index fe2f045..9ce5a0c 100644 --- a/lustre/tests/flocks_test.c +++ b/lustre/tests/flocks_test.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -17,17 +15,15 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2014, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -42,6 +38,7 @@ #include #include #include +#include #include #define MAX_PATH_LENGTH 4096 @@ -61,9 +58,10 @@ int t_fcntl(int fd, int cmd, ...) va_end(ap); rc = fcntl(fd, cmd); if (rc == -1) { + rc = -errno; fprintf(stderr, "fcntl GETFL failed: %s\n", strerror(errno)); - return(1); + return rc; } break; case F_SETFL: @@ -71,9 +69,10 @@ int t_fcntl(int fd, int cmd, ...) va_end(ap); rc = fcntl(fd, cmd, arg); if (rc == -1) { + rc = -errno; fprintf(stderr, "fcntl SETFL %ld failed: %s\n", arg, strerror(errno)); - return(1); + return rc ; } break; case F_GETLK: @@ -83,9 +82,10 @@ int t_fcntl(int fd, int cmd, ...) va_end(ap); rc = fcntl(fd, cmd, lock); if (rc == -1) { + rc = -errno; fprintf(stderr, "fcntl cmd %d failed: %s\n", cmd, strerror(errno)); - return(1); + return rc ; } break; case F_DUPFD: @@ -93,15 +93,16 @@ int t_fcntl(int fd, int cmd, ...) va_end(ap); rc = fcntl(fd, cmd, arg); if (rc == -1) { + rc = -errno; fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n", (int)arg, strerror(errno)); - return(1); + return rc; } break; default: va_end(ap); fprintf(stderr, "fcntl cmd %d not supported\n", cmd); - return(1); + return rc; } return rc; } @@ -131,6 +132,7 @@ int t1(int argc, char *argv[]) int fd; int mount_with_flock = 0; int error = 0; + int rc = 0; if (argc != 5) { t1_usage(); @@ -147,7 +149,7 @@ int t1(int argc, char *argv[]) } if ((fd = open(argv[4], O_RDWR)) < 0) { - fprintf(stderr, "Couldn't open file: %s\n", argv[3]); + fprintf(stderr, "Couldn't open file: %s\n", argv[4]); return EXIT_FAILURE; } @@ -166,13 +168,19 @@ int t1(int argc, char *argv[]) error = flock(fd, LOCK_EX); } else { t1_usage(); - return EXIT_FAILURE; + rc = EXIT_FAILURE; + goto out; } if (mount_with_flock) - return((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE); + rc = ((error == 0) ? EXIT_SUCCESS : EXIT_FAILURE); else - return((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS); + rc = ((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS); + +out: + if (fd >= 0) + close(fd); + return rc; } /** =============================================================== @@ -241,9 +249,10 @@ int t2(int argc, char* argv[]) t_fcntl(fd, F_SETFL, O_APPEND); rc = t_fcntl(fd, F_GETFL); - if ((rc & O_APPEND) == 0) { + if ((rc < 0) || (rc & O_APPEND) == 0) { fprintf(stderr, "error get flag: ret %x\n", rc); - return EXIT_FAILURE; + rc = EXIT_FAILURE; + goto out; } ta.lock = &lock; @@ -268,6 +277,290 @@ out: return rc; } +/** ================================================================= + * test number 3 + * + * Bug 24040: Two conflicting flocks from same process different fds should fail + * two conflicting flocks from different processes but same fs + * should succeed. + */ +int t3(int argc, char *argv[]) +{ + int fd, fd2; + int pid; + int rc = EXIT_SUCCESS; + + if (argc != 3) { + fprintf(stderr, "Usage: ./flocks_test 3 filename\n"); + return EXIT_FAILURE; + } + + if ((fd = open(argv[2], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[2]); + return EXIT_FAILURE; + } + if (flock(fd, LOCK_EX | LOCK_NB) < 0) { + perror("first flock failed"); + rc = EXIT_FAILURE; + goto out; + } + if ((fd2 = open(argv[2], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[2]); + rc = EXIT_FAILURE; + goto out; + } + if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) { + fprintf(stderr, "Second flock succeeded - FAIL\n"); + rc = EXIT_FAILURE; + close(fd2); + goto out; + } + + close(fd2); + + pid = fork(); + if (pid == -1) { + perror("fork"); + rc = EXIT_FAILURE; + goto out; + } + + if (pid == 0) { + if ((fd2 = open(argv[2], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[1]); + rc = EXIT_FAILURE; + exit(rc); + } + if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) { + fprintf(stderr, "Second flock succeeded - FAIL\n"); + rc = EXIT_FAILURE; + goto out_child; + } + if (flock(fd, LOCK_UN) == -1) { + fprintf(stderr, "Child unlock on parent fd failed\n"); + rc = EXIT_FAILURE; + goto out_child; + } + if (flock(fd2, LOCK_EX | LOCK_NB) == -1) { + fprintf(stderr, "Relock after parent unlock failed!\n"); + rc = EXIT_FAILURE; + goto out_child; + } + out_child: + close(fd2); + exit(rc); + } + + waitpid(pid, &rc, 0); +out: + close(fd); + return rc; +} + +int t4(int argc, char *argv[]) +{ + struct flock lock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 10, + }; + + int fd, fd2; + pid_t child_pid; + int child_status; + int rc = EXIT_SUCCESS; + + if (argc != 4) { + fprintf(stderr, "Usage: ./flocks_test 4 file1 file2\n"); + return EXIT_FAILURE; + } + + if ((fd = open(argv[2], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[2]); + return EXIT_FAILURE; + } + if ((fd2 = open(argv[3], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[3]); + rc = EXIT_FAILURE; + goto out; + } + + child_pid = fork(); + if (child_pid < 0) { + perror("fork"); + rc = EXIT_FAILURE; + goto out; + } + + if (child_pid == 0) { + printf("%d: get lock1\n", getpid()); + fflush(stdout); + if (t_fcntl(fd, F_SETLKW, &lock) < 0) { + fprintf(stderr, "%d: cannot get lock1: %s\n", + getpid(), strerror(errno)); + rc = EXIT_FAILURE; + goto out_child; + } + printf("%d: done\n", getpid()); + sleep(3); + printf("%d: get lock2\n", getpid()); + fflush(stdout); + if (t_fcntl(fd2, F_SETLKW, &lock) < 0) { + fprintf(stderr, "%d: cannot get lock2: %s\n", + getpid(), strerror(errno)); + + if (errno == EDEADLK) + rc = EXIT_SUCCESS; + else + rc = EXIT_FAILURE; + + goto out_child; + } + printf("%d: done\n", getpid()); +out_child: + printf("%d: exit rc=%d\n", getpid(), rc); + exit(rc); + } else { + printf("%d: get lock2\n", getpid()); + fflush(stdout); + if (t_fcntl(fd2, F_SETLKW, &lock) < 0) { + fprintf(stderr, "%d: cannot get lock2: %s\n", + getpid(), strerror(errno)); + rc = EXIT_FAILURE; + goto out; + } + printf("%d: done\n", getpid()); + sleep(3); + printf("%d: get lock1\n", getpid()); + fflush(stdout); + if (t_fcntl(fd, F_SETLKW, &lock) < 0) { + fprintf(stderr, "%d: cannot get lock1: %s\n", + getpid(), strerror(errno)); + + if (errno != EDEADLK) { + rc = EXIT_FAILURE; + goto out; + } + } + printf("%d: done\n", getpid()); + } + + sleep(1); + + if (close(fd) < 0) { + fprintf(stderr, "%d: error closing file1: %s\n", + getpid(), strerror(errno)); + rc = EXIT_FAILURE; + } + + if (close(fd2) < 0) { + fprintf(stderr, "%d: error closing file2: %s\n", + getpid(), strerror(errno)); + rc = EXIT_FAILURE; + } + + if (waitpid(child_pid, &child_status, 0) < 0) { + fprintf(stderr, "%d: cannot get termination status of %d: %s\n", + getpid(), child_pid, strerror(errno)); + rc = EXIT_FAILURE; + } else if (!WIFEXITED(child_status)) { + fprintf(stderr, "%d: child %d terminated with status %d\n", + getpid(), child_pid, child_status); + rc = EXIT_FAILURE; + } else { + rc = WEXITSTATUS(child_status); + } + +out: + printf("%d: exit rc=%d\n", getpid(), rc); + return rc; +} + +#define T5_USAGE \ + "Usage: ./flocks_test 5 set|get|unlock [read|write] [sleep N] file1\n"\ +" set: F_SETLKW F_WRLCK\n" \ +" get: F_GETLK F_WRLCK (conflict)\n" \ +" unlock: F_SETLKW F_UNLCK\n" \ +" read|write: lock mode, write by default\n" \ +" sleep N: sleep for N secs after fcntl\n" \ +" file1: fcntl is called for this file\n" + +int t5(int argc, char *argv[]) +{ + struct flock lock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + int setlk = 0, getlk = 0, unlk = 0, secs = 0; + int pos; + int fd; + int rc = 0; + + if (argc < 4 || argc > 7) { + fprintf(stderr, T5_USAGE); + return EXIT_FAILURE; + } + + if (!strncmp(argv[2], "set", 4)) + setlk = 1; + else if (!strncmp(argv[2], "get", 4)) + getlk = 1; + else if (!strncmp(argv[2], "unlock", 7)) + unlk = 1; + else { + fprintf(stderr, "Wrong 2nd argument: %s\n", argv[2]); + return EXIT_FAILURE; + } + + pos = 3; + + if (!strncmp(argv[pos], "read", 5)) { + lock.l_type = F_RDLCK; + pos++; + } else if (!strncmp(argv[pos], "write", 6)) { + lock.l_type = F_WRLCK; + pos++; + } + + if (!strncmp(argv[pos], "sleep", 6)) { + secs = atoi(argv[pos + 1]); + if (secs < 0 || secs > 10) { + fprintf(stderr, "Sleep argument is wrong: %s\n", + argv[pos + 1]); + return EXIT_FAILURE; + } + pos += 2; + } + + fd = open(argv[pos], O_RDWR); + if (fd < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[pos]); + return EXIT_FAILURE; + } + + fprintf(stderr, "\nFLOCKS_TEST 5: %s %s flock\n", + setlk ? "SET" : getlk ? "GET" : "UNLOCK", + lock.l_type == F_WRLCK ? "write" : "read"); + + if (setlk) { + rc = t_fcntl(fd, F_SETLKW, &lock); + } else if (getlk) { + rc = t_fcntl(fd, F_GETLK, &lock); + } else if (unlk) { + lock.l_type = F_UNLCK; + rc = t_fcntl(fd, F_SETLKW, &lock); + } + + if (secs) + sleep(secs); + + close(fd); + return rc < 0 ? -rc : 0; + +} + /** ============================================================== * program entry */ @@ -294,7 +587,16 @@ int main(int argc, char* argv[]) case 2: rc = t2(argc, argv); break; - default: + case 3: + rc = t3(argc, argv); + break; + case 4: + rc = t4(argc, argv); + break; + case 5: + rc = t5(argc, argv); + break; + default: fprintf(stderr, "unknow test number %s\n", argv[1]); break; }