nscd_intaddr.c revision 2830:5228d1267a01
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
33static rwlock_t		addrDB_rwlock = DEFAULTRWLOCK;
34static nscd_db_t	*addrDB = NULL;
35
36/*
37 * internal structure representing a nscd internal address
38 */
39typedef 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 */
53void *
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 */
85nscd_rc_t
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 */
130rwlock_t *
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 */
183void
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 */
241void
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