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
11static 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
23static 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
35int 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(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: &fl);
52 if (rc == 0) {
53 ksft_print_msg
54 (msg: "[SUCCESS] set OFD read lock on first fd\n");
55 } else {
56 ksft_print_msg(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(fd: fd2, fl: &fl);
64 if (rc != 0)
65 return -1;
66 if (fl.l_type != F_UNLCK) {
67 ksft_print_msg(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(fd: fd2, fl: &fl);
75 if (rc != 0)
76 return -1;
77 if (fl.l_type != F_UNLCK) {
78 ksft_print_msg
79 (msg: "[SUCCESS] read and write locks conflicted\n");
80 } else {
81 ksft_print_msg
82 (msg: "[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: &fl);
90 if (rc != 0) {
91 ksft_print_msg
92 (msg: "[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 (msg: "[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 (msg: "[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, fl: &fl2);
109 if (rc != 0) {
110 ksft_print_msg
111 (msg: "[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 (msg: "[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(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(fd: fd2, fl: &fl);
126 if (fl.l_type != F_UNLCK) {
127 ksft_print_msg
128 (msg: "[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n");
129 return -1;
130 }
131 return 0;
132}
133

source code of linux/tools/testing/selftests/filelock/ofdlocks.c