Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: add OFD lock tests

Test the basic locking stuff on 2 fds: multiple read locks,
conflicts between read and write locks, use of len==0 for queries.
Also tests for F_UNLCK F_OFD_GETLK extension.

[ jlayton: fix unlink() pathname in selftest ]

Cc: Jeff Layton <jlayton@kernel.org>
Cc: Chuck Lever <chuck.lever@oracle.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <brauner@kernel.org>
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-api@vger.kernel.org
Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
Signed-off-by: Jeff Layton <jlayton@kernel.org>

authored by

Stas Sergeev and committed by
Jeff Layton
bfe2e8f5 6c9007f6

+137
+5
tools/testing/selftests/filelock/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + TEST_GEN_PROGS := ofdlocks 4 + 5 + include ../lib.mk
+132
tools/testing/selftests/filelock/ofdlocks.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define _GNU_SOURCE 4 + #include <fcntl.h> 5 + #include <assert.h> 6 + #include <stdio.h> 7 + #include <unistd.h> 8 + #include <string.h> 9 + #include "../kselftest.h" 10 + 11 + static int lock_set(int fd, struct flock *fl) 12 + { 13 + int ret; 14 + 15 + fl->l_pid = 0; // needed for OFD locks 16 + fl->l_whence = SEEK_SET; 17 + ret = fcntl(fd, F_OFD_SETLK, fl); 18 + if (ret) 19 + perror("fcntl()"); 20 + return ret; 21 + } 22 + 23 + static int lock_get(int fd, struct flock *fl) 24 + { 25 + int ret; 26 + 27 + fl->l_pid = 0; // needed for OFD locks 28 + fl->l_whence = SEEK_SET; 29 + ret = fcntl(fd, F_OFD_GETLK, fl); 30 + if (ret) 31 + perror("fcntl()"); 32 + return ret; 33 + } 34 + 35 + int main(void) 36 + { 37 + int rc; 38 + struct flock fl, fl2; 39 + int fd = open("/tmp/aa", O_RDWR | O_CREAT | O_EXCL, 0600); 40 + int fd2 = open("/tmp/aa", O_RDONLY); 41 + 42 + unlink("/tmp/aa"); 43 + assert(fd != -1); 44 + assert(fd2 != -1); 45 + ksft_print_msg("[INFO] opened fds %i %i\n", fd, fd2); 46 + 47 + /* Set some read lock */ 48 + fl.l_type = F_RDLCK; 49 + fl.l_start = 5; 50 + fl.l_len = 3; 51 + rc = lock_set(fd, &fl); 52 + if (rc == 0) { 53 + ksft_print_msg 54 + ("[SUCCESS] set OFD read lock on first fd\n"); 55 + } else { 56 + ksft_print_msg("[FAIL] to set OFD read lock on first fd\n"); 57 + return -1; 58 + } 59 + /* Make sure read locks do not conflict on different fds. */ 60 + fl.l_type = F_RDLCK; 61 + fl.l_start = 5; 62 + fl.l_len = 1; 63 + rc = lock_get(fd2, &fl); 64 + if (rc != 0) 65 + return -1; 66 + if (fl.l_type != F_UNLCK) { 67 + ksft_print_msg("[FAIL] read locks conflicted\n"); 68 + return -1; 69 + } 70 + /* Make sure read/write locks do conflict on different fds. */ 71 + fl.l_type = F_WRLCK; 72 + fl.l_start = 5; 73 + fl.l_len = 1; 74 + rc = lock_get(fd2, &fl); 75 + if (rc != 0) 76 + return -1; 77 + if (fl.l_type != F_UNLCK) { 78 + ksft_print_msg 79 + ("[SUCCESS] read and write locks conflicted\n"); 80 + } else { 81 + ksft_print_msg 82 + ("[SUCCESS] read and write locks not conflicted\n"); 83 + return -1; 84 + } 85 + /* Get info about the lock on first fd. */ 86 + fl.l_type = F_UNLCK; 87 + fl.l_start = 5; 88 + fl.l_len = 1; 89 + rc = lock_get(fd, &fl); 90 + if (rc != 0) { 91 + ksft_print_msg 92 + ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n"); 93 + return -1; 94 + } 95 + if (fl.l_type != F_UNLCK) { 96 + ksft_print_msg 97 + ("[SUCCESS] F_UNLCK test returns: locked, type %i pid %i len %zi\n", 98 + fl.l_type, fl.l_pid, fl.l_len); 99 + } else { 100 + ksft_print_msg 101 + ("[FAIL] F_OFD_GETLK with F_UNLCK did not return lock info\n"); 102 + return -1; 103 + } 104 + /* Try the same but by locking everything by len==0. */ 105 + fl2.l_type = F_UNLCK; 106 + fl2.l_start = 0; 107 + fl2.l_len = 0; 108 + rc = lock_get(fd, &fl2); 109 + if (rc != 0) { 110 + ksft_print_msg 111 + ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n"); 112 + return -1; 113 + } 114 + if (memcmp(&fl, &fl2, sizeof(fl))) { 115 + ksft_print_msg 116 + ("[FAIL] F_UNLCK test returns: locked, type %i pid %i len %zi\n", 117 + fl.l_type, fl.l_pid, fl.l_len); 118 + return -1; 119 + } 120 + ksft_print_msg("[SUCCESS] F_UNLCK with len==0 returned the same\n"); 121 + /* Get info about the lock on second fd - no locks on it. */ 122 + fl.l_type = F_UNLCK; 123 + fl.l_start = 0; 124 + fl.l_len = 0; 125 + lock_get(fd2, &fl); 126 + if (fl.l_type != F_UNLCK) { 127 + ksft_print_msg 128 + ("[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n"); 129 + return -1; 130 + } 131 + return 0; 132 + }