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	"@(#)shm_best_ops.c	1.16	09/05/26 SMI"
     28 
     29 /*
     30  * shared memory operations.  They support the attaching and
     31  * detaching of shared memory, to reduce the overall address space
     32  * usage on a 32 bit system. All this extra work is a waste of
     33  * time on a 64 bit system at present.
     34  */
     35 #include <stdlib.h>
     36 #include <unistd.h>
     37 #include <limits.h>
     38 #include <stdio.h>
     39 #include <errno.h>
     40 
     41 #include <diskomizer/log.h>
     42 #include "shm_ops.h"
     43 #include "list.h"
     44 #include <diskomizer/assert.h>
     45 
     46 static struct shm_ops *all_ops[] = {&shm_bestshm_ops, &shm_mmap_ops, NULL};
     47 static int hasfailed;
     48 static struct best_shm *head;
     49 struct best_shm {
     50 	void *handle;
     51 	void *addr;
     52 	int ref;
     53 	shm_flags flags;
     54 	ulong_t len;
     55 	struct shm_ops *ops;
     56 	struct best_shm *allnext;
     57 	struct best_shm *next;
     58 	struct best_shm *prev;
     59 };
     60 struct list_head {
     61 	struct best_shm *head;
     62 	struct best_shm *tail;
     63 };
     64 static struct list_head free_list, active_list;
     65 
     66 #define	PRINT_LIST(LIST_HEAD, NEXT) { \
     67 	struct best_shm *x; \
     68 	plog(LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, #LIST_HEAD); \
     69 	for (x = LIST_HEAD; x != NULL; x = x->NEXT) { \
     70 		plog(LOG_DEBUG, "List %s Handle %#lx, Addr %#lx, " \
     71 			"ref %d type %s\n", #LIST_HEAD, \
     72 			(ulong_t)x->handle, (ulong_t)x->addr, \
     73 			x->ref, x->ops->name(x->handle)); \
     74 		plog(LOG_DEBUG, "execute %d write %d allow_detach %d " \
     75 			"always_detach %d\n", \
     76 			x->flags.execute, x->flags.write, \
     77 			x->flags.allow_detach, x->flags.always_detach); \
     78 		plog(LOG_DEBUG, "x %#lx, next %#lx, prev %#lx, len %ld\n", \
     79 			(ulong_t)x, (ulong_t)x->next, (ulong_t)x->prev, \
     80 			x->len); \
     81 	} \
     82 }
     83 static void *
     84 my_alloc(size_t nelem, size_t elsize)
     85 {
     86 	void *res;
     87 	long sbrkval;
     88 	struct best_shm *q;
     89 
     90 	res = calloc(nelem, elsize);
     91 	if (res == NULL && (sbrkval = (long)sbrk(0))  != -1) {
     92 		sbrkval += (nelem * elsize) + 8192;
     93 		for (q = free_list.tail; q != NULL && res == NULL;
     94 		    q = q->prev) {
     95 			if (q->addr != NULL && q->ref == 0)
     96 				if ((ulong_t)q->addr <= sbrkval) {
     97 				if (q->ops->detach(q->handle) !=
     98 				    SHM_DETACH_ERR) {
     99 					q->addr = NULL;
    100 					res = calloc(nelem, elsize);
    101 				}
    102 			}
    103 		}
    104 	}
    105 	for (q = free_list.tail; q != NULL && res == NULL; q = q->prev) {
    106 		if (q->addr != NULL && q->ref == 0) {
    107 			if (q->ops->detach(q->handle) != SHM_DETACH_ERR) {
    108 				q->addr = NULL;
    109 				res = calloc(nelem, elsize);
    110 			}
    111 		}
    112 	}
    113 	return (res);
    114 }
    115 
    116 void
    117 try_init(struct best_shm *x, long a, long b, shm_flags flags)
    118 {
    119 	struct best_shm *q;
    120 	int i;
    121 
    122 	for (i = flags.allow_detach ? 0 : 1; all_ops[i] != NULL; i++) {
    123 		x->ops = all_ops[i];
    124 		flags.always_detach = 1;
    125 		if ((x->handle = x->ops->init(a, b, flags)) != NULL) {
    126 			x->addr = x->ops->attach(x->handle);
    127 			for (q = free_list.tail; x->addr == NULL && q != NULL;
    128 			    q = q->prev) {
    129 				assert(q->ref == 0);
    130 				if (q->addr != NULL && q->flags.allow_detach &&
    131 				    q->ops->detach(q->handle) !=
    132 				    SHM_DETACH_ERR) {
    133 					q->addr = NULL;
    134 					x->addr = x->ops->attach(x->handle);
    135 				}
    136 			}
    137 			if (x->addr != NULL) {
    138 				break;
    139 			} else {
    140 				x->ops->destroy(x->handle);
    141 			}
    142 		}
    143 	}
    144 }
    145 void *
    146 best_init(long a, long b, shm_flags flags)
    147 {
    148 	struct best_shm *x;
    149 	struct best_shm *q;
    150 
    151 	x = my_alloc(1, sizeof (struct best_shm));
    152 	if (x == NULL)
    153 		return (NULL);
    154 	x->flags = flags;
    155 
    156 	try_init(x, a, b, flags);
    157 	for (q = free_list.tail; x->handle == NULL && q != NULL; q = q->prev) {
    158 		if (q->addr != NULL && q->flags.allow_detach) {
    159 			assert(q->ref == 0);
    160 			if (q->ops->detach(q->handle) != SHM_DETACH_ERR) {
    161 				q->addr = NULL;
    162 				try_init(x, a, b, flags);
    163 			}
    164 		}
    165 	}
    166 	if (x->handle == NULL) {
    167 		free(x);
    168 		return (NULL);
    169 	} else {
    170 		x->allnext = head;
    171 		head = x;
    172 	}
    173 	x->len = a * b;
    174 	x->ref = 0;
    175 	LIST_ADD(&free_list, x);
    176 	return (x);
    177 }
    178 static ulong_t
    179 best_max_size(void)
    180 {
    181 	ulong_t size = 0;
    182 	int i;
    183 
    184 	for (i = 0; all_ops[i] != NULL; i++) {
    185 		ulong_t tmp = all_ops[i]->max_size();
    186 		if (tmp > size)
    187 			size = tmp;
    188 	}
    189 	return (size);
    190 }
    191 
    192 /*
    193  * The shared memeory is not attached so attach it. If it can't be attached
    194  * try detaching other segments until it can be attached or all have been
    195  * detached.
    196  */
    197 static void *
    198 best_do_attach(struct best_shm *x)
    199 {
    200 	struct best_shm *q;
    201 
    202 	x->addr = x->ops->attach(x->handle);
    203 	for (q = free_list.tail; x->addr == NULL && q != NULL; q = q->prev) {
    204 		shm_det_status status;
    205 
    206 		hasfailed = 1;
    207 		if (q->ref != 0) {
    208 			PRINT_LIST(head, allnext);
    209 
    210 			PRINT_LIST(free_list.head, next);
    211 			PRINT_LIST(active_list.head, next);
    212 			exit(1);
    213 		}
    214 		if ((errno != EMFILE || q->ops == x->ops)) {
    215 			if (q->addr != NULL && q->flags.allow_detach &&
    216 			    (status = q->ops->detach(q->handle)) !=
    217 			    SHM_DETACH_ERR) {
    218 				q->addr = NULL;
    219 				if (status == SHM_DETACH_DONE) {
    220 					x->addr = x->ops->attach(x->handle);
    221 				}
    222 			}
    223 		}
    224 	}
    225 	for (q = free_list.tail; x->addr == NULL && q != NULL; q = q->prev) {
    226 		if (q->addr != NULL && q->flags.allow_detach &&
    227 		    q->ops->detach(q->handle) == SHM_DETACH_DONE) {
    228 			q->addr = NULL;
    229 			x->addr = x->ops->attach(x->handle);
    230 		}
    231 	}
    232 	if (x->addr != NULL) {
    233 		if (x->ref == 0) {
    234 			LIST_REMOVE(&free_list, x);
    235 			LIST_ADD(&active_list, x);
    236 		}
    237 		x->ref++;
    238 	} else {
    239 		pperror("Can't attach %s", x->ops->name(x));
    240 		PRINT_LIST(head, allnext);
    241 		PRINT_LIST(free_list.head, next);
    242 	}
    243 	return (x->addr);
    244 
    245 }
    246 
    247 static void *
    248 best_attach(void * arg)
    249 {
    250 	struct best_shm *x = (struct best_shm *)arg;
    251 	if (x->addr == NULL) {
    252 		return (best_do_attach(x));
    253 	} else {
    254 		if (x->ref == 0) {
    255 			LIST_REMOVE(&free_list, x);
    256 			LIST_ADD(&active_list, x);
    257 		}
    258 		x->ref++;
    259 		return (x->addr);
    260 	}
    261 }
    262 
    263 static shm_det_status
    264 best_move_to_free(struct best_shm *x)
    265 {
    266 	shm_det_status status;
    267 
    268 	LIST_REMOVE(&active_list, x);
    269 	LIST_ADD(&free_list, x);
    270 	if (x->flags.always_detach) {
    271 		if ((status = x->ops->detach(x->handle)) != SHM_DETACH_ERR) {
    272 			x->addr = NULL;
    273 			return (status);
    274 		} else {
    275 			return (SHM_DETACH_ERR);
    276 		}
    277 	}
    278 	return (SHM_DETACH_OK);
    279 }
    280 shm_det_status
    281 best_detach(void *arg)
    282 {
    283 	struct best_shm *x = (struct best_shm *)arg;
    284 
    285 	if (--(x->ref) == 0) {
    286 		return (best_move_to_free(x));
    287 	}
    288 	return (SHM_DETACH_OK);
    289 }
    290 
    291 void
    292 best_destroy(void *arg)
    293 {
    294 	struct best_shm *x = (struct best_shm *)arg;
    295 	x->ops->destroy(x->handle);
    296 	free(x);
    297 }
    298 static char name[] = "best";
    299 const char *
    300 best_name(void *arg)
    301 {
    302 	struct best_shm *x = (struct best_shm *)arg;
    303 	if (x != NULL)
    304 		return (x->ops->name(x->handle));
    305 	return (&name[0]);
    306 }
    307 const char *
    308 best_longname(void *arg)
    309 {
    310 	struct best_shm *x = (struct best_shm *)arg;
    311 	if (x != NULL)
    312 		return (x->ops->longname(x->handle));
    313 	return (&name[0]);
    314 }
    315 static int
    316 best_is_short_of_mem(void)
    317 {
    318 	return (hasfailed);
    319 }
    320 static void
    321 best_complete(void *handle)
    322 {
    323 	int i;
    324 	for (i = 0; all_ops[i] != NULL; i++) {
    325 		all_ops[i]->complete(handle);
    326 	}
    327 }
    328 static void
    329 best_fini(void)
    330 {
    331 	int i;
    332 	for (i = 0; all_ops[i] != NULL; i++) {
    333 		all_ops[i]->fini();
    334 	}
    335 }
    336 
    337 struct shm_ops shm_best_ops = {
    338 	best_name,
    339 	best_longname,
    340 	best_init,
    341 	best_attach,
    342 	best_detach,
    343 	best_destroy,
    344 	best_max_size,
    345 	best_is_short_of_mem,
    346 	best_complete,
    347 	best_fini
    348 };
    349