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