1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2020 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/stdinc.h"
7 #include "spdk/env.h"
8 #include "spdk/log.h"
9
10 struct sigbus_handler {
11 spdk_pci_error_handler func;
12 void *ctx;
13
14 TAILQ_ENTRY(sigbus_handler) tailq;
15 };
16
17 static pthread_mutex_t g_sighandler_mutex = PTHREAD_MUTEX_INITIALIZER;
18 static TAILQ_HEAD(, sigbus_handler) g_sigbus_handler =
19 TAILQ_HEAD_INITIALIZER(g_sigbus_handler);
20
21 static void
sigbus_fault_sighandler(int signum,siginfo_t * info,void * ctx)22 sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
23 {
24 struct sigbus_handler *sigbus_handler;
25
26 pthread_mutex_lock(&g_sighandler_mutex);
27 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
28 sigbus_handler->func(info->si_addr, sigbus_handler->ctx);
29 }
30 pthread_mutex_unlock(&g_sighandler_mutex);
31 }
32
33 __attribute__((constructor)) static void
device_set_signal(void)34 device_set_signal(void)
35 {
36 struct sigaction sa;
37
38 sa.sa_sigaction = sigbus_fault_sighandler;
39 sigemptyset(&sa.sa_mask);
40 sa.sa_flags = SA_SIGINFO;
41 sigaction(SIGBUS, &sa, NULL);
42 }
43
44 __attribute__((destructor)) static void
device_destroy_signal(void)45 device_destroy_signal(void)
46 {
47 struct sigbus_handler *sigbus_handler, *tmp;
48
49 TAILQ_FOREACH_SAFE(sigbus_handler, &g_sigbus_handler, tailq, tmp) {
50 free(sigbus_handler);
51 }
52 }
53
54 int
spdk_pci_register_error_handler(spdk_pci_error_handler sighandler,void * ctx)55 spdk_pci_register_error_handler(spdk_pci_error_handler sighandler, void *ctx)
56 {
57 struct sigbus_handler *sigbus_handler;
58
59 if (!sighandler) {
60 SPDK_ERRLOG("Error handler is NULL\n");
61 return -EINVAL;
62 }
63
64 pthread_mutex_lock(&g_sighandler_mutex);
65 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
66 if (sigbus_handler->func == sighandler) {
67 pthread_mutex_unlock(&g_sighandler_mutex);
68 SPDK_ERRLOG("Error handler has been registered\n");
69 return -EINVAL;
70 }
71 }
72 pthread_mutex_unlock(&g_sighandler_mutex);
73
74 sigbus_handler = calloc(1, sizeof(*sigbus_handler));
75 if (!sigbus_handler) {
76 SPDK_ERRLOG("Failed to allocate sigbus handler\n");
77 return -ENOMEM;
78 }
79
80 sigbus_handler->func = sighandler;
81 sigbus_handler->ctx = ctx;
82
83 pthread_mutex_lock(&g_sighandler_mutex);
84 TAILQ_INSERT_TAIL(&g_sigbus_handler, sigbus_handler, tailq);
85 pthread_mutex_unlock(&g_sighandler_mutex);
86
87 return 0;
88 }
89
90 void
spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler)91 spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler)
92 {
93 struct sigbus_handler *sigbus_handler;
94
95 if (!sighandler) {
96 return;
97 }
98
99 pthread_mutex_lock(&g_sighandler_mutex);
100 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
101 if (sigbus_handler->func == sighandler) {
102 TAILQ_REMOVE(&g_sigbus_handler, sigbus_handler, tailq);
103 free(sigbus_handler);
104 pthread_mutex_unlock(&g_sighandler_mutex);
105 return;
106 }
107 }
108 pthread_mutex_unlock(&g_sighandler_mutex);
109 }
110