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