xref: /illumos-gate/usr/src/test/nvme-tests/tests/ioctl/bad-lock.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
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