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