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