xref: /illumos-gate/usr/src/test/nvme-tests/tests/ioctl/multi-reader-lock.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
1*533affcbSRobert Mustacchi /*
2*533affcbSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*533affcbSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*533affcbSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*533affcbSRobert Mustacchi  * 1.0 of the CDDL.
6*533affcbSRobert Mustacchi  *
7*533affcbSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*533affcbSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*533affcbSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*533affcbSRobert Mustacchi  */
11*533affcbSRobert Mustacchi 
12*533affcbSRobert Mustacchi /*
13*533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*533affcbSRobert Mustacchi  */
15*533affcbSRobert Mustacchi 
16*533affcbSRobert Mustacchi /*
17*533affcbSRobert Mustacchi  * The purpose of this test is to verify that multiple readers can all grab the
18*533affcbSRobert Mustacchi  * same lock. In this case, we will use a mix of namespace and controller locks,
19*533affcbSRobert Mustacchi  * but only one lock per fd. Specifically we want to ensure that all three of
20*533affcbSRobert Mustacchi  * these classes can simultaneously hold the lock:
21*533affcbSRobert Mustacchi  *
22*533affcbSRobert Mustacchi  * o Controller fd, controller lock
23*533affcbSRobert Mustacchi  * o Controller fd, namespace lock
24*533affcbSRobert Mustacchi  * o Namespace fd, namespace lock
25*533affcbSRobert Mustacchi  *
26*533affcbSRobert Mustacchi  * This also is testing that multiple instances of the same type can hold the fd
27*533affcbSRobert Mustacchi  * as well. In addition, We want to ensure that this happens regardless of
28*533affcbSRobert Mustacchi  * whomever does the first lock. In particular we want to test the following
29*533affcbSRobert Mustacchi  * orders:
30*533affcbSRobert Mustacchi  *
31*533affcbSRobert Mustacchi  * 1) All controller read locks, then all ctrl ns, then all ns
32*533affcbSRobert Mustacchi  * 2) All ns fd read locks, then all ctrl fd ns locks, then all ctrl ctrl
33*533affcbSRobert Mustacchi  * 3) All ctrl fd ns locks, then all ctrl ctrl locks, then all ns fd
34*533affcbSRobert Mustacchi  *
35*533affcbSRobert Mustacchi  * Then we repeat the above but swizzling with one fd from each.
36*533affcbSRobert Mustacchi  */
37*533affcbSRobert Mustacchi 
38*533affcbSRobert Mustacchi #include <err.h>
39*533affcbSRobert Mustacchi #include <stdlib.h>
40*533affcbSRobert Mustacchi #include <string.h>
41*533affcbSRobert Mustacchi #include <unistd.h>
42*533affcbSRobert Mustacchi #include <stdbool.h>
43*533affcbSRobert Mustacchi 
44*533affcbSRobert Mustacchi #include "nvme_ioctl_util.h"
45*533affcbSRobert Mustacchi 
46*533affcbSRobert Mustacchi /*
47*533affcbSRobert Mustacchi  * Number of readers of each type.
48*533affcbSRobert Mustacchi  */
49*533affcbSRobert Mustacchi #define	NREADERS	10
50*533affcbSRobert Mustacchi 
51*533affcbSRobert Mustacchi static bool
multi_lock_one(int fd,const nvme_ioctl_lock_t * tmpl,const char * desc,size_t iter)52*533affcbSRobert Mustacchi multi_lock_one(int fd, const nvme_ioctl_lock_t *tmpl, const char *desc,
53*533affcbSRobert Mustacchi     size_t iter)
54*533affcbSRobert Mustacchi {
55*533affcbSRobert Mustacchi 	nvme_ioctl_lock_t lock = *tmpl;
56*533affcbSRobert Mustacchi 
57*533affcbSRobert Mustacchi 	if (ioctl(fd, NVME_IOC_LOCK, &lock) != 0) {
58*533affcbSRobert Mustacchi 		warn("TEST FAILED: %s %zu: failed to issue lock ioctl",
59*533affcbSRobert Mustacchi 		    desc, iter);
60*533affcbSRobert Mustacchi 		return (false);
61*533affcbSRobert Mustacchi 	} else if (lock.nil_common.nioc_drv_err != NVME_IOCTL_E_OK) {
62*533affcbSRobert Mustacchi 		warnx("TEST FAILED: %s %zu: lock ioctl failed with driver "
63*533affcbSRobert Mustacchi 		    "error 0x%x", desc, iter, lock.nil_common.nioc_drv_err);
64*533affcbSRobert Mustacchi 		return (false);
65*533affcbSRobert Mustacchi 	} else {
66*533affcbSRobert Mustacchi 		return (true);
67*533affcbSRobert Mustacchi 	}
68*533affcbSRobert Mustacchi }
69*533affcbSRobert Mustacchi 
70*533affcbSRobert Mustacchi static bool
multi_unlock_one(int fd,const nvme_ioctl_unlock_t * tmpl,const char * desc,size_t iter)71*533affcbSRobert Mustacchi multi_unlock_one(int fd, const nvme_ioctl_unlock_t *tmpl, const char *desc,
72*533affcbSRobert Mustacchi     size_t iter)
73*533affcbSRobert Mustacchi {
74*533affcbSRobert Mustacchi 	nvme_ioctl_unlock_t unlock = *tmpl;
75*533affcbSRobert Mustacchi 	if (ioctl(fd, NVME_IOC_UNLOCK, &unlock) != 0) {
76*533affcbSRobert Mustacchi 		warn("TEST FAILED: %s %zu: failed to issue unlock ioctl",
77*533affcbSRobert Mustacchi 		    desc, iter);
78*533affcbSRobert Mustacchi 		return (false);
79*533affcbSRobert Mustacchi 	} else if (unlock.niu_common.nioc_drv_err != NVME_IOCTL_E_OK) {
80*533affcbSRobert Mustacchi 		warnx("TEST FAILED: %s %zu: unlock ioctl failed with driver "
81*533affcbSRobert Mustacchi 		    "error 0x%x", desc, iter, unlock.niu_common.nioc_drv_err);
82*533affcbSRobert Mustacchi 		return (false);
83*533affcbSRobert Mustacchi 	} else {
84*533affcbSRobert Mustacchi 		return (true);
85*533affcbSRobert Mustacchi 	}
86*533affcbSRobert Mustacchi }
87*533affcbSRobert Mustacchi 
88*533affcbSRobert Mustacchi static bool
multi_unlock_all(int ctrl_ctrl[NREADERS],int ctrl_ns[NREADERS],int ns_ns[NREADERS])89*533affcbSRobert Mustacchi multi_unlock_all(int ctrl_ctrl[NREADERS], int ctrl_ns[NREADERS],
90*533affcbSRobert Mustacchi     int ns_ns[NREADERS])
91*533affcbSRobert Mustacchi {
92*533affcbSRobert Mustacchi 	bool ret = true;
93*533affcbSRobert Mustacchi 	for (uint32_t i = 0; i < NREADERS; i++) {
94*533affcbSRobert Mustacchi 		if (!multi_unlock_one(ctrl_ctrl[i], &nvme_test_ctrl_unlock,
95*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
96*533affcbSRobert Mustacchi 			ret = false;
97*533affcbSRobert Mustacchi 		}
98*533affcbSRobert Mustacchi 
99*533affcbSRobert Mustacchi 		if (!multi_unlock_one(ctrl_ns[i], &nvme_test_ns_unlock,
100*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
101*533affcbSRobert Mustacchi 			ret = false;
102*533affcbSRobert Mustacchi 		}
103*533affcbSRobert Mustacchi 
104*533affcbSRobert Mustacchi 		if (!multi_unlock_one(ns_ns[i], &nvme_test_ns_unlock,
105*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
106*533affcbSRobert Mustacchi 			ret = false;
107*533affcbSRobert Mustacchi 		}
108*533affcbSRobert Mustacchi 	}
109*533affcbSRobert Mustacchi 
110*533affcbSRobert Mustacchi 	return (ret);
111*533affcbSRobert Mustacchi }
112*533affcbSRobert Mustacchi 
113*533affcbSRobert Mustacchi int
main(void)114*533affcbSRobert Mustacchi main(void)
115*533affcbSRobert Mustacchi {
116*533affcbSRobert Mustacchi 	int ret = EXIT_SUCCESS;
117*533affcbSRobert Mustacchi 	int ctrl_ctrl[NREADERS];
118*533affcbSRobert Mustacchi 	int ctrl_ns[NREADERS];
119*533affcbSRobert Mustacchi 	int ns_ns[NREADERS];
120*533affcbSRobert Mustacchi 	bool test;
121*533affcbSRobert Mustacchi 
122*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
123*533affcbSRobert Mustacchi 		ctrl_ctrl[i] = nvme_ioctl_test_get_fd(0);
124*533affcbSRobert Mustacchi 		ctrl_ns[i] = nvme_ioctl_test_get_fd(0);
125*533affcbSRobert Mustacchi 		ns_ns[i] = nvme_ioctl_test_get_fd(1);
126*533affcbSRobert Mustacchi 	}
127*533affcbSRobert Mustacchi 
128*533affcbSRobert Mustacchi 	/*
129*533affcbSRobert Mustacchi 	 * Order 1
130*533affcbSRobert Mustacchi 	 */
131*533affcbSRobert Mustacchi 	test = true;
132*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
133*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
134*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
135*533affcbSRobert Mustacchi 			test = false;
136*533affcbSRobert Mustacchi 		}
137*533affcbSRobert Mustacchi 	}
138*533affcbSRobert Mustacchi 
139*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
140*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
141*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
142*533affcbSRobert Mustacchi 			test = false;
143*533affcbSRobert Mustacchi 		}
144*533affcbSRobert Mustacchi 	}
145*533affcbSRobert Mustacchi 
146*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
147*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
148*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
149*533affcbSRobert Mustacchi 			test = false;
150*533affcbSRobert Mustacchi 		}
151*533affcbSRobert Mustacchi 	}
152*533affcbSRobert Mustacchi 
153*533affcbSRobert Mustacchi 	if (test) {
154*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: order 1\n");
155*533affcbSRobert Mustacchi 	} else {
156*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
157*533affcbSRobert Mustacchi 		    "order 1");
158*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
159*533affcbSRobert Mustacchi 	}
160*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
161*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
162*533affcbSRobert Mustacchi 	}
163*533affcbSRobert Mustacchi 
164*533affcbSRobert Mustacchi 	/*
165*533affcbSRobert Mustacchi 	 * Order 2
166*533affcbSRobert Mustacchi 	 */
167*533affcbSRobert Mustacchi 	test = true;
168*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
169*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
170*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
171*533affcbSRobert Mustacchi 			test = false;
172*533affcbSRobert Mustacchi 		}
173*533affcbSRobert Mustacchi 	}
174*533affcbSRobert Mustacchi 
175*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
176*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
177*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
178*533affcbSRobert Mustacchi 			test = false;
179*533affcbSRobert Mustacchi 		}
180*533affcbSRobert Mustacchi 	}
181*533affcbSRobert Mustacchi 
182*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
183*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
184*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
185*533affcbSRobert Mustacchi 			test = false;
186*533affcbSRobert Mustacchi 		}
187*533affcbSRobert Mustacchi 	}
188*533affcbSRobert Mustacchi 
189*533affcbSRobert Mustacchi 	if (test) {
190*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: order 2\n");
191*533affcbSRobert Mustacchi 	} else {
192*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
193*533affcbSRobert Mustacchi 		    "order 2");
194*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
195*533affcbSRobert Mustacchi 	}
196*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
197*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
198*533affcbSRobert Mustacchi 	}
199*533affcbSRobert Mustacchi 
200*533affcbSRobert Mustacchi 	/*
201*533affcbSRobert Mustacchi 	 * Order 3
202*533affcbSRobert Mustacchi 	 */
203*533affcbSRobert Mustacchi 	test = true;
204*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
205*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
206*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
207*533affcbSRobert Mustacchi 			test = false;
208*533affcbSRobert Mustacchi 		}
209*533affcbSRobert Mustacchi 	}
210*533affcbSRobert Mustacchi 
211*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
212*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
213*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
214*533affcbSRobert Mustacchi 			test = false;
215*533affcbSRobert Mustacchi 		}
216*533affcbSRobert Mustacchi 	}
217*533affcbSRobert Mustacchi 
218*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
219*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
220*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
221*533affcbSRobert Mustacchi 			test = false;
222*533affcbSRobert Mustacchi 		}
223*533affcbSRobert Mustacchi 	}
224*533affcbSRobert Mustacchi 
225*533affcbSRobert Mustacchi 	if (test) {
226*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: order 3\n");
227*533affcbSRobert Mustacchi 	} else {
228*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
229*533affcbSRobert Mustacchi 		    "order 3");
230*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
231*533affcbSRobert Mustacchi 	}
232*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
233*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
234*533affcbSRobert Mustacchi 	}
235*533affcbSRobert Mustacchi 	/*
236*533affcbSRobert Mustacchi 	 * Swizzle 1.
237*533affcbSRobert Mustacchi 	 */
238*533affcbSRobert Mustacchi 	test = true;
239*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
240*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
241*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
242*533affcbSRobert Mustacchi 			test = false;
243*533affcbSRobert Mustacchi 		}
244*533affcbSRobert Mustacchi 
245*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
246*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
247*533affcbSRobert Mustacchi 			test = false;
248*533affcbSRobert Mustacchi 		}
249*533affcbSRobert Mustacchi 
250*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
251*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
252*533affcbSRobert Mustacchi 			test = false;
253*533affcbSRobert Mustacchi 		}
254*533affcbSRobert Mustacchi 	}
255*533affcbSRobert Mustacchi 
256*533affcbSRobert Mustacchi 	if (test) {
257*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: swizzle 1\n");
258*533affcbSRobert Mustacchi 	} else {
259*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
260*533affcbSRobert Mustacchi 		    "swizzle 1");
261*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
262*533affcbSRobert Mustacchi 	}
263*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
264*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
265*533affcbSRobert Mustacchi 	}
266*533affcbSRobert Mustacchi 
267*533affcbSRobert Mustacchi 	/*
268*533affcbSRobert Mustacchi 	 * Swizzle 2.
269*533affcbSRobert Mustacchi 	 */
270*533affcbSRobert Mustacchi 	test = true;
271*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
272*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
273*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
274*533affcbSRobert Mustacchi 			test = false;
275*533affcbSRobert Mustacchi 		}
276*533affcbSRobert Mustacchi 
277*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
278*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
279*533affcbSRobert Mustacchi 			test = false;
280*533affcbSRobert Mustacchi 		}
281*533affcbSRobert Mustacchi 
282*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
283*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
284*533affcbSRobert Mustacchi 			test = false;
285*533affcbSRobert Mustacchi 		}
286*533affcbSRobert Mustacchi 	}
287*533affcbSRobert Mustacchi 
288*533affcbSRobert Mustacchi 	if (test) {
289*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: swizzle 2\n");
290*533affcbSRobert Mustacchi 	} else {
291*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
292*533affcbSRobert Mustacchi 		    "swizzle 2");
293*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
294*533affcbSRobert Mustacchi 	}
295*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
296*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
297*533affcbSRobert Mustacchi 	}
298*533affcbSRobert Mustacchi 
299*533affcbSRobert Mustacchi 	/*
300*533affcbSRobert Mustacchi 	 * Swizzle 3.
301*533affcbSRobert Mustacchi 	 */
302*533affcbSRobert Mustacchi 	test = true;
303*533affcbSRobert Mustacchi 	for (size_t i = 0; i < NREADERS; i++) {
304*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ns[i], &nvme_test_ns_rdlock,
305*533affcbSRobert Mustacchi 		    "ctrl fd ns lock", i)) {
306*533affcbSRobert Mustacchi 			test = false;
307*533affcbSRobert Mustacchi 		}
308*533affcbSRobert Mustacchi 
309*533affcbSRobert Mustacchi 		if (!multi_lock_one(ns_ns[i], &nvme_test_ns_rdlock,
310*533affcbSRobert Mustacchi 		    "ns fd ns lock", i)) {
311*533affcbSRobert Mustacchi 			test = false;
312*533affcbSRobert Mustacchi 		}
313*533affcbSRobert Mustacchi 
314*533affcbSRobert Mustacchi 		if (!multi_lock_one(ctrl_ctrl[i], &nvme_test_ctrl_rdlock,
315*533affcbSRobert Mustacchi 		    "ctrl fd ctrl lock", i)) {
316*533affcbSRobert Mustacchi 			test = false;
317*533affcbSRobert Mustacchi 		}
318*533affcbSRobert Mustacchi 	}
319*533affcbSRobert Mustacchi 
320*533affcbSRobert Mustacchi 	if (test) {
321*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: all read locks taken: swizzle 3\n");
322*533affcbSRobert Mustacchi 	} else {
323*533affcbSRobert Mustacchi 		warnx("TEST FAILED: failed to take all read locks following "
324*533affcbSRobert Mustacchi 		    "swizzle 3");
325*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
326*533affcbSRobert Mustacchi 	}
327*533affcbSRobert Mustacchi 	if (!multi_unlock_all(ctrl_ctrl, ctrl_ns, ns_ns)) {
328*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
329*533affcbSRobert Mustacchi 	}
330*533affcbSRobert Mustacchi 
331*533affcbSRobert Mustacchi 	return (ret);
332*533affcbSRobert Mustacchi }
333