xref: /src/sys/contrib/openzfs/tests/zfs-tests/cmd/setlease.c (revision 8a62a2a5659d1839d8799b4274c04469d7f17c78)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright (c) 2026, TrueNAS.
25  */
26 
27 /*
28  * This is a sanity check test for the F_SETLEASE and F_GETLEASE fcntl() calls.
29  * We use the generic kernel implementation, but we want to be alerted if it
30  * ever breaks.
31  *
32  * This is not a comprehensive test. It would be nice if it could be!
33  */
34 
35 #ifndef _GNU_SOURCE
36 #define	_GNU_SOURCE
37 #endif
38 
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <string.h>
45 
46 static int
get_lease(int fd)47 get_lease(int fd) {
48 	int r = fcntl(fd, F_GETLEASE);
49 	if (r < 0) {
50 		perror("fcntl(GETLEASE)");
51 		exit(2);
52 	}
53 	return (r);
54 }
55 
56 static int
set_lease(int fd,int lease)57 set_lease(int fd, int lease) {
58 	return (fcntl(fd, F_SETLEASE, lease) < 0 ? errno : 0);
59 }
60 
61 static const char *lease_str[] = {
62 	[F_RDLCK] = "RDLCK",
63 	[F_WRLCK] = "WRLCK",
64 	[F_UNLCK] = "UNLCK",
65 };
66 
67 static void
assert_lease(int fd,int expect)68 assert_lease(int fd, int expect) {
69 	int got = get_lease(fd);
70 	if (got != expect) {
71 		fprintf(stderr, "ASSERT_LEASE: expected %s [%d], got %s [%d]\n",
72 		    lease_str[expect], expect, lease_str[got], got);
73 		abort();
74 	}
75 	printf("ok: lease is %s\n", lease_str[got]);
76 }
77 
78 static void
assert_set_lease(int fd,int lease)79 assert_set_lease(int fd, int lease) {
80 	int err = set_lease(fd, lease);
81 	if (err != 0) {
82 		fprintf(stderr, "ASSERT_SET_LEASE: tried %s [%d], error: %s\n",
83 		    lease_str[lease], lease, strerror(err));
84 		abort();
85 	}
86 	printf("ok: set lease to %s\n", lease_str[lease]);
87 }
88 
89 int
main(int argc,char ** argv)90 main(int argc, char **argv)
91 {
92 	if (argc != 2) {
93 		fprintf(stderr, "usage: %s <filename>\n", argv[0]);
94 		exit(1);
95 	}
96 
97 	/* create and open file, read+write */
98 	int fd = open(argv[1], O_CREAT|O_RDONLY, S_IRWXU|S_IRWXG|S_IRWXO);
99 	if (fd < 0) {
100 		perror("open");
101 		exit(2);
102 	}
103 	printf("ok: opened file RDONLY\n");
104 
105 	/* fd starts with no lease */
106 	assert_lease(fd, F_UNLCK);
107 
108 	/* fd is readonly, so can take read lease */
109 	assert_set_lease(fd, F_RDLCK);
110 	/* confirm read lease */
111 	assert_lease(fd, F_RDLCK);
112 
113 	/* no other openers, so can take write lease */
114 	assert_set_lease(fd, F_WRLCK);
115 	/* confirm write lease */
116 	assert_lease(fd, F_WRLCK);
117 
118 	/* release lease */
119 	assert_set_lease(fd, F_UNLCK);
120 	/* confirm lease released */
121 	assert_lease(fd, F_UNLCK);
122 
123 	close(fd);
124 
125 	return (0);
126 }
127