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
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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
*)];
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
*
56 sp
= uu_zalloc(sizeof (*sp
));
58 (void) pthread_mutex_init(&sp
->rs_lock
, NULL
);
59 (void) pthread_cond_init(&sp
->rs_cv
, NULL
);
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
) {
78 assert(lvl
->rsl_parent
== sp
);
79 lvl
->rsl_parent
= NULL
;
82 free((char *)lvl
->rsl_service
);
83 if (lvl
->rsl_instance
)
84 free((char *)lvl
->rsl_instance
);
92 rc_snapshot_hold(rc_snapshot_t
*sp
)
94 (void) pthread_mutex_lock(&sp
->rs_lock
);
96 assert(sp
->rs_refcnt
> 0);
97 (void) pthread_mutex_unlock(&sp
->rs_lock
);
101 rc_snapshot_rele(rc_snapshot_t
*sp
)
104 (void) pthread_mutex_lock(&sp
->rs_lock
);
105 assert(sp
->rs_refcnt
> 0);
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
);
116 rc_snaplevel_hold(rc_snaplevel_t
*lvl
)
118 rc_snapshot_t
*sp
= lvl
->rsl_parent
;
119 (void) pthread_mutex_lock(&sp
->rs_lock
);
121 assert(sp
->rs_childref
> 0);
122 (void) pthread_mutex_unlock(&sp
->rs_lock
);
126 rc_snaplevel_rele(rc_snaplevel_t
*lvl
)
129 rc_snapshot_t
*sp
= lvl
->rsl_parent
;
130 (void) pthread_mutex_lock(&sp
->rs_lock
);
131 assert(sp
->rs_childref
> 0);
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
);
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
);
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
)
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
);
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
;
186 snapshot_remove_unlocked(snapshot_bucket_t
*bp
, rc_snapshot_t
*sp
)
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
)
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.
212 rc_snapshot_get(uint32_t snap_id
, rc_snapshot_t
**snpp
)
214 snapshot_bucket_t
*bp
;
218 bp
= snapshot_hold_bucket(snap_id
);
219 sp
= snapshot_lookup_unlocked(bp
, snap_id
);
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
);
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 */
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
);
270 return (REP_PROTOCOL_SUCCESS
); /* pass on creation reference */