xref: /linux/tools/testing/selftests/filelock/ofdlocks.c (revision 33d5b13098fb8db5ff120d4e2124c8b214696859)
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 		ksft_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 		ksft_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 	ksft_print_header();
43 	ksft_set_plan(4);
44 
45 	unlink("/tmp/aa");
46 	assert(fd != -1);
47 	assert(fd2 != -1);
48 	ksft_print_msg("opened fds %i %i\n", fd, fd2);
49 
50 	/* Set some read lock */
51 	fl.l_type = F_RDLCK;
52 	fl.l_start = 5;
53 	fl.l_len = 3;
54 	rc = lock_set(fd, &fl);
55 	ksft_test_result(rc == 0, "set OFD read lock on first fd\n");
56 	if (rc != 0)
57 		ksft_finished();
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 		ksft_finished();
66 	if (fl.l_type != F_UNLCK)
67 		ksft_exit_fail_msg("read locks conflicted\n");
68 
69 	/* Make sure read/write locks do conflict on different fds. */
70 	fl.l_type = F_WRLCK;
71 	fl.l_start = 5;
72 	fl.l_len = 1;
73 	rc = lock_get(fd2, &fl);
74 	if (rc != 0)
75 		ksft_finished();
76 	ksft_test_result(fl.l_type != F_UNLCK,
77 			 "read and write locks conflicted\n");
78 	if (fl.l_type == F_UNLCK)
79 		ksft_finished();
80 
81 	/* Get info about the lock on first fd. */
82 	fl.l_type = F_UNLCK;
83 	fl.l_start = 5;
84 	fl.l_len = 1;
85 	rc = lock_get(fd, &fl);
86 	if (rc != 0)
87 		ksft_exit_fail_msg("F_OFD_GETLK with F_UNLCK not supported\n");
88 	ksft_test_result(fl.l_type != F_UNLCK,
89 			 "F_OFD_GETLK with F_UNLCK returned lock info\n");
90 	if (fl.l_type == F_UNLCK)
91 		ksft_exit_fail();
92 	ksft_print_msg("F_UNLCK test returns: locked, type %i pid %i len %zi\n",
93 		       fl.l_type, fl.l_pid, fl.l_len);
94 
95 	/* Try the same but by locking everything by len==0. */
96 	fl2.l_type = F_UNLCK;
97 	fl2.l_start = 0;
98 	fl2.l_len = 0;
99 	rc = lock_get(fd, &fl2);
100 	if (rc != 0)
101 		ksft_exit_fail_msg
102 		    ("F_OFD_GETLK with F_UNLCK not supported\n");
103 	ksft_test_result(memcmp(&fl, &fl2, sizeof(fl)) == 0,
104 			 "F_UNLCK with len==0 returned the same\n");
105 	if (memcmp(&fl, &fl2, sizeof(fl))) {
106 		ksft_exit_fail_msg
107 		    ("F_UNLCK test returns: locked, type %i pid %i len %zi\n",
108 		     fl.l_type, fl.l_pid, fl.l_len);
109 	}
110 
111 	/* Get info about the lock on second fd - no locks on it. */
112 	fl.l_type = F_UNLCK;
113 	fl.l_start = 0;
114 	fl.l_len = 0;
115 	lock_get(fd2, &fl);
116 	ksft_test_result(fl.l_type == F_UNLCK,
117 			 "F_OFD_GETLK with F_UNLCK return lock info from another fd\n");
118 
119 	ksft_finished();
120 }
121