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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include "nscd_db.h"
31 #include "nscd_log.h"
32
33 static rwlock_t addrDB_rwlock = DEFAULTRWLOCK;
34 static nscd_db_t *addrDB = NULL;
35
36 /*
37 * internal structure representing a nscd internal address
38 */
39 typedef struct nscd_int_addr {
40 int to_delete; /* no longer valid */
41 int type;
42 void *ptr;
43 nscd_seq_num_t seq_num;
44 rwlock_t rwlock; /* used to serialize get and destroy */
45 } nscd_int_addr_t;
46
47 /*
48 * FUNCTION: _nscd_create_int_addrDB
49 *
50 * Create the internal address database to keep track of the
51 * memory allocated by _nscd_alloc.
52 */
53 void *
_nscd_create_int_addrDB()54 _nscd_create_int_addrDB()
55 {
56
57 nscd_db_t *ret;
58 char *me = "_nscd_create_int_addrDB";
59
60 _NSCD_LOG(NSCD_LOG_INT_ADDR | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
61 (me, "initializing the internal address database\n");
62
63 (void) rw_wrlock(&addrDB_rwlock);
64
65 if (addrDB != NULL) {
66 (void) rw_unlock(&addrDB_rwlock);
67 return (addrDB);
68 }
69
70 ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE);
71
72 if (ret != NULL)
73 addrDB = ret;
74
75 (void) rw_unlock(&addrDB_rwlock);
76
77 return (ret);
78 }
79
80 /*
81 * FUNCTION: _nscd_add_int_addr
82 *
83 * Add an address of 'type' to the internal address database.
84 */
85 nscd_rc_t
_nscd_add_int_addr(void * ptr,int type,nscd_seq_num_t seq_num)86 _nscd_add_int_addr(
87 void *ptr,
88 int type,
89 nscd_seq_num_t seq_num)
90 {
91 int size;
92 char buf[2 * sizeof (ptr) + 1];
93 nscd_db_entry_t *db_entry;
94 nscd_int_addr_t *int_addr;
95
96 if (ptr == NULL)
97 return (NSCD_INVALID_ARGUMENT);
98
99 (void) snprintf(buf, sizeof (buf), "%p", ptr);
100
101 size = sizeof (*int_addr);
102
103 db_entry = _nscd_alloc_db_entry(NSCD_DATA_ADDR,
104 (const char *)buf, size, 1, 1);
105 if (db_entry == NULL)
106 return (NSCD_NO_MEMORY);
107
108 int_addr = (nscd_int_addr_t *)*(db_entry->data_array);
109 int_addr->ptr = ptr;
110 int_addr->type = type;
111 int_addr->seq_num = seq_num;
112 (void) rwlock_init(&int_addr->rwlock, USYNC_THREAD, NULL);
113
114 (void) rw_wrlock(&addrDB_rwlock);
115 (void) _nscd_add_db_entry(addrDB, buf, db_entry,
116 NSCD_ADD_DB_ENTRY_FIRST);
117 (void) rw_unlock(&addrDB_rwlock);
118
119 return (NSCD_SUCCESS);
120 }
121
122 /*
123 * FUNCTION: _nscd_is_int_addr
124 *
125 * Check to see if an address can be found in the internal
126 * address database, if so, obtain a reader lock on the
127 * associated rw_lock. The caller needs to unlock it when
128 * done using the data.
129 */
130 rwlock_t *
_nscd_is_int_addr(void * ptr,nscd_seq_num_t seq_num)131 _nscd_is_int_addr(
132 void *ptr,
133 nscd_seq_num_t seq_num)
134 {
135 char *me = "_nscd_is_int_addr";
136 char ptrstr[1 + 2 * sizeof (ptr)];
137 rwlock_t *addr_rwlock;
138 const nscd_db_entry_t *db_entry;
139
140 if (ptr == NULL)
141 return (NULL);
142
143 (void) snprintf(ptrstr, sizeof (ptrstr), "%p", ptr);
144
145 (void) rw_rdlock(&addrDB_rwlock);
146
147 db_entry = _nscd_get_db_entry(addrDB, NSCD_DATA_ADDR,
148 (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0);
149
150 if (db_entry != NULL) {
151 nscd_int_addr_t *int_addr;
152
153 int_addr = (nscd_int_addr_t *)*(db_entry->data_array);
154 addr_rwlock = &int_addr->rwlock;
155 (void) rw_rdlock(addr_rwlock);
156
157 /*
158 * If the data is marked as to be deleted
159 * or the sequence number does not match,
160 * return NULL.
161 */
162 if (int_addr->to_delete == 1 ||
163 int_addr->seq_num != seq_num) {
164 (void) rw_unlock(addr_rwlock);
165 addr_rwlock = NULL;
166 }
167
168 _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_DEBUG)
169 (me, "found %p, seq# = %lld\n", ptr, int_addr->seq_num);
170 } else
171 addr_rwlock = NULL;
172
173 (void) rw_unlock(&addrDB_rwlock);
174
175 return (addr_rwlock);
176 }
177
178 /*
179 * FUNCTION: _nscd_del_int_addr
180 *
181 * Delete an address from the internal address database.
182 */
183 void
_nscd_del_int_addr(void * ptr,nscd_seq_num_t seq_num)184 _nscd_del_int_addr(
185 void *ptr,
186 nscd_seq_num_t seq_num)
187 {
188 char *me = "_nscd_del_int_addr";
189 char ptrstr[1 + 2 * sizeof (ptr)];
190 rwlock_t *addr_rwlock;
191 nscd_int_addr_t *int_addr;
192 const nscd_db_entry_t *db_entry;
193
194 if (ptr == NULL)
195 return;
196
197 _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_DEBUG)
198 (me, "deleting int addr %p (%d)\n", ptr, seq_num);
199 (void) snprintf(ptrstr, sizeof (ptrstr), "%p", ptr);
200
201 (void) rw_rdlock(&addrDB_rwlock);
202 /*
203 * first find the db entry and make sure that
204 * no one is currently locking it. i.e.,
205 * no one is waiting to use the same address.
206 * If it is locked, rw_wrlock() will not return
207 * until it is unlocked.
208 */
209 db_entry = _nscd_get_db_entry(addrDB,
210 NSCD_DATA_ADDR,
211 (const char *)ptrstr,
212 NSCD_GET_FIRST_DB_ENTRY, 0);
213 if (db_entry != NULL) {
214 int_addr = (nscd_int_addr_t *)*(db_entry->data_array);
215 addr_rwlock = &int_addr->rwlock;
216 (void) rw_wrlock(addr_rwlock);
217 } else {
218 (void) rw_unlock(&addrDB_rwlock);
219 return;
220 }
221 (void) rw_unlock(&addrDB_rwlock);
222
223 /*
224 * delete the db entry if the sequence numbers match
225 */
226 if (int_addr->seq_num == seq_num) {
227 (void) rw_wrlock(&addrDB_rwlock);
228 (void) _nscd_delete_db_entry(addrDB,
229 NSCD_DATA_ADDR,
230 (const char *)ptrstr,
231 NSCD_DEL_FIRST_DB_ENTRY, 0);
232 (void) rw_unlock(&addrDB_rwlock);
233 }
234 }
235
236 /*
237 * FUNCTION: _nscd_destroy_int_addrDB
238 *
239 * Destroy the internal address database.
240 */
241 void
_nscd_destroy_int_addrDB()242 _nscd_destroy_int_addrDB()
243 {
244 (void) rw_wrlock(&addrDB_rwlock);
245 _nscd_free_db(addrDB);
246 addrDB = NULL;
247 (void) rw_unlock(&addrDB_rwlock);
248 }
249