Home | History | Annotate | Download | only in diskomizer
      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