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 * Create a thread that blocks on a lock and then once we know it is blocked,
18*533affcbSRobert Mustacchi * signal it. Verify that it errored out with EINTR. Once we do that, we ensure
19*533affcbSRobert Mustacchi * we can take all four basic locks in turn to verify that our state isn't bad.
20*533affcbSRobert Mustacchi */
21*533affcbSRobert Mustacchi
22*533affcbSRobert Mustacchi #include <err.h>
23*533affcbSRobert Mustacchi #include <stdlib.h>
24*533affcbSRobert Mustacchi #include <unistd.h>
25*533affcbSRobert Mustacchi #include <stdbool.h>
26*533affcbSRobert Mustacchi #include <sys/sysmacros.h>
27*533affcbSRobert Mustacchi #include <sys/debug.h>
28*533affcbSRobert Mustacchi #include <thread.h>
29*533affcbSRobert Mustacchi #include <synch.h>
30*533affcbSRobert Mustacchi #include <strings.h>
31*533affcbSRobert Mustacchi #include <signal.h>
32*533affcbSRobert Mustacchi
33*533affcbSRobert Mustacchi #include "nvme_ioctl_util.h"
34*533affcbSRobert Mustacchi
35*533affcbSRobert Mustacchi static volatile int lock_sig_ret = EXIT_SUCCESS;
36*533affcbSRobert Mustacchi static volatile uint32_t lock_sig_nsignals = 0;
37*533affcbSRobert Mustacchi static volatile thread_t lock_sig_thrid;
38*533affcbSRobert Mustacchi
39*533affcbSRobert Mustacchi typedef struct {
40*533affcbSRobert Mustacchi const char *lss_desc;
41*533affcbSRobert Mustacchi const nvme_ioctl_lock_t *lss_lock;
42*533affcbSRobert Mustacchi } lock_sig_test_t;
43*533affcbSRobert Mustacchi
44*533affcbSRobert Mustacchi static const lock_sig_test_t lock_sig_tests[] = {
45*533affcbSRobert Mustacchi { "controller write lock", &nvme_test_ctrl_wrlock },
46*533affcbSRobert Mustacchi { "controller read lock", &nvme_test_ctrl_wrlock },
47*533affcbSRobert Mustacchi { "namespace write lock", &nvme_test_ns_wrlock },
48*533affcbSRobert Mustacchi { "namespace read lock", &nvme_test_ns_wrlock }
49*533affcbSRobert Mustacchi };
50*533affcbSRobert Mustacchi
51*533affcbSRobert Mustacchi static void
lock_signal_hdlr(int sig)52*533affcbSRobert Mustacchi lock_signal_hdlr(int sig)
53*533affcbSRobert Mustacchi {
54*533affcbSRobert Mustacchi VERIFY3U(sig, ==, SIGINFO);
55*533affcbSRobert Mustacchi VERIFY3U(thr_self(), ==, lock_sig_thrid);
56*533affcbSRobert Mustacchi lock_sig_nsignals++;
57*533affcbSRobert Mustacchi }
58*533affcbSRobert Mustacchi
59*533affcbSRobert Mustacchi static void *
lock_signal_thr(void * arg)60*533affcbSRobert Mustacchi lock_signal_thr(void *arg)
61*533affcbSRobert Mustacchi {
62*533affcbSRobert Mustacchi int fd = nvme_ioctl_test_get_fd(0);
63*533affcbSRobert Mustacchi const lock_sig_test_t *test = arg;
64*533affcbSRobert Mustacchi nvme_ioctl_lock_t lock = *test->lss_lock;
65*533affcbSRobert Mustacchi sigset_t set;
66*533affcbSRobert Mustacchi int ret;
67*533affcbSRobert Mustacchi
68*533affcbSRobert Mustacchi VERIFY0(sigemptyset(&set));
69*533affcbSRobert Mustacchi VERIFY0(sigaddset(&set, SIGINFO));
70*533affcbSRobert Mustacchi lock_sig_thrid = thr_self();
71*533affcbSRobert Mustacchi
72*533affcbSRobert Mustacchi if ((ret = thr_sigsetmask(SIG_UNBLOCK, &set, NULL)) != 0) {
73*533affcbSRobert Mustacchi errc(EXIT_FAILURE, ret, "failed to unblock SIGINFO");
74*533affcbSRobert Mustacchi }
75*533affcbSRobert Mustacchi
76*533affcbSRobert Mustacchi
77*533affcbSRobert Mustacchi lock.nil_flags &= ~NVME_LOCK_F_DONT_BLOCK;
78*533affcbSRobert Mustacchi if (ioctl(fd, NVME_IOC_LOCK, &lock) != 0) {
79*533affcbSRobert Mustacchi err(EXIT_FAILURE, "TEST FAILED: unable to continue test "
80*533affcbSRobert Mustacchi "execution due to lock ioctl failure");
81*533affcbSRobert Mustacchi }
82*533affcbSRobert Mustacchi
83*533affcbSRobert Mustacchi if (lock.nil_common.nioc_drv_err != NVME_IOCTL_E_LOCK_WAIT_SIGNAL) {
84*533affcbSRobert Mustacchi warnx("TEST FAILED: %s: lock thread didn't error with "
85*533affcbSRobert Mustacchi "NVME_IOCTL_E_LOCK_WAIT_SIGNAL (%u), but found instead %u",
86*533affcbSRobert Mustacchi test->lss_desc, NVME_IOCTL_E_LOCK_WAIT_SIGNAL,
87*533affcbSRobert Mustacchi lock.nil_common.nioc_drv_err);
88*533affcbSRobert Mustacchi lock_sig_ret = EXIT_FAILURE;
89*533affcbSRobert Mustacchi } else {
90*533affcbSRobert Mustacchi (void) printf("TEST PASSED: %s: thread successfully "
91*533affcbSRobert Mustacchi "interrupted\n", test->lss_desc);
92*533affcbSRobert Mustacchi }
93*533affcbSRobert Mustacchi
94*533affcbSRobert Mustacchi thr_exit(NULL);
95*533affcbSRobert Mustacchi }
96*533affcbSRobert Mustacchi
97*533affcbSRobert Mustacchi static void
lock_signal_one(const lock_sig_test_t * test)98*533affcbSRobert Mustacchi lock_signal_one(const lock_sig_test_t *test)
99*533affcbSRobert Mustacchi {
100*533affcbSRobert Mustacchi int fd = nvme_ioctl_test_get_fd(0);
101*533affcbSRobert Mustacchi int ret;
102*533affcbSRobert Mustacchi thread_t thr;
103*533affcbSRobert Mustacchi
104*533affcbSRobert Mustacchi nvme_ioctl_test_lock(fd, &nvme_test_ctrl_wrlock);
105*533affcbSRobert Mustacchi ret = thr_create(NULL, 0, lock_signal_thr, (void *)test, 0, &thr);
106*533affcbSRobert Mustacchi if (ret != 0) {
107*533affcbSRobert Mustacchi errc(EXIT_FAILURE, ret, "TEST FAILED: %s: cannot continue "
108*533affcbSRobert Mustacchi "because we failed to create the thread to signal",
109*533affcbSRobert Mustacchi test->lss_desc);
110*533affcbSRobert Mustacchi }
111*533affcbSRobert Mustacchi
112*533affcbSRobert Mustacchi while (!nvme_ioctl_test_thr_blocked(thr)) {
113*533affcbSRobert Mustacchi struct timespec sleep;
114*533affcbSRobert Mustacchi
115*533affcbSRobert Mustacchi sleep.tv_sec = 0;
116*533affcbSRobert Mustacchi sleep.tv_nsec = MSEC2NSEC(10);
117*533affcbSRobert Mustacchi (void) nanosleep(&sleep, NULL);
118*533affcbSRobert Mustacchi }
119*533affcbSRobert Mustacchi
120*533affcbSRobert Mustacchi ret = thr_kill(thr, SIGINFO);
121*533affcbSRobert Mustacchi if (ret != 0) {
122*533affcbSRobert Mustacchi errc(EXIT_FAILURE, ret, "TEST FAILED: %s: cannot continue "
123*533affcbSRobert Mustacchi "because we failed to send SIGINFO to tid %u",
124*533affcbSRobert Mustacchi test->lss_desc, thr);
125*533affcbSRobert Mustacchi }
126*533affcbSRobert Mustacchi
127*533affcbSRobert Mustacchi ret = thr_join(thr, NULL, NULL);
128*533affcbSRobert Mustacchi if (ret != 0) {
129*533affcbSRobert Mustacchi errc(EXIT_FAILURE, ret, "TEST FAILED: %s: cannot continue "
130*533affcbSRobert Mustacchi "because we failed to join thread %u", test->lss_desc, thr);
131*533affcbSRobert Mustacchi }
132*533affcbSRobert Mustacchi
133*533affcbSRobert Mustacchi VERIFY0(close(fd));
134*533affcbSRobert Mustacchi fd = nvme_ioctl_test_get_fd(0);
135*533affcbSRobert Mustacchi nvme_ioctl_test_lock(fd, test->lss_lock);
136*533affcbSRobert Mustacchi (void) printf("TEST PASSED: %s: successfully grabbed follow up lock\n",
137*533affcbSRobert Mustacchi test->lss_desc);
138*533affcbSRobert Mustacchi VERIFY0(close(fd));
139*533affcbSRobert Mustacchi }
140*533affcbSRobert Mustacchi
141*533affcbSRobert Mustacchi int
main(void)142*533affcbSRobert Mustacchi main(void)
143*533affcbSRobert Mustacchi {
144*533affcbSRobert Mustacchi int ret;
145*533affcbSRobert Mustacchi sigset_t set;
146*533affcbSRobert Mustacchi struct sigaction act;
147*533affcbSRobert Mustacchi
148*533affcbSRobert Mustacchi VERIFY0(sigfillset(&set));
149*533affcbSRobert Mustacchi if ((ret = thr_sigsetmask(SIG_BLOCK, &set, NULL)) != 0) {
150*533affcbSRobert Mustacchi errc(EXIT_FAILURE, ret, "failed to block signals");
151*533affcbSRobert Mustacchi }
152*533affcbSRobert Mustacchi
153*533affcbSRobert Mustacchi act.sa_handler = lock_signal_hdlr;
154*533affcbSRobert Mustacchi VERIFY0(sigemptyset(&act.sa_mask));
155*533affcbSRobert Mustacchi act.sa_flags = 0;
156*533affcbSRobert Mustacchi VERIFY0(sigaction(SIGINFO, &act, NULL));
157*533affcbSRobert Mustacchi
158*533affcbSRobert Mustacchi for (size_t i = 0; i < ARRAY_SIZE(lock_sig_tests); i++) {
159*533affcbSRobert Mustacchi lock_signal_one(&lock_sig_tests[i]);
160*533affcbSRobert Mustacchi }
161*533affcbSRobert Mustacchi
162*533affcbSRobert Mustacchi if (lock_sig_nsignals != ARRAY_SIZE(lock_sig_tests)) {
163*533affcbSRobert Mustacchi lock_sig_ret = EXIT_FAILURE;
164*533affcbSRobert Mustacchi warnx("TEST FAILED: Didn't get %zu SIGINFO handlers, instead "
165*533affcbSRobert Mustacchi "got %u", ARRAY_SIZE(lock_sig_tests), lock_sig_nsignals);
166*533affcbSRobert Mustacchi } else {
167*533affcbSRobert Mustacchi (void) printf("TEST PASSED: Successfully ran SIGINFO "
168*533affcbSRobert Mustacchi "handlers\n");
169*533affcbSRobert Mustacchi }
170*533affcbSRobert Mustacchi
171*533affcbSRobert Mustacchi return (lock_sig_ret);
172*533affcbSRobert Mustacchi }
173