X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Ftests%2Fflocks_test.c;h=ab38fa0c46d31bd10863a37f1419bc4c685b74ed;hb=a98d44e0439ad5b20d0d7f273b29e6ea990312f0;hp=4c97e6371f39a53488241df30d78a0289f1c82e1;hpb=70e80ade90af09300396706b8910e196a7928520;p=fs%2Flustre-release.git diff --git a/lustre/tests/flocks_test.c b/lustre/tests/flocks_test.c index 4c97e63..ab38fa0 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. @@ -16,8 +14,8 @@ * in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see [sun.com URL with a - * copy of GPLv2]. + * 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 @@ -26,8 +24,10 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -40,38 +40,120 @@ #include #include #include - +#include #include +#include +#include -void usage(void) +#define MAX_PATH_LENGTH 4096 +/** + * helper functions + */ +int t_fcntl(int fd, int cmd, ...) +{ + va_list ap; + long arg; + struct flock *lock; + int rc = -1; + + va_start(ap, cmd); + switch (cmd) { + case F_GETFL: + va_end(ap); + rc = fcntl(fd, cmd); + if (rc == -1) { + fprintf(stderr, "fcntl GETFL failed: %s\n", + strerror(errno)); + return(1); + } + break; + case F_SETFL: + arg = va_arg(ap, long); + va_end(ap); + rc = fcntl(fd, cmd, arg); + if (rc == -1) { + fprintf(stderr, "fcntl SETFL %ld failed: %s\n", + arg, strerror(errno)); + return(1); + } + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + lock = va_arg(ap, struct flock *); + va_end(ap); + rc = fcntl(fd, cmd, lock); + if (rc == -1) { + fprintf(stderr, "fcntl cmd %d failed: %s\n", + cmd, strerror(errno)); + return(1); + } + break; + case F_DUPFD: + arg = va_arg(ap, long); + va_end(ap); + rc = fcntl(fd, cmd, arg); + if (rc == -1) { + fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n", + (int)arg, strerror(errno)); + return(1); + } + break; + default: + va_end(ap); + fprintf(stderr, "fcntl cmd %d not supported\n", cmd); + return(1); + } + return rc; +} + +int t_unlink(const char *path) { - fprintf(stderr, "usage: ./flocks_test on|off -c|-f|-l /path/to/file\n"); - exit(EXIT_FAILURE); + int rc; + + rc = unlink(path); + if (rc) + fprintf(stderr, "unlink(%s) error: %s\n", path, strerror(errno)); + return rc; +} + +/** ================================================================= + * test number 1 + * + * normal flock test + */ +void t1_usage(void) +{ + fprintf(stderr, "usage: ./flocks_test 1 on|off -c|-f|-l /path/to/file\n"); } -int main(int argc, char *argv[]) +int t1(int argc, char *argv[]) { int fd; int mount_with_flock = 0; int error = 0; + int rc = 0; - if (argc != 4) - usage(); - - if (!strncmp(argv[1], "on", 3)) { + if (argc != 5) { + t1_usage(); + return EXIT_FAILURE; + } + + if (!strncmp(argv[2], "on", 3)) { mount_with_flock = 1; - } else if (!strncmp(argv[1], "off", 4)) { + } else if (!strncmp(argv[2], "off", 4)) { mount_with_flock = 0; } else { - usage(); + t1_usage(); + return EXIT_FAILURE; } - if ((fd = open(argv[3], O_RDWR)) < 0) { - fprintf(stderr, "Couldn't open file: %s\n", argv[2]); - exit(EXIT_FAILURE); + if ((fd = open(argv[4], O_RDWR)) < 0) { + fprintf(stderr, "Couldn't open file: %s\n", argv[3]); + return EXIT_FAILURE; } - if (!strncmp(argv[2], "-c", 3)) { + if (!strncmp(argv[3], "-c", 3)) { struct flock fl; fl.l_type = F_RDLCK; @@ -80,16 +162,317 @@ int main(int argc, char *argv[]) fl.l_len = 1; error = fcntl(fd, F_SETLK, &fl); - } else if (!strncmp(argv[2], "-l", 3)) { + } else if (!strncmp(argv[3], "-l", 3)) { error = lockf(fd, F_LOCK, 1); - } else if (!strncmp(argv[2], "-f", 3)) { + } else if (!strncmp(argv[3], "-f", 3)) { error = flock(fd, LOCK_EX); } else { - usage(); + t1_usage(); + 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; +} + +/** =============================================================== + * test number 2 + * + * 2 threads flock ops interweave + */ +typedef struct { + struct flock* lock; + int fd; +} th_data; + +void* t2_thread1(void *arg) +{ + struct flock *lock = ((th_data *)arg)->lock; + int fd = ((th_data *)arg)->fd; + + printf("thread 1: set write lock (blocking)\n"); + lock->l_type = F_WRLCK; + t_fcntl(fd, F_SETLKW, lock); + printf("thread 1: set write lock done\n"); + t_fcntl(fd, F_GETLK, lock); + printf("thread 1: unlock\n"); + lock->l_type = F_UNLCK; + t_fcntl(fd, F_SETLK, lock); + printf("thread 1: unlock done\n"); + return 0; +} + +void* t2_thread2(void *arg) +{ + struct flock *lock = ((th_data *)arg)->lock; + int fd = ((th_data *)arg)->fd; + + sleep(2); + printf("thread 2: unlock\n"); + lock->l_type = F_UNLCK; + t_fcntl(fd, F_SETLK, lock); + printf("thread 2: unlock done\n"); + printf("thread 2: set write lock (non-blocking)\n"); + lock->l_type = F_WRLCK; + t_fcntl(fd, F_SETLK, lock); + printf("thread 2: set write lock done\n"); + t_fcntl(fd, F_GETLK, lock); + return 0; +} + +int t2(int argc, char* argv[]) +{ + struct flock lock = { + .l_type = F_RDLCK, + .l_whence = SEEK_SET, + }; + char file[MAX_PATH_LENGTH] = ""; + int fd, rc; + pthread_t th1, th2; + th_data ta; + + snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]); + + fd = open(file, O_RDWR|O_CREAT, (mode_t)0666); + if (fd < 0) { + fprintf(stderr, "error open file: %s\n", file); + return EXIT_FAILURE; + } + + t_fcntl(fd, F_SETFL, O_APPEND); + rc = t_fcntl(fd, F_GETFL); + if ((rc & O_APPEND) == 0) { + fprintf(stderr, "error get flag: ret %x\n", rc); + rc = EXIT_FAILURE; + goto out; + } + + ta.lock = &lock; + ta.fd = fd; + rc = pthread_create(&th1, NULL, t2_thread1, &ta); + if (rc) { + fprintf(stderr, "error create thread 1\n"); + rc = EXIT_FAILURE; + goto out; + } + rc = pthread_create(&th2, NULL, t2_thread2, &ta); + if (rc) { + fprintf(stderr, "error create thread 2\n"); + rc = EXIT_FAILURE; + goto out; + } + (void)pthread_join(th1, NULL); + (void)pthread_join(th2, NULL); +out: + t_unlink(file); + close(fd); + 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[1]); + 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[1]); + 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; + int pid; + 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; + } + + pid = fork(); + if (pid == -1) { + perror("fork"); + rc = EXIT_FAILURE; + goto out; + } + + if (pid == 0) { + printf("%d: get lock1\n", getpid()); + fflush(stdout); + if (t_fcntl(fd, F_SETLKW, &lock) < 0) { + perror("first flock failed"); + 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) { + perror("first flock failed"); + 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) { + perror("first flock failed"); + 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) { + perror("first flock failed"); + rc = EXIT_FAILURE; + goto out; + } + printf("%d: done\n", getpid()); + } + +out: + printf("%d: exit rc=%d\n", getpid(), rc); + return rc; +} + +/** ============================================================== + * program entry + */ +void usage(void) +{ + fprintf(stderr, "usage: ./flocks_test test# [corresponding arguments]\n"); +} + +int main(int argc, char* argv[]) +{ + int test_no; + int rc = EXIT_SUCCESS; + + if (argc < 1) { + usage(); + exit(EXIT_FAILURE); + } + test_no = atoi(argv[1]); + + switch(test_no) { + case 1: + rc = t1(argc, argv); + break; + case 2: + rc = t2(argc, argv); + break; + case 3: + rc = t3(argc, argv); + break; + case 4: + rc = t4(argc, argv); + break; + default: + fprintf(stderr, "unknow test number %s\n", argv[1]); + break; + } + return rc; }