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 #include <assert.h> 28 #include <pthread.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include "configd.h" 32 #include "repcache_protocol.h" 33 34 typedef struct snapshot_bucket { 35 pthread_mutex_t sb_lock; 36 rc_snapshot_t *sb_head; 37 38 char sb_pad[64 - sizeof (pthread_mutex_t) - 39 sizeof (rc_snapshot_t *)]; 40 } snapshot_bucket_t; 41 42 #define SN_HASH_SIZE 64 43 #define SN_HASH_MASK (SN_HASH_SIZE - 1) 44 45 #pragma align 64(snapshot_hash) 46 static snapshot_bucket_t snapshot_hash[SN_HASH_SIZE]; 47 48 #define SNAPSHOT_BUCKET(h) (&snapshot_hash[(h) & SN_HASH_MASK]) 49 50 static rc_snapshot_t * 51 snapshot_alloc(void) 52 { 53 rc_snapshot_t *sp; 54 sp = uu_zalloc(sizeof (*sp)); 55 56 (void) pthread_mutex_init(&sp->rs_lock, NULL); 57 (void) pthread_cond_init(&sp->rs_cv, NULL); 58 59 sp->rs_refcnt++; 60 return (sp); 61 } 62 63 static void 64 snapshot_free(rc_snapshot_t *sp) 65 { 66 rc_snaplevel_t *lvl, *next; 67 68 assert(sp->rs_refcnt == 0 && sp->rs_childref == 0); 69 70 (void) pthread_mutex_destroy(&sp->rs_lock); 71 (void) pthread_cond_destroy(&sp->rs_cv); 72 73 for (lvl = sp->rs_levels; lvl != NULL; lvl = next) { 74 next = lvl->rsl_next; 75 76 assert(lvl->rsl_parent == sp); 77 lvl->rsl_parent = NULL; 78 79 if (lvl->rsl_service) 80 free((char *)lvl->rsl_service); 81 if (lvl->rsl_instance) 82 free((char *)lvl->rsl_instance); 83 84 uu_free(lvl); 85 } 86 uu_free(sp); 87 } 88 89 static void 90 rc_snapshot_hold(rc_snapshot_t *sp) 91 { 92 (void) pthread_mutex_lock(&sp->rs_lock); 93 sp->rs_refcnt++; 94 assert(sp->rs_refcnt > 0); 95 (void) pthread_mutex_unlock(&sp->rs_lock); 96 } 97 98 void 99 rc_snapshot_rele(rc_snapshot_t *sp) 100 { 101 int done; 102 (void) pthread_mutex_lock(&sp->rs_lock); 103 assert(sp->rs_refcnt > 0); 104 sp->rs_refcnt--; 105 done = ((sp->rs_flags & RC_SNAPSHOT_DEAD) && 106 sp->rs_refcnt == 0 && sp->rs_childref == 0); 107 (void) pthread_mutex_unlock(&sp->rs_lock); 108 109 if (done) 110 snapshot_free(sp); 111 } 112 113 void 114 rc_snaplevel_hold(rc_snaplevel_t *lvl) 115 { 116 rc_snapshot_t *sp = lvl->rsl_parent; 117 (void) pthread_mutex_lock(&sp->rs_lock); 118 sp->rs_childref++; 119 assert(sp->rs_childref > 0); 120 (void) pthread_mutex_unlock(&sp->rs_lock); 121 } 122 123 void 124 rc_snaplevel_rele(rc_snaplevel_t *lvl) 125 { 126 int done; 127 rc_snapshot_t *sp = lvl->rsl_parent; 128 (void) pthread_mutex_lock(&sp->rs_lock); 129 assert(sp->rs_childref > 0); 130 sp->rs_childref--; 131 done = ((sp->rs_flags & RC_SNAPSHOT_DEAD) && 132 sp->rs_refcnt == 0 && sp->rs_childref == 0); 133 (void) pthread_mutex_unlock(&sp->rs_lock); 134 135 if (done) 136 snapshot_free(sp); 137 } 138 139 static snapshot_bucket_t * 140 snapshot_hold_bucket(uint32_t snap_id) 141 { 142 snapshot_bucket_t *bp = SNAPSHOT_BUCKET(snap_id); 143 (void) pthread_mutex_lock(&bp->sb_lock); 144 return (bp); 145 } 146 147 static void 148 snapshot_rele_bucket(snapshot_bucket_t *bp) 149 { 150 assert(MUTEX_HELD(&bp->sb_lock)); 151 (void) pthread_mutex_unlock(&bp->sb_lock); 152 } 153 154 static rc_snapshot_t * 155 snapshot_lookup_unlocked(snapshot_bucket_t *bp, uint32_t snap_id) 156 { 157 rc_snapshot_t *sp; 158 159 assert(MUTEX_HELD(&bp->sb_lock)); 160 assert(bp == SNAPSHOT_BUCKET(snap_id)); 161 162 for (sp = bp->sb_head; sp != NULL; sp = sp->rs_hash_next) { 163 if (sp->rs_snap_id == snap_id) { 164 rc_snapshot_hold(sp); 165 return (sp); 166 } 167 } 168 return (NULL); 169 } 170 171 static void 172 snapshot_insert_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp) 173 { 174 assert(MUTEX_HELD(&bp->sb_lock)); 175 assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id)); 176 177 assert(sp->rs_hash_next == NULL); 178 179 sp->rs_hash_next = bp->sb_head; 180 bp->sb_head = sp; 181 } 182 183 static void 184 snapshot_remove_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp) 185 { 186 rc_snapshot_t **spp; 187 188 assert(MUTEX_HELD(&bp->sb_lock)); 189 assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id)); 190 191 assert(sp->rs_hash_next == NULL); 192 193 for (spp = &bp->sb_head; *spp != NULL; spp = &(*spp)->rs_hash_next) 194 if (*spp == sp) 195 break; 196 197 assert(*spp == sp); 198 *spp = sp->rs_hash_next; 199 sp->rs_hash_next = NULL; 200 } 201 202 /* 203 * Look up the snapshot with id snap_id in the hash table, or create it 204 * & populate it with its snaplevels if it's not in the hash table yet. 205 * 206 * Fails with 207 * _NO_RESOURCES 208 */ 209 int 210 rc_snapshot_get(uint32_t snap_id, rc_snapshot_t **snpp) 211 { 212 snapshot_bucket_t *bp; 213 rc_snapshot_t *sp; 214 int r; 215 216 bp = snapshot_hold_bucket(snap_id); 217 sp = snapshot_lookup_unlocked(bp, snap_id); 218 if (sp != NULL) { 219 snapshot_rele_bucket(bp); 220 (void) pthread_mutex_lock(&sp->rs_lock); 221 while (sp->rs_flags & RC_SNAPSHOT_FILLING) 222 (void) pthread_cond_wait(&sp->rs_cv, &sp->rs_lock); 223 224 if (sp->rs_flags & RC_SNAPSHOT_DEAD) { 225 (void) pthread_mutex_unlock(&sp->rs_lock); 226 rc_snapshot_rele(sp); 227 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 228 } 229 assert(sp->rs_flags & RC_SNAPSHOT_READY); 230 (void) pthread_mutex_unlock(&sp->rs_lock); 231 *snpp = sp; 232 return (REP_PROTOCOL_SUCCESS); 233 } 234 sp = snapshot_alloc(); 235 sp->rs_snap_id = snap_id; 236 sp->rs_flags |= RC_SNAPSHOT_FILLING; 237 snapshot_insert_unlocked(bp, sp); 238 snapshot_rele_bucket(bp); 239 240 /* 241 * Now fill in the snapshot tree 242 */ 243 r = object_fill_snapshot(sp); 244 if (r != REP_PROTOCOL_SUCCESS) { 245 assert(r == REP_PROTOCOL_FAIL_NO_RESOURCES); 246 247 /* 248 * failed -- first remove it from the hash table, then kill it 249 */ 250 bp = snapshot_hold_bucket(snap_id); 251 snapshot_remove_unlocked(bp, sp); 252 snapshot_rele_bucket(bp); 253 254 (void) pthread_mutex_lock(&sp->rs_lock); 255 sp->rs_flags &= ~RC_SNAPSHOT_FILLING; 256 sp->rs_flags |= RC_SNAPSHOT_DEAD; 257 (void) pthread_cond_broadcast(&sp->rs_cv); 258 (void) pthread_mutex_unlock(&sp->rs_lock); 259 rc_snapshot_rele(sp); /* may free sp */ 260 return (r); 261 } 262 (void) pthread_mutex_lock(&sp->rs_lock); 263 sp->rs_flags &= ~RC_SNAPSHOT_FILLING; 264 sp->rs_flags |= RC_SNAPSHOT_READY; 265 (void) pthread_cond_broadcast(&sp->rs_cv); 266 (void) pthread_mutex_unlock(&sp->rs_lock); 267 *snpp = sp; 268 return (REP_PROTOCOL_SUCCESS); /* pass on creation reference */ 269 } 270