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