1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)shared_device_info.c 1.9 09/05/26 SMI" 28 29 /* 30 * Routines for storing shared information about devices. Used for 31 * errors and statistics. 32 * 33 * Update routines are non blocking. On error the caller is expected to 34 * keep the data and resubmit it later when the lock or memory can 35 * be accessed. 36 * 37 * Chris.Gerhard (at) uk.sun.com - CS CTE 38 * 39 * Still to do: 40 * Shared statistics. 41 * on_error stop routine. 42 * re implement the device control to use these routines, 43 * this will save memory. 44 */ 45 #ifndef _LARGEFILE64_SOURCE 46 #define _LARGEFILE64_SOURCE 47 #endif 48 #include <sys/types.h> 49 #include <string.h> 50 #include <libintl.h> 51 #include "locks.h" 52 #include "shm_ops.h" 53 #include <diskomizer/log.h> 54 #include "shared_device_info.h" 55 #define ZERO_OBJ(X) (void) memset(&X, NULL, sizeof (X)) 56 #define CACHE_LINE 64 57 struct fast_locks { 58 union { 59 pthread_mutex_t lock; 60 char pad[CACHE_LINE]; 61 } u; 62 }; 63 static int nprocs; 64 /* 65 * Private data structure that is used to store the shared information. 66 */ 67 struct shared_device_info { 68 pthread_mutex_t error_lock; 69 uint_t errors; 70 /* To update you have to hold all the locks in array */ 71 uint_t stop_flag:1; 72 /* Must be the last element in the structure */ 73 struct fast_locks locks[1]; 74 }; 75 void * 76 init_shared_device_info(int nproc) 77 { 78 shm_flags flag; 79 void *handle; 80 struct shared_device_info *info; 81 int i; 82 83 nprocs = nproc; 84 85 ZERO_OBJ(flag); 86 87 flag.allow_detach = 1; 88 89 handle = shm_ops->init(1, sizeof (struct shared_device_info) + 90 sizeof (struct fast_locks) * (nproc - 1), flag); 91 92 if (handle == NULL) 93 return (NULL); 94 info = (struct shared_device_info *)shm_ops->attach(handle); 95 if (info == NULL) { 96 shm_ops->destroy(handle); 97 return (NULL); 98 } 99 if (init_shared_lock(&info->error_lock)) { 100 shm_ops->detach(handle); 101 shm_ops->destroy(handle); 102 return (NULL); 103 } 104 info->errors = 0; 105 for (i = 0; i < nprocs; i++) { 106 if (init_shared_lock(&info->locks[i].u.lock)) { 107 shm_ops->detach(handle); 108 shm_ops->destroy(handle); 109 return (NULL); 110 } 111 } 112 113 if (shm_ops->detach(handle) == SHM_DETACH_ERR) { 114 pperror(gettext("Unable to detach %s shared memory segment\n"), 115 shm_ops->name(handle)); 116 } 117 return (handle); 118 } 119 /* 120 * Increment the error counter by count. Return the previous error count. 121 * on error return -1. 122 * 123 * The caller has to cope with the error. 124 */ 125 int 126 incr_shared_device_error(void *handle, int count) 127 { 128 struct shared_device_info *info; 129 int old; 130 /* 131 * I the count is zero then, this is just alook up which will block 132 * lookups are only done as the whole thing exits. 133 */ 134 int (*lock)(pthread_mutex_t *mutex) = count ? pthread_mutex_trylock : 135 pthread_mutex_lock; 136 137 if (handle == NULL) 138 return (-1); 139 140 info = (struct shared_device_info *)shm_ops->attach(handle); 141 if (info == NULL) { 142 return (-1); 143 } 144 if (lock(&info->error_lock)) { 145 shm_ops->detach(handle); 146 return (-1); 147 } 148 old = info->errors; 149 info->errors += count; 150 pthread_mutex_unlock(&info->error_lock); 151 shm_ops->detach(handle); 152 return (old); 153 } 154 int 155 get_shared_device_error(void *handle) 156 { 157 return (incr_shared_device_error(handle, 0)); 158 } 159 int 160 get_shared_stop_flag(void *handle, int proc) 161 { 162 struct shared_device_info *info; 163 int x; 164 if (handle == NULL) 165 return (-1); 166 info = (struct shared_device_info *)shm_ops->attach(handle); 167 if (info == NULL) { 168 return (-1); 169 } 170 if (pthread_mutex_trylock(&info->locks[proc].u.lock)) { 171 shm_ops->detach(handle); 172 return (-1); 173 } 174 x = info->stop_flag; 175 pthread_mutex_unlock(&info->locks[proc].u.lock); 176 shm_ops->detach(handle); 177 return (x); 178 } 179 int 180 set_shared_stop_flag(void *handle) 181 { 182 struct shared_device_info *info; 183 int i; 184 185 if (handle == NULL) 186 return (-1); 187 188 info = (struct shared_device_info *)shm_ops->attach(handle); 189 if (info == NULL) { 190 return (-1); 191 } 192 for (i = 0; i < nprocs; i++) { 193 if (pthread_mutex_trylock(&info->locks[i].u.lock)) { 194 while ((--i) >= 0) { 195 pthread_mutex_unlock(&info->locks[i].u.lock); 196 } 197 shm_ops->detach(handle); 198 return (-1); 199 } 200 } 201 info->stop_flag = 1; 202 203 while ((--i) >= 0) { 204 pthread_mutex_unlock(&info->locks[i].u.lock); 205 } 206 shm_ops->detach(handle); 207 return (1); 208 } 209