Home | History | Annotate | Download | only in configd
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <assert.h>
     30 #include <pthread.h>
     31 #include <stdlib.h>
     32 #include <strings.h>
     33 #include "configd.h"
     34 #include "repcache_protocol.h"
     35 
     36 typedef struct snapshot_bucket {
     37 	pthread_mutex_t	sb_lock;
     38 	rc_snapshot_t	*sb_head;
     39 
     40 	char		sb_pad[64 - sizeof (pthread_mutex_t) -
     41 			    sizeof (rc_snapshot_t *)];
     42 } snapshot_bucket_t;
     43 
     44 #define	SN_HASH_SIZE	64
     45 #define	SN_HASH_MASK	(SN_HASH_SIZE - 1)
     46 
     47 #pragma align 64(snapshot_hash)
     48 static snapshot_bucket_t snapshot_hash[SN_HASH_SIZE];
     49 
     50 #define	SNAPSHOT_BUCKET(h)	(&snapshot_hash[(h) & SN_HASH_MASK])
     51 
     52 static rc_snapshot_t *
     53 snapshot_alloc(void)
     54 {
     55 	rc_snapshot_t *sp;
     56 	sp = uu_zalloc(sizeof (*sp));
     57 
     58 	(void) pthread_mutex_init(&sp->rs_lock, NULL);
     59 	(void) pthread_cond_init(&sp->rs_cv, NULL);
     60 
     61 	sp->rs_refcnt++;
     62 	return (sp);
     63 }
     64 
     65 static void
     66 snapshot_free(rc_snapshot_t *sp)
     67 {
     68 	rc_snaplevel_t *lvl, *next;
     69 
     70 	assert(sp->rs_refcnt == 0 && sp->rs_childref == 0);
     71 
     72 	(void) pthread_mutex_destroy(&sp->rs_lock);
     73 	(void) pthread_cond_destroy(&sp->rs_cv);
     74 
     75 	for (lvl = sp->rs_levels; lvl != NULL; lvl = next) {
     76 		next = lvl->rsl_next;
     77 
     78 		assert(lvl->rsl_parent == sp);
     79 		lvl->rsl_parent = NULL;
     80 
     81 		if (lvl->rsl_service)
     82 			free((char *)lvl->rsl_service);
     83 		if (lvl->rsl_instance)
     84 			free((char *)lvl->rsl_instance);
     85 
     86 		uu_free(lvl);
     87 	}
     88 	uu_free(sp);
     89 }
     90 
     91 static void
     92 rc_snapshot_hold(rc_snapshot_t *sp)
     93 {
     94 	(void) pthread_mutex_lock(&sp->rs_lock);
     95 	sp->rs_refcnt++;
     96 	assert(sp->rs_refcnt > 0);
     97 	(void) pthread_mutex_unlock(&sp->rs_lock);
     98 }
     99 
    100 void
    101 rc_snapshot_rele(rc_snapshot_t *sp)
    102 {
    103 	int done;
    104 	(void) pthread_mutex_lock(&sp->rs_lock);
    105 	assert(sp->rs_refcnt > 0);
    106 	sp->rs_refcnt--;
    107 	done = ((sp->rs_flags & RC_SNAPSHOT_DEAD) &&
    108 	    sp->rs_refcnt == 0 && sp->rs_childref == 0);
    109 	(void) pthread_mutex_unlock(&sp->rs_lock);
    110 
    111 	if (done)
    112 		snapshot_free(sp);
    113 }
    114 
    115 void
    116 rc_snaplevel_hold(rc_snaplevel_t *lvl)
    117 {
    118 	rc_snapshot_t *sp = lvl->rsl_parent;
    119 	(void) pthread_mutex_lock(&sp->rs_lock);
    120 	sp->rs_childref++;
    121 	assert(sp->rs_childref > 0);
    122 	(void) pthread_mutex_unlock(&sp->rs_lock);
    123 }
    124 
    125 void
    126 rc_snaplevel_rele(rc_snaplevel_t *lvl)
    127 {
    128 	int done;
    129 	rc_snapshot_t *sp = lvl->rsl_parent;
    130 	(void) pthread_mutex_lock(&sp->rs_lock);
    131 	assert(sp->rs_childref > 0);
    132 	sp->rs_childref--;
    133 	done = ((sp->rs_flags & RC_SNAPSHOT_DEAD) &&
    134 	    sp->rs_refcnt == 0 && sp->rs_childref == 0);
    135 	(void) pthread_mutex_unlock(&sp->rs_lock);
    136 
    137 	if (done)
    138 		snapshot_free(sp);
    139 }
    140 
    141 static snapshot_bucket_t *
    142 snapshot_hold_bucket(uint32_t snap_id)
    143 {
    144 	snapshot_bucket_t *bp = SNAPSHOT_BUCKET(snap_id);
    145 	(void) pthread_mutex_lock(&bp->sb_lock);
    146 	return (bp);
    147 }
    148 
    149 static void
    150 snapshot_rele_bucket(snapshot_bucket_t *bp)
    151 {
    152 	assert(MUTEX_HELD(&bp->sb_lock));
    153 	(void) pthread_mutex_unlock(&bp->sb_lock);
    154 }
    155 
    156 static rc_snapshot_t *
    157 snapshot_lookup_unlocked(snapshot_bucket_t *bp, uint32_t snap_id)
    158 {
    159 	rc_snapshot_t *sp;
    160 
    161 	assert(MUTEX_HELD(&bp->sb_lock));
    162 	assert(bp == SNAPSHOT_BUCKET(snap_id));
    163 
    164 	for (sp = bp->sb_head; sp != NULL; sp = sp->rs_hash_next) {
    165 		if (sp->rs_snap_id == snap_id) {
    166 			rc_snapshot_hold(sp);
    167 			return (sp);
    168 		}
    169 	}
    170 	return (NULL);
    171 }
    172 
    173 static void
    174 snapshot_insert_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp)
    175 {
    176 	assert(MUTEX_HELD(&bp->sb_lock));
    177 	assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id));
    178 
    179 	assert(sp->rs_hash_next == NULL);
    180 
    181 	sp->rs_hash_next = bp->sb_head;
    182 	bp->sb_head = sp;
    183 }
    184 
    185 static void
    186 snapshot_remove_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp)
    187 {
    188 	rc_snapshot_t **spp;
    189 
    190 	assert(MUTEX_HELD(&bp->sb_lock));
    191 	assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id));
    192 
    193 	assert(sp->rs_hash_next == NULL);
    194 
    195 	for (spp = &bp->sb_head; *spp != NULL; spp = &(*spp)->rs_hash_next)
    196 		if (*spp == sp)
    197 			break;
    198 
    199 	assert(*spp == sp);
    200 	*spp = sp->rs_hash_next;
    201 	sp->rs_hash_next = NULL;
    202 }
    203 
    204 /*
    205  * Look up the snapshot with id snap_id in the hash table, or create it
    206  * & populate it with its snaplevels if it's not in the hash table yet.
    207  *
    208  * Fails with
    209  *   _NO_RESOURCES
    210  */
    211 int
    212 rc_snapshot_get(uint32_t snap_id, rc_snapshot_t **snpp)
    213 {
    214 	snapshot_bucket_t *bp;
    215 	rc_snapshot_t *sp;
    216 	int r;
    217 
    218 	bp = snapshot_hold_bucket(snap_id);
    219 	sp = snapshot_lookup_unlocked(bp, snap_id);
    220 	if (sp != NULL) {
    221 		snapshot_rele_bucket(bp);
    222 		(void) pthread_mutex_lock(&sp->rs_lock);
    223 		while (sp->rs_flags & RC_SNAPSHOT_FILLING)
    224 			(void) pthread_cond_wait(&sp->rs_cv, &sp->rs_lock);
    225 
    226 		if (sp->rs_flags & RC_SNAPSHOT_DEAD) {
    227 			(void) pthread_mutex_unlock(&sp->rs_lock);
    228 			rc_snapshot_rele(sp);
    229 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
    230 		}
    231 		assert(sp->rs_flags & RC_SNAPSHOT_READY);
    232 		(void) pthread_mutex_unlock(&sp->rs_lock);
    233 		*snpp = sp;
    234 		return (REP_PROTOCOL_SUCCESS);
    235 	}
    236 	sp = snapshot_alloc();
    237 	sp->rs_snap_id = snap_id;
    238 	sp->rs_flags |= RC_SNAPSHOT_FILLING;
    239 	snapshot_insert_unlocked(bp, sp);
    240 	snapshot_rele_bucket(bp);
    241 
    242 	/*
    243 	 * Now fill in the snapshot tree
    244 	 */
    245 	r = object_fill_snapshot(sp);
    246 	if (r != REP_PROTOCOL_SUCCESS) {
    247 		assert(r == REP_PROTOCOL_FAIL_NO_RESOURCES);
    248 
    249 		/*
    250 		 * failed -- first remove it from the hash table, then kill it
    251 		 */
    252 		bp = snapshot_hold_bucket(snap_id);
    253 		snapshot_remove_unlocked(bp, sp);
    254 		snapshot_rele_bucket(bp);
    255 
    256 		(void) pthread_mutex_lock(&sp->rs_lock);
    257 		sp->rs_flags &= ~RC_SNAPSHOT_FILLING;
    258 		sp->rs_flags |= RC_SNAPSHOT_DEAD;
    259 		(void) pthread_cond_broadcast(&sp->rs_cv);
    260 		(void) pthread_mutex_unlock(&sp->rs_lock);
    261 		rc_snapshot_rele(sp);		/* may free sp */
    262 		return (r);
    263 	}
    264 	(void) pthread_mutex_lock(&sp->rs_lock);
    265 	sp->rs_flags &= ~RC_SNAPSHOT_FILLING;
    266 	sp->rs_flags |= RC_SNAPSHOT_READY;
    267 	(void) pthread_cond_broadcast(&sp->rs_cv);
    268 	(void) pthread_mutex_unlock(&sp->rs_lock);
    269 	*snpp = sp;
    270 	return (REP_PROTOCOL_SUCCESS);		/* pass on creation reference */
    271 }
    272