8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / svc / configd / snapshot.c
blob66e92123fd43e5c45463e08ef3376193cca95b8f
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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"
36 typedef struct snapshot_bucket {
37 pthread_mutex_t sb_lock;
38 rc_snapshot_t *sb_head;
40 char sb_pad[64 - sizeof (pthread_mutex_t) -
41 sizeof (rc_snapshot_t *)];
42 } snapshot_bucket_t;
44 #define SN_HASH_SIZE 64
45 #define SN_HASH_MASK (SN_HASH_SIZE - 1)
47 #pragma align 64(snapshot_hash)
48 static snapshot_bucket_t snapshot_hash[SN_HASH_SIZE];
50 #define SNAPSHOT_BUCKET(h) (&snapshot_hash[(h) & SN_HASH_MASK])
52 static rc_snapshot_t *
53 snapshot_alloc(void)
55 rc_snapshot_t *sp;
56 sp = uu_zalloc(sizeof (*sp));
58 (void) pthread_mutex_init(&sp->rs_lock, NULL);
59 (void) pthread_cond_init(&sp->rs_cv, NULL);
61 sp->rs_refcnt++;
62 return (sp);
65 static void
66 snapshot_free(rc_snapshot_t *sp)
68 rc_snaplevel_t *lvl, *next;
70 assert(sp->rs_refcnt == 0 && sp->rs_childref == 0);
72 (void) pthread_mutex_destroy(&sp->rs_lock);
73 (void) pthread_cond_destroy(&sp->rs_cv);
75 for (lvl = sp->rs_levels; lvl != NULL; lvl = next) {
76 next = lvl->rsl_next;
78 assert(lvl->rsl_parent == sp);
79 lvl->rsl_parent = NULL;
81 if (lvl->rsl_service)
82 free((char *)lvl->rsl_service);
83 if (lvl->rsl_instance)
84 free((char *)lvl->rsl_instance);
86 uu_free(lvl);
88 uu_free(sp);
91 static void
92 rc_snapshot_hold(rc_snapshot_t *sp)
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);
100 void
101 rc_snapshot_rele(rc_snapshot_t *sp)
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);
111 if (done)
112 snapshot_free(sp);
115 void
116 rc_snaplevel_hold(rc_snaplevel_t *lvl)
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);
125 void
126 rc_snaplevel_rele(rc_snaplevel_t *lvl)
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);
137 if (done)
138 snapshot_free(sp);
141 static snapshot_bucket_t *
142 snapshot_hold_bucket(uint32_t snap_id)
144 snapshot_bucket_t *bp = SNAPSHOT_BUCKET(snap_id);
145 (void) pthread_mutex_lock(&bp->sb_lock);
146 return (bp);
149 static void
150 snapshot_rele_bucket(snapshot_bucket_t *bp)
152 assert(MUTEX_HELD(&bp->sb_lock));
153 (void) pthread_mutex_unlock(&bp->sb_lock);
156 static rc_snapshot_t *
157 snapshot_lookup_unlocked(snapshot_bucket_t *bp, uint32_t snap_id)
159 rc_snapshot_t *sp;
161 assert(MUTEX_HELD(&bp->sb_lock));
162 assert(bp == SNAPSHOT_BUCKET(snap_id));
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);
170 return (NULL);
173 static void
174 snapshot_insert_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp)
176 assert(MUTEX_HELD(&bp->sb_lock));
177 assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id));
179 assert(sp->rs_hash_next == NULL);
181 sp->rs_hash_next = bp->sb_head;
182 bp->sb_head = sp;
185 static void
186 snapshot_remove_unlocked(snapshot_bucket_t *bp, rc_snapshot_t *sp)
188 rc_snapshot_t **spp;
190 assert(MUTEX_HELD(&bp->sb_lock));
191 assert(bp == SNAPSHOT_BUCKET(sp->rs_snap_id));
193 assert(sp->rs_hash_next == NULL);
195 for (spp = &bp->sb_head; *spp != NULL; spp = &(*spp)->rs_hash_next)
196 if (*spp == sp)
197 break;
199 assert(*spp == sp);
200 *spp = sp->rs_hash_next;
201 sp->rs_hash_next = NULL;
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.
208 * Fails with
209 * _NO_RESOURCES
212 rc_snapshot_get(uint32_t snap_id, rc_snapshot_t **snpp)
214 snapshot_bucket_t *bp;
215 rc_snapshot_t *sp;
216 int r;
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);
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);
231 assert(sp->rs_flags & RC_SNAPSHOT_READY);
232 (void) pthread_mutex_unlock(&sp->rs_lock);
233 *snpp = sp;
234 return (REP_PROTOCOL_SUCCESS);
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);
243 * Now fill in the snapshot tree
245 r = object_fill_snapshot(sp);
246 if (r != REP_PROTOCOL_SUCCESS) {
247 assert(r == REP_PROTOCOL_FAIL_NO_RESOURCES);
250 * failed -- first remove it from the hash table, then kill it
252 bp = snapshot_hold_bucket(snap_id);
253 snapshot_remove_unlocked(bp, sp);
254 snapshot_rele_bucket(bp);
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);
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 */