xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/fcntl/fcntl33.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2015 Fujitsu Ltd.
4*49cdfc7eSAndroid Build Coastguard Worker  * Author: Guangwen Feng <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker  */
6*49cdfc7eSAndroid Build Coastguard Worker 
7*49cdfc7eSAndroid Build Coastguard Worker /*
8*49cdfc7eSAndroid Build Coastguard Worker  * DESCRIPTION
9*49cdfc7eSAndroid Build Coastguard Worker  *  Test for feature F_SETLEASE of fcntl(2).
10*49cdfc7eSAndroid Build Coastguard Worker  *  "F_SETLEASE is used to establish a lease which provides a mechanism:
11*49cdfc7eSAndroid Build Coastguard Worker  *   When a process (the lease breaker) performs an open(2) or truncate(2)
12*49cdfc7eSAndroid Build Coastguard Worker  *   that conflicts with the lease, the system call will be blocked by
13*49cdfc7eSAndroid Build Coastguard Worker  *   kernel, meanwhile the kernel notifies the lease holder by sending
14*49cdfc7eSAndroid Build Coastguard Worker  *   it a signal (SIGIO by default), after the lease holder successes
15*49cdfc7eSAndroid Build Coastguard Worker  *   to downgrade or remove the lease, the kernel permits the system
16*49cdfc7eSAndroid Build Coastguard Worker  *   call of the lease breaker to proceed."
17*49cdfc7eSAndroid Build Coastguard Worker  */
18*49cdfc7eSAndroid Build Coastguard Worker 
19*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
20*49cdfc7eSAndroid Build Coastguard Worker 
21*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
22*49cdfc7eSAndroid Build Coastguard Worker #include "tst_timer.h"
23*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_macros.h"
24*49cdfc7eSAndroid Build Coastguard Worker 
25*49cdfc7eSAndroid Build Coastguard Worker /*
26*49cdfc7eSAndroid Build Coastguard Worker  * MIN_TIME_LIMIT is defined to 5 senconds as a minimal acceptable
27*49cdfc7eSAndroid Build Coastguard Worker  * amount of time for the lease breaker waiting for unblock via
28*49cdfc7eSAndroid Build Coastguard Worker  * lease holder voluntarily downgrade or remove the lease, if the
29*49cdfc7eSAndroid Build Coastguard Worker  * lease breaker is unblocked within MIN_TIME_LIMIT we may consider
30*49cdfc7eSAndroid Build Coastguard Worker  * that the feature of the lease mechanism works well.
31*49cdfc7eSAndroid Build Coastguard Worker  *
32*49cdfc7eSAndroid Build Coastguard Worker  * The lease-break-time is set to 45 seconds for timeout in kernel.
33*49cdfc7eSAndroid Build Coastguard Worker  */
34*49cdfc7eSAndroid Build Coastguard Worker #define MIN_TIME_LIMIT	5
35*49cdfc7eSAndroid Build Coastguard Worker 
36*49cdfc7eSAndroid Build Coastguard Worker #define OP_OPEN_RDONLY	0
37*49cdfc7eSAndroid Build Coastguard Worker #define OP_OPEN_WRONLY	1
38*49cdfc7eSAndroid Build Coastguard Worker #define OP_OPEN_RDWR	2
39*49cdfc7eSAndroid Build Coastguard Worker #define OP_TRUNCATE	3
40*49cdfc7eSAndroid Build Coastguard Worker 
41*49cdfc7eSAndroid Build Coastguard Worker #define FILE_MODE	(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID)
42*49cdfc7eSAndroid Build Coastguard Worker #define PATH_LS_BRK_T	"/proc/sys/fs/lease-break-time"
43*49cdfc7eSAndroid Build Coastguard Worker 
44*49cdfc7eSAndroid Build Coastguard Worker static void do_test(unsigned int);
45*49cdfc7eSAndroid Build Coastguard Worker static void do_child(unsigned int);
46*49cdfc7eSAndroid Build Coastguard Worker 
47*49cdfc7eSAndroid Build Coastguard Worker static int fd;
48*49cdfc7eSAndroid Build Coastguard Worker static int ls_brk_t;
49*49cdfc7eSAndroid Build Coastguard Worker static long type;
50*49cdfc7eSAndroid Build Coastguard Worker static sigset_t newset, oldset;
51*49cdfc7eSAndroid Build Coastguard Worker 
52*49cdfc7eSAndroid Build Coastguard Worker /* Time limit for lease holder to receive SIGIO. */
53*49cdfc7eSAndroid Build Coastguard Worker static struct timespec timeout = {.tv_sec = 5};
54*49cdfc7eSAndroid Build Coastguard Worker 
55*49cdfc7eSAndroid Build Coastguard Worker static struct test_case_t {
56*49cdfc7eSAndroid Build Coastguard Worker 	int lease_type;
57*49cdfc7eSAndroid Build Coastguard Worker 	int op_type;
58*49cdfc7eSAndroid Build Coastguard Worker 	char *desc;
59*49cdfc7eSAndroid Build Coastguard Worker } test_cases[] = {
60*49cdfc7eSAndroid Build Coastguard Worker 	{F_WRLCK, OP_OPEN_RDONLY,
61*49cdfc7eSAndroid Build Coastguard Worker 		"open(O_RDONLY) conflicts with fcntl(F_SETLEASE, F_WRLCK)"},
62*49cdfc7eSAndroid Build Coastguard Worker 	{F_WRLCK, OP_OPEN_WRONLY,
63*49cdfc7eSAndroid Build Coastguard Worker 		"open(O_WRONLY) conflicts with fcntl(F_SETLEASE, F_WRLCK)"},
64*49cdfc7eSAndroid Build Coastguard Worker 	{F_WRLCK, OP_OPEN_RDWR,
65*49cdfc7eSAndroid Build Coastguard Worker 		"open(O_RDWR) conflicts with fcntl(F_SETLEASE, F_WRLCK)"},
66*49cdfc7eSAndroid Build Coastguard Worker 	{F_WRLCK, OP_TRUNCATE,
67*49cdfc7eSAndroid Build Coastguard Worker 		"truncate() conflicts with fcntl(F_SETLEASE, F_WRLCK)"},
68*49cdfc7eSAndroid Build Coastguard Worker 	{F_RDLCK, OP_OPEN_WRONLY,
69*49cdfc7eSAndroid Build Coastguard Worker 		"open(O_WRONLY) conflicts with fcntl(F_SETLEASE, F_RDLCK)"},
70*49cdfc7eSAndroid Build Coastguard Worker 	{F_RDLCK, OP_OPEN_RDWR,
71*49cdfc7eSAndroid Build Coastguard Worker 		"open(O_RDWR) conflicts with fcntl(F_SETLEASE, F_RDLCK)"},
72*49cdfc7eSAndroid Build Coastguard Worker 	{F_RDLCK, OP_TRUNCATE,
73*49cdfc7eSAndroid Build Coastguard Worker 		"truncate() conflicts with fcntl(F_SETLEASE, F_RDLCK)"},
74*49cdfc7eSAndroid Build Coastguard Worker };
75*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)76*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
77*49cdfc7eSAndroid Build Coastguard Worker {
78*49cdfc7eSAndroid Build Coastguard Worker 	tst_timer_check(CLOCK_MONOTONIC);
79*49cdfc7eSAndroid Build Coastguard Worker 
80*49cdfc7eSAndroid Build Coastguard Worker 	/* Backup and set the lease-break-time. */
81*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF(PATH_LS_BRK_T, "%d", &ls_brk_t);
82*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_PRINTF(PATH_LS_BRK_T, "%d", 45);
83*49cdfc7eSAndroid Build Coastguard Worker 
84*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_TOUCH("file", FILE_MODE, NULL);
85*49cdfc7eSAndroid Build Coastguard Worker 
86*49cdfc7eSAndroid Build Coastguard Worker 	sigemptyset(&newset);
87*49cdfc7eSAndroid Build Coastguard Worker 	sigaddset(&newset, SIGIO);
88*49cdfc7eSAndroid Build Coastguard Worker 
89*49cdfc7eSAndroid Build Coastguard Worker 	if (sigprocmask(SIG_SETMASK, &newset, &oldset) < 0)
90*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "sigprocmask() failed");
91*49cdfc7eSAndroid Build Coastguard Worker }
92*49cdfc7eSAndroid Build Coastguard Worker 
do_test(unsigned int i)93*49cdfc7eSAndroid Build Coastguard Worker static void do_test(unsigned int i)
94*49cdfc7eSAndroid Build Coastguard Worker {
95*49cdfc7eSAndroid Build Coastguard Worker 	pid_t cpid;
96*49cdfc7eSAndroid Build Coastguard Worker 
97*49cdfc7eSAndroid Build Coastguard Worker 	cpid = SAFE_FORK();
98*49cdfc7eSAndroid Build Coastguard Worker 	if (cpid == 0) {
99*49cdfc7eSAndroid Build Coastguard Worker 		do_child(i);
100*49cdfc7eSAndroid Build Coastguard Worker 		return;
101*49cdfc7eSAndroid Build Coastguard Worker 	}
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker 	fd = SAFE_OPEN("file", O_RDONLY);
104*49cdfc7eSAndroid Build Coastguard Worker 
105*49cdfc7eSAndroid Build Coastguard Worker 	TEST(fcntl(fd, F_SETLEASE, test_cases[i].lease_type));
106*49cdfc7eSAndroid Build Coastguard Worker 	if (TST_RET == -1) {
107*49cdfc7eSAndroid Build Coastguard Worker 		if (type == TST_OVERLAYFS_MAGIC && TST_ERR == EAGAIN) {
108*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TINFO | TTERRNO,
109*49cdfc7eSAndroid Build Coastguard Worker 				"fcntl(F_SETLEASE, F_WRLCK) failed on overlayfs as expected");
110*49cdfc7eSAndroid Build Coastguard Worker 		} else {
111*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL | TTERRNO, "fcntl() failed to set lease");
112*49cdfc7eSAndroid Build Coastguard Worker 		}
113*49cdfc7eSAndroid Build Coastguard Worker 		TST_CHECKPOINT_WAKE(0);
114*49cdfc7eSAndroid Build Coastguard Worker 		goto exit;
115*49cdfc7eSAndroid Build Coastguard Worker 	}
116*49cdfc7eSAndroid Build Coastguard Worker 
117*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE(0);
118*49cdfc7eSAndroid Build Coastguard Worker 	/* Wait for SIGIO caused by lease breaker. */
119*49cdfc7eSAndroid Build Coastguard Worker 	TEST(sigtimedwait(&newset, NULL, &timeout));
120*49cdfc7eSAndroid Build Coastguard Worker 	if (TST_RET == -1) {
121*49cdfc7eSAndroid Build Coastguard Worker 		if (TST_ERR == EAGAIN) {
122*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL | TTERRNO,
123*49cdfc7eSAndroid Build Coastguard Worker 				"failed to receive SIGIO within %lis",
124*49cdfc7eSAndroid Build Coastguard Worker 				timeout.tv_sec);
125*49cdfc7eSAndroid Build Coastguard Worker 			goto exit;
126*49cdfc7eSAndroid Build Coastguard Worker 		}
127*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TTERRNO, "sigtimedwait() failed");
128*49cdfc7eSAndroid Build Coastguard Worker 	}
129*49cdfc7eSAndroid Build Coastguard Worker 
130*49cdfc7eSAndroid Build Coastguard Worker 	/* Try to downgrade or remove the lease. */
131*49cdfc7eSAndroid Build Coastguard Worker 	switch (test_cases[i].lease_type) {
132*49cdfc7eSAndroid Build Coastguard Worker 	case F_WRLCK:
133*49cdfc7eSAndroid Build Coastguard Worker 		TEST(fcntl(fd, F_SETLEASE, F_RDLCK));
134*49cdfc7eSAndroid Build Coastguard Worker 		if (TST_RET == 0) {
135*49cdfc7eSAndroid Build Coastguard Worker 			if (test_cases[i].op_type == OP_OPEN_RDONLY)
136*49cdfc7eSAndroid Build Coastguard Worker 				break;
137*49cdfc7eSAndroid Build Coastguard Worker 
138*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL,
139*49cdfc7eSAndroid Build Coastguard Worker 				"fcntl() downgraded lease when not read-only");
140*49cdfc7eSAndroid Build Coastguard Worker 		}
141*49cdfc7eSAndroid Build Coastguard Worker 
142*49cdfc7eSAndroid Build Coastguard Worker 		if (test_cases[i].op_type == OP_OPEN_RDONLY) {
143*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL | TTERRNO,
144*49cdfc7eSAndroid Build Coastguard Worker 				"fcntl() failed to downgrade lease");
145*49cdfc7eSAndroid Build Coastguard Worker 		}
146*49cdfc7eSAndroid Build Coastguard Worker 
147*49cdfc7eSAndroid Build Coastguard Worker 		/* Falls through */
148*49cdfc7eSAndroid Build Coastguard Worker 	case F_RDLCK:
149*49cdfc7eSAndroid Build Coastguard Worker 		TEST(fcntl(fd, F_SETLEASE, F_UNLCK));
150*49cdfc7eSAndroid Build Coastguard Worker 		if (TST_RET == -1) {
151*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL | TTERRNO,
152*49cdfc7eSAndroid Build Coastguard Worker 				 "fcntl() failed to remove the lease");
153*49cdfc7eSAndroid Build Coastguard Worker 		}
154*49cdfc7eSAndroid Build Coastguard Worker 		break;
155*49cdfc7eSAndroid Build Coastguard Worker 	default:
156*49cdfc7eSAndroid Build Coastguard Worker 		break;
157*49cdfc7eSAndroid Build Coastguard Worker 	}
158*49cdfc7eSAndroid Build Coastguard Worker 
159*49cdfc7eSAndroid Build Coastguard Worker exit:
160*49cdfc7eSAndroid Build Coastguard Worker 	tst_reap_children();
161*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd);
162*49cdfc7eSAndroid Build Coastguard Worker }
163*49cdfc7eSAndroid Build Coastguard Worker 
do_child(unsigned int i)164*49cdfc7eSAndroid Build Coastguard Worker static void do_child(unsigned int i)
165*49cdfc7eSAndroid Build Coastguard Worker {
166*49cdfc7eSAndroid Build Coastguard Worker 	long long elapsed_ms;
167*49cdfc7eSAndroid Build Coastguard Worker 
168*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAIT(0);
169*49cdfc7eSAndroid Build Coastguard Worker 
170*49cdfc7eSAndroid Build Coastguard Worker 	tst_timer_start(CLOCK_MONOTONIC);
171*49cdfc7eSAndroid Build Coastguard Worker 
172*49cdfc7eSAndroid Build Coastguard Worker 	switch (test_cases[i].op_type) {
173*49cdfc7eSAndroid Build Coastguard Worker 	case OP_OPEN_RDONLY:
174*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_OPEN("file", O_RDONLY);
175*49cdfc7eSAndroid Build Coastguard Worker 		break;
176*49cdfc7eSAndroid Build Coastguard Worker 	case OP_OPEN_WRONLY:
177*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_OPEN("file", O_WRONLY);
178*49cdfc7eSAndroid Build Coastguard Worker 		break;
179*49cdfc7eSAndroid Build Coastguard Worker 	case OP_OPEN_RDWR:
180*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_OPEN("file", O_RDWR);
181*49cdfc7eSAndroid Build Coastguard Worker 		break;
182*49cdfc7eSAndroid Build Coastguard Worker 	case OP_TRUNCATE:
183*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_TRUNCATE("file", 0);
184*49cdfc7eSAndroid Build Coastguard Worker 		break;
185*49cdfc7eSAndroid Build Coastguard Worker 	default:
186*49cdfc7eSAndroid Build Coastguard Worker 		break;
187*49cdfc7eSAndroid Build Coastguard Worker 	}
188*49cdfc7eSAndroid Build Coastguard Worker 
189*49cdfc7eSAndroid Build Coastguard Worker 	tst_timer_stop();
190*49cdfc7eSAndroid Build Coastguard Worker 
191*49cdfc7eSAndroid Build Coastguard Worker 	elapsed_ms = tst_timer_elapsed_ms();
192*49cdfc7eSAndroid Build Coastguard Worker 
193*49cdfc7eSAndroid Build Coastguard Worker 	if (elapsed_ms < MIN_TIME_LIMIT * 1000) {
194*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "%s, unblocked within %ds",
195*49cdfc7eSAndroid Build Coastguard Worker 			 test_cases[i].desc, MIN_TIME_LIMIT);
196*49cdfc7eSAndroid Build Coastguard Worker 	} else {
197*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL,
198*49cdfc7eSAndroid Build Coastguard Worker 			"%s, blocked too long %llims, expected within %ds",
199*49cdfc7eSAndroid Build Coastguard Worker 			test_cases[i].desc, elapsed_ms, MIN_TIME_LIMIT);
200*49cdfc7eSAndroid Build Coastguard Worker 	}
201*49cdfc7eSAndroid Build Coastguard Worker }
202*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)203*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
204*49cdfc7eSAndroid Build Coastguard Worker {
205*49cdfc7eSAndroid Build Coastguard Worker 	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
206*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TWARN | TERRNO, "sigprocmask restore oldset failed");
207*49cdfc7eSAndroid Build Coastguard Worker 
208*49cdfc7eSAndroid Build Coastguard Worker 	if (fd > 0)
209*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
210*49cdfc7eSAndroid Build Coastguard Worker 
211*49cdfc7eSAndroid Build Coastguard Worker 	/* Restore the lease-break-time. */
212*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t);
213*49cdfc7eSAndroid Build Coastguard Worker }
214*49cdfc7eSAndroid Build Coastguard Worker 
215*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
216*49cdfc7eSAndroid Build Coastguard Worker 	.forks_child = 1,
217*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
218*49cdfc7eSAndroid Build Coastguard Worker 	.needs_checkpoints = 1,
219*49cdfc7eSAndroid Build Coastguard Worker 	.tcnt = ARRAY_SIZE(test_cases),
220*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
221*49cdfc7eSAndroid Build Coastguard Worker 	.test = do_test,
222*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
223*49cdfc7eSAndroid Build Coastguard Worker 	.skip_filesystems = (const char *const []) {
224*49cdfc7eSAndroid Build Coastguard Worker 		"tmpfs",
225*49cdfc7eSAndroid Build Coastguard Worker 		"ramfs",
226*49cdfc7eSAndroid Build Coastguard Worker 		"nfs",
227*49cdfc7eSAndroid Build Coastguard Worker 		NULL
228*49cdfc7eSAndroid Build Coastguard Worker 	},
229*49cdfc7eSAndroid Build Coastguard Worker };
230