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 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 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 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