1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/env.h" 36 #include "spdk/log.h" 37 38 struct sigbus_handler { 39 spdk_pci_error_handler func; 40 void *ctx; 41 42 TAILQ_ENTRY(sigbus_handler) tailq; 43 }; 44 45 static pthread_mutex_t g_sighandler_mutex = PTHREAD_MUTEX_INITIALIZER; 46 static TAILQ_HEAD(, sigbus_handler) g_sigbus_handler = 47 TAILQ_HEAD_INITIALIZER(g_sigbus_handler); 48 49 static void 50 sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx) 51 { 52 struct sigbus_handler *sigbus_handler; 53 54 pthread_mutex_lock(&g_sighandler_mutex); 55 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) { 56 sigbus_handler->func(info->si_addr, sigbus_handler->ctx); 57 } 58 pthread_mutex_unlock(&g_sighandler_mutex); 59 } 60 61 __attribute__((constructor)) static void 62 device_set_signal(void) 63 { 64 struct sigaction sa; 65 66 sa.sa_sigaction = sigbus_fault_sighandler; 67 sigemptyset(&sa.sa_mask); 68 sa.sa_flags = SA_SIGINFO; 69 sigaction(SIGBUS, &sa, NULL); 70 } 71 72 __attribute__((destructor)) static void 73 device_destroy_signal(void) 74 { 75 struct sigbus_handler *sigbus_handler, *tmp; 76 77 TAILQ_FOREACH_SAFE(sigbus_handler, &g_sigbus_handler, tailq, tmp) { 78 free(sigbus_handler); 79 } 80 } 81 82 int 83 spdk_pci_register_error_handler(spdk_pci_error_handler sighandler, void *ctx) 84 { 85 struct sigbus_handler *sigbus_handler; 86 87 if (!sighandler) { 88 SPDK_ERRLOG("Error handler is NULL\n"); 89 return -EINVAL; 90 } 91 92 pthread_mutex_lock(&g_sighandler_mutex); 93 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) { 94 if (sigbus_handler->func == sighandler) { 95 pthread_mutex_unlock(&g_sighandler_mutex); 96 SPDK_ERRLOG("Error handler has been registered\n"); 97 return -EINVAL; 98 } 99 } 100 pthread_mutex_unlock(&g_sighandler_mutex); 101 102 sigbus_handler = calloc(1, sizeof(*sigbus_handler)); 103 if (!sigbus_handler) { 104 SPDK_ERRLOG("Failed to allocate sigbus handler\n"); 105 return -ENOMEM; 106 } 107 108 sigbus_handler->func = sighandler; 109 sigbus_handler->ctx = ctx; 110 111 pthread_mutex_lock(&g_sighandler_mutex); 112 TAILQ_INSERT_TAIL(&g_sigbus_handler, sigbus_handler, tailq); 113 pthread_mutex_unlock(&g_sighandler_mutex); 114 115 return 0; 116 } 117 118 void 119 spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler) 120 { 121 struct sigbus_handler *sigbus_handler; 122 123 if (!sighandler) { 124 return; 125 } 126 127 pthread_mutex_lock(&g_sighandler_mutex); 128 TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) { 129 if (sigbus_handler->func == sighandler) { 130 TAILQ_REMOVE(&g_sigbus_handler, sigbus_handler, tailq); 131 free(sigbus_handler); 132 pthread_mutex_unlock(&g_sighandler_mutex); 133 return; 134 } 135 } 136 pthread_mutex_unlock(&g_sighandler_mutex); 137 } 138