1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2024 Oxide Computer Company
14 */
15
16 /*
17 * Test various lock scenarios that should always result in an error. This
18 * includes:
19 *
20 * o Invalid unknown entities on lock and unlock
21 * o Invalid lock levels
22 * o Invalid lock flags
23 * o Namespace fds trying to do anything with the controller lock
24 *
25 * Then test various unlock scenarios that should always result in an error:
26 * o Asking to unlock when you don't hold a lock
27 * o Asking to unlock the wrong lock type when you hold the opposite lock
28 * (controller only)
29 * o Asking to unlock the controller lock on a ns fd
30 *
31 * The following aren't currently tested because we don't have tests that
32 * currently distinguish between whether or not we have multiple namespaces.
33 *
34 * o Asking to unlock a namespace that isn't the one you have locked
35 * (controller only)
36 */
37
38 #include <err.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42 #include <sys/sysmacros.h>
43 #include <sys/debug.h>
44
45 #include "nvme_ioctl_util.h"
46
47 typedef struct {
48 const char *blt_desc;
49 nvme_ioctl_lock_t blt_lock;
50 nvme_ioctl_errno_t blt_err;
51 } bad_lock_test_t;
52
53 typedef struct {
54 const char *but_desc;
55 nvme_ioctl_unlock_t but_unlock;
56 nvme_ioctl_errno_t but_err;
57 } bad_unlock_test_t;
58
59 static const bad_lock_test_t bad_lock_tests_com[] = { {
60 .blt_desc = "bad lock entity (1)",
61 .blt_lock = { .nil_ent = 0, .nil_level = NVME_LOCK_L_READ },
62 .blt_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
63 }, {
64 .blt_desc = "bad lock entity (2)",
65 .blt_lock = { .nil_ent = 0x23, .nil_level = NVME_LOCK_L_READ },
66 .blt_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
67 }, {
68 .blt_desc = "bad lock entity (3)",
69 .blt_lock = { .nil_ent = INT32_MAX, .nil_level = NVME_LOCK_L_READ },
70 .blt_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
71 } };
72
73 static const bad_lock_test_t bad_lock_tests_ctrl[] = { {
74 .blt_desc = "bad lock level (1)",
75 .blt_lock = { .nil_ent = NVME_LOCK_E_CTRL, .nil_level = 0 },
76 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
77 }, {
78 .blt_desc = "bad lock level (2)",
79 .blt_lock = { .nil_ent = NVME_LOCK_E_CTRL, .nil_level = 7 },
80 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
81 }, {
82 .blt_desc = "bad lock level (3)",
83 .blt_lock = { .nil_ent = NVME_LOCK_E_CTRL, .nil_level = UINT32_MAX },
84 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
85 }, {
86 .blt_desc = "bad lock level on ns (1)",
87 .blt_lock = {
88 .nil_common = { .nioc_nsid = 1 },
89 .nil_ent = NVME_LOCK_E_NS,
90 .nil_level = 0
91 },
92 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
93 }, {
94 .blt_desc = "bad lock level on ns (2)",
95 .blt_lock = {
96 .nil_common = { .nioc_nsid = 1 },
97 .nil_ent = NVME_LOCK_E_NS,
98 .nil_level = 7
99 },
100 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
101 }, {
102 .blt_desc = "bad lock level on ns (3)",
103 .blt_lock = {
104 .nil_common = { .nioc_nsid = 1 },
105 .nil_ent = NVME_LOCK_E_NS,
106 .nil_level = UINT32_MAX
107 },
108 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
109 }, {
110 .blt_desc = "bad lock flags (1)",
111 .blt_lock = {
112 .nil_ent = NVME_LOCK_E_CTRL,
113 .nil_level = NVME_LOCK_L_READ,
114 .nil_flags = 0x2
115 },
116 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
117 }, {
118 .blt_desc = "bad lock flags (2)",
119 .blt_lock = {
120 .nil_ent = NVME_LOCK_E_CTRL,
121 .nil_level = NVME_LOCK_L_READ,
122 .nil_flags = 0x23
123 },
124 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
125 }, {
126 .blt_desc = "bad lock flags on ns (1)",
127 .blt_lock = {
128 .nil_common = { .nioc_nsid = 1 },
129 .nil_ent = NVME_LOCK_E_NS,
130 .nil_level = NVME_LOCK_L_READ,
131 .nil_flags = 0x2
132 },
133 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
134 }, {
135 .blt_desc = "bad lock flags on ns (2)",
136 .blt_lock = {
137 .nil_common = { .nioc_nsid = 1 },
138 .nil_ent = NVME_LOCK_E_NS,
139 .nil_level = NVME_LOCK_L_READ,
140 .nil_flags = 0x23
141 },
142 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
143 } };
144
145 static const bad_lock_test_t bad_lock_tests_ns[] = { {
146 .blt_desc = "bad lock level (1)",
147 .blt_lock = { .nil_ent = NVME_LOCK_E_NS, .nil_level = 0 },
148 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
149 }, {
150 .blt_desc = "bad lock level (2)",
151 .blt_lock = { .nil_ent = NVME_LOCK_E_NS, .nil_level = 7 },
152 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
153 }, {
154 .blt_desc = "bad lock level (3)",
155 .blt_lock = { .nil_ent = NVME_LOCK_E_NS, .nil_level = UINT32_MAX },
156 .blt_err = NVME_IOCTL_E_BAD_LOCK_LEVEL
157 }, {
158 .blt_desc = "bad lock flags (1)",
159 .blt_lock = {
160 .nil_ent = NVME_LOCK_E_NS,
161 .nil_level = NVME_LOCK_L_READ,
162 .nil_flags = 0x2
163 },
164 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
165 }, {
166 .blt_desc = "bad lock flags (2)",
167 .blt_lock = {
168 .nil_ent = NVME_LOCK_E_NS,
169 .nil_level = NVME_LOCK_L_READ,
170 .nil_flags = 0x23
171 },
172 .blt_err = NVME_IOCTL_E_BAD_LOCK_FLAGS
173 }, {
174 .blt_desc = "ns fd cant take ctrl read lock",
175 .blt_lock = {
176 .nil_ent = NVME_LOCK_E_CTRL,
177 .nil_level = NVME_LOCK_L_READ,
178 .nil_flags = NVME_LOCK_F_DONT_BLOCK
179 },
180 .blt_err = NVME_IOCTL_E_NS_CANNOT_LOCK_CTRL
181 }, {
182 .blt_desc = "ns fd cant take ctrl write lock",
183 .blt_lock = {
184 .nil_ent = NVME_LOCK_E_CTRL,
185 .nil_level = NVME_LOCK_L_WRITE,
186 .nil_flags = NVME_LOCK_F_DONT_BLOCK
187 },
188 .blt_err = NVME_IOCTL_E_NS_CANNOT_LOCK_CTRL
189 } };
190
191 static const bad_unlock_test_t bad_unlock_tests_cmn[] = { {
192 .but_desc = "bad unlock entity (1)",
193 .but_unlock = { .niu_ent = 0 },
194 .but_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
195 }, {
196 .but_desc = "bad unlock entity (2)",
197 .but_unlock = { .niu_ent = 0x23 },
198 .but_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
199 }, {
200 .but_desc = "bad unlock entity (3)",
201 .but_unlock = { .niu_ent = INT32_MAX },
202 .but_err = NVME_IOCTL_E_BAD_LOCK_ENTITY
203 } };
204
205 static const bad_unlock_test_t bad_unlock_tests_ctrl[] = { {
206 .but_desc = "unlock ctrl without lock",
207 .but_unlock = { .niu_ent = NVME_LOCK_E_CTRL },
208 .but_err = NVME_IOCTL_E_LOCK_NOT_HELD,
209 }, {
210 .but_desc = "unlock ns without lock",
211 .but_unlock = {
212 .niu_common = { .nioc_nsid = 1 },
213 .niu_ent = NVME_LOCK_E_NS
214 },
215 .but_err = NVME_IOCTL_E_LOCK_NOT_HELD
216 } };
217
218 static const bad_unlock_test_t bad_unlock_tests_ns[] = { {
219 .but_desc = "unlock ns without lock",
220 .but_unlock = { .niu_ent = NVME_LOCK_E_NS },
221 .but_err = NVME_IOCTL_E_LOCK_NOT_HELD
222 }, {
223 .but_desc = "unlock ctrl from ns fd",
224 .but_unlock = { .niu_ent = NVME_LOCK_E_CTRL },
225 .but_err = NVME_IOCTL_E_NS_CANNOT_UNLOCK_CTRL
226 } };
227
228 static const bad_unlock_test_t bad_unlock_tests_ctrl_w_ctrl[] = { {
229 .but_desc = "unlock ns with control lock",
230 .but_unlock = {
231 .niu_common = { .nioc_nsid = 1 },
232 .niu_ent = NVME_LOCK_E_NS
233 },
234 .but_err = NVME_IOCTL_E_LOCK_NOT_HELD
235 } };
236
237 static const bad_unlock_test_t bad_unlock_tests_ctrl_w_ns[] = { {
238 .but_desc = "unlock ctrl with ns lock",
239 .but_unlock = {
240 .niu_ent = NVME_LOCK_E_CTRL
241 },
242 .but_err = NVME_IOCTL_E_LOCK_NOT_HELD
243 } };
244
245 static bool
bad_lock_test(int fd,const bad_lock_test_t * test,bool ns)246 bad_lock_test(int fd, const bad_lock_test_t *test, bool ns)
247 {
248 nvme_ioctl_lock_t lock = test->blt_lock;
249 const char *type = ns ? "(ns)" : "(ctrl)";
250
251 if (ioctl(fd, NVME_IOC_LOCK, &lock) != 0) {
252 warn("TEST FAILED: %s %s: failed to issue lock ioctl",
253 test->blt_desc, type);
254 return (false);
255 }
256
257 if (lock.nil_common.nioc_drv_err != test->blt_err) {
258 warnx("TEST FAILED: %s %s: lock ioctl failed with 0x%x, "
259 "expected 0x%x", test->blt_desc, type,
260 lock.nil_common.nioc_drv_err, test->blt_err);
261 return (false);
262 }
263
264 (void) printf("TEST PASSED: %s %s\n", test->blt_desc, type);
265 return (true);
266 }
267
268 static bool
bad_unlock_test(int fd,const bad_unlock_test_t * test,bool ns)269 bad_unlock_test(int fd, const bad_unlock_test_t *test, bool ns)
270 {
271 nvme_ioctl_unlock_t unlock = test->but_unlock;
272 const char *type = ns ? "(ns)" : "(ctrl)";
273
274 if (ioctl(fd, NVME_IOC_UNLOCK, &unlock) != 0) {
275 warn("TEST FAILED: %s %s: failed to issue unlock ioctl",
276 test->but_desc, type);
277 return (false);
278 }
279
280 if (unlock.niu_common.nioc_drv_err != test->but_err) {
281 warnx("TEST FAILED: %s %s: unlock ioctl failed with 0x%x, "
282 "expected 0x%x", test->but_desc, type,
283 unlock.niu_common.nioc_drv_err, test->but_err);
284 return (false);
285 }
286
287 (void) printf("TEST PASSED: %s %s\n", test->but_desc, type);
288 return (true);
289 }
290
291 int
main(void)292 main(void)
293 {
294 int ret = EXIT_SUCCESS;
295 int fd = nvme_ioctl_test_get_fd(0);
296
297 for (size_t i = 0; i < ARRAY_SIZE(bad_lock_tests_com); i++) {
298 if (!bad_lock_test(fd, &bad_lock_tests_com[i], false)) {
299 ret = EXIT_FAILURE;
300 }
301 }
302
303 for (size_t i = 0; i < ARRAY_SIZE(bad_lock_tests_ctrl); i++) {
304 if (!bad_lock_test(fd, &bad_lock_tests_ctrl[i], false)) {
305 ret = EXIT_FAILURE;
306 }
307 }
308
309 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_cmn); i++) {
310 if (!bad_unlock_test(fd, &bad_unlock_tests_cmn[i], false)) {
311 ret = EXIT_FAILURE;
312 }
313 }
314
315 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_ctrl); i++) {
316 if (!bad_unlock_test(fd, &bad_unlock_tests_ctrl[i], false)) {
317 ret = EXIT_FAILURE;
318 }
319 }
320
321 VERIFY0(close(fd));
322 fd = nvme_ioctl_test_get_fd(1);
323
324 for (size_t i = 0; i < ARRAY_SIZE(bad_lock_tests_com); i++) {
325 if (!bad_lock_test(fd, &bad_lock_tests_com[i], true)) {
326 ret = EXIT_FAILURE;
327 }
328 }
329
330 for (size_t i = 0; i < ARRAY_SIZE(bad_lock_tests_ns); i++) {
331 if (!bad_lock_test(fd, &bad_lock_tests_ns[i], true)) {
332 ret = EXIT_FAILURE;
333 }
334 }
335
336 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_cmn); i++) {
337 if (!bad_unlock_test(fd, &bad_unlock_tests_cmn[i], true)) {
338 ret = EXIT_FAILURE;
339 }
340 }
341
342 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_ns); i++) {
343 if (!bad_unlock_test(fd, &bad_unlock_tests_ns[i], true)) {
344 ret = EXIT_FAILURE;
345 }
346 }
347 VERIFY0(close(fd));
348
349 /*
350 * Unlock tests that require a lock to be held.
351 */
352 fd = nvme_ioctl_test_get_fd(0);
353 nvme_ioctl_test_lock(fd, &nvme_test_ctrl_rdlock);
354 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_ctrl_w_ctrl); i++) {
355 if (!bad_unlock_test(fd, &bad_unlock_tests_ctrl_w_ctrl[i],
356 false)) {
357 ret = EXIT_FAILURE;
358 }
359 }
360
361 VERIFY0(close(fd));
362 fd = nvme_ioctl_test_get_fd(0);
363 nvme_ioctl_test_lock(fd, &nvme_test_ns_rdlock);
364 for (size_t i = 0; i < ARRAY_SIZE(bad_unlock_tests_ctrl_w_ns); i++) {
365 if (!bad_unlock_test(fd, &bad_unlock_tests_ctrl_w_ns[i],
366 false)) {
367 ret = EXIT_FAILURE;
368 }
369 }
370
371 VERIFY0(close(fd));
372
373 return (ret);
374 }
375