diff options
author | djl <none@none> | 2006-09-29 06:00:17 -0700 |
---|---|---|
committer | djl <none@none> | 2006-09-29 06:00:17 -0700 |
commit | cb5caa98562cf06753163f558cbcfe30b8f4673a (patch) | |
tree | 7a24623821583899295e29553207e69701b471ff /usr/src/cmd/nscd/nscd_access.c | |
parent | 350f572a3fa518fc3690d53066c2c54fd03b5a08 (diff) | |
download | illumos-joyent-cb5caa98562cf06753163f558cbcfe30b8f4673a.tar.gz |
PSARC 2005/133 Sparks: Name Service Switch 2
4406529 artificial limit of 10 threads per backend
4516075 LDAP connections could be reused more
4696964 LDAP naming services should support Kerberos authentication
4740951 Need host based authentication options in Native LDAP
4952533 Some backends of gethostby* do not set h_errno correctly
4979596 getXbyY calls should have better buffer mechanism
5028908 /usr/bin/logins accesses free memory deep in nss_getent_u().
5046881 nscd: old-data-ok parameter is not useful, should go away
6225323 NSS/nscd Enhancements (Sparks Project)
--HG--
rename : usr/src/cmd/nscd/attrstr.c => deleted_files/usr/src/cmd/nscd/attrstr.c
rename : usr/src/cmd/nscd/hash.c => deleted_files/usr/src/cmd/nscd/hash.c
rename : usr/src/cmd/nscd/nscd_parse.c => deleted_files/usr/src/cmd/nscd/nscd_parse.c
rename : usr/src/cmd/nscd/nscd.h => usr/src/cmd/nscd/cache.h
Diffstat (limited to 'usr/src/cmd/nscd/nscd_access.c')
-rw-r--r-- | usr/src/cmd/nscd/nscd_access.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/usr/src/cmd/nscd/nscd_access.c b/usr/src/cmd/nscd/nscd_access.c new file mode 100644 index 0000000000..36f168652b --- /dev/null +++ b/usr/src/cmd/nscd/nscd_access.c @@ -0,0 +1,588 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "nscd_db.h" +#include "nscd_log.h" + +/* + * Access control structure for a piece of nscd data. This structure + * is always tagged before the nscd data. nscd_alloc, which should + * be used to allocate memory that requires access control or usage + * count control, will initialize this access control structure at the + * start of the memory returned to the caller. + */ +struct nscd_access_s { + void *data; /* addr of real data */ + void (*free_func)(nscd_acc_data_t *data); /* destructor */ + mutex_t mutex; /* protect this structure */ + mutex_t *data_mutex; + rwlock_t *data_rwlock; + cond_t *data_cond; + int nUse; /* usage count */ + int type; + int delete; /* no longer available */ + nscd_seq_num_t seq_num; /* sequence number */ +}; + +/* size should be in multiple of 8 */ +static int sizeof_access = roundup(sizeof (nscd_access_t)); + +#define ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA 0 +#define ASSERT_ACCESS_DATA \ + if (access->data != data) \ + assert(ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA) + +#define SET_ACCESS_PTR \ + access = (nscd_access_t *) \ + ((void *)((char *)data - sizeof_access)) + +static void _nscd_free(nscd_acc_data_t *data); + +/* + * FUNCTION: _nscd_release + * + * Decrements the usage count maintained in the access data + * tagged before 'data'. Delete the nscd data item if the delete + * flag is set and the usage count reaches 0. + */ +void +_nscd_release( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_release"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p, " + "seq = %lld, nUse = %d\n", + data, access->data, access->seq_num, access->nUse); + ASSERT_ACCESS_DATA; + + (void) mutex_lock(&access->mutex); + access->nUse--; + if (access->nUse < 0) { +#define ACCESS_NUSE_LESS_THAN_ZERO 0 + assert(ACCESS_NUSE_LESS_THAN_ZERO); + } + if (access->nUse <= 0 && + access->delete == 1) { + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "deleting data %p\n", access->data); + (access->free_func)(access->data); + + /* + * if we get here, no other thread could be + * holding the access->mutex lock, It is safe + * to free the memory containing the mutex + * structure. No mutex_unlock is necessary. + */ + _nscd_free(data); + } else + (void) mutex_unlock(&access->mutex); +} + + +/* + * FUNCTION: _nscd_destroy + * + * Marks the nscd data item as to-be-deleted and then releases + * (If the usage count happens to be zero, then _nscd_release() + * will destroy the data.) + * + * Note that _nscd_destroy should only be called if the + * caller has created the nscd data with _nscd_alloc + * (with the exception of _nscd_set). That nscd data + * item should be private to the caller. + */ +static void +_nscd_destroy( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_destroy"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + (void) mutex_lock(&access->mutex); + access->delete = 1; + (void) mutex_unlock(&access->mutex); + + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_get + * + * Increment the usage count by one if 'data' can + * be found in the internal address database. + */ +nscd_acc_data_t * +_nscd_get( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret = data; + rwlock_t *addr_rwlock; + char *me = "_nscd_get"; + + if (data == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p, seq#= %lld, nUse = %d\n", + data, access->data, access->seq_num, access->nUse); + ASSERT_ACCESS_DATA; + + /* + * see if this addr is still valid, + * if so, _nscd_is_int_addr will + * do a read lock on the returned + * multiple readers/single writer lock + * to prevent the access data from being + * deleted while it is being accessed. + */ + if ((addr_rwlock = _nscd_is_int_addr(data, + access->seq_num)) == NULL) { + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "internal address %p not found\n", data); + assert(addr_rwlock != NULL); + return (NULL); + } + + (void) mutex_lock(&access->mutex); + if (access->delete == 1) + ret = NULL; + else + access->nUse++; + (void) mutex_unlock(&access->mutex); + + /* + * done with the multiple readers/single writer lock + */ + (void) rw_unlock(addr_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_set + * + * _nscd_set sets the address of a nscd data item + * to 'new' and delete the old nscd data (old). + * The pointer 'new' is returned. + */ +nscd_acc_data_t * +_nscd_set( + nscd_acc_data_t *old, + nscd_acc_data_t *new) +{ + nscd_acc_data_t *old_data, *new_data; + char *me = "_nscd_set"; + + if (new == old) + return (old); + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "new = %p, old = %p\n", new, old); + + old_data = _nscd_get(old); + new_data = _nscd_get(new); + + if (old_data != new_data) { + + _nscd_destroy(old_data); + _nscd_release(new_data); + return (new_data); + } + + /* if old_data == new_data, both must be NULL */ + return (NULL); +} + +/* + * FUNCTION: _nscd_rdlock + * + * Lock (rw_rdlock) a nscd data item for reading. The caller + * needs to call _nscd_rw_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_rdlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_rdlock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_rdlock(access->data_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_wrlock + * + * Lock (rw_wrlock) a nscd data item for writing. The caller + * needs to call _nscd_rw_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_wrlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_wrlock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_wrlock(access->data_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_rw_unlock + * + * Unlock (rw_unlock) a locked nscd data item. + */ +void +_nscd_rw_unlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_rw_unlock"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", + data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_unlock(access->data_rwlock); + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_rw_unlock_no_release + * + * Unlock (rw_unlock) a locked nscd data item but without release + * it, i.e., without decrement the usage count to indicate that + * the data item is still being referenced. + */ +void +_nscd_rw_unlock_no_release( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_unlock(access->data_rwlock); +} + +/* + * FUNCTION: _nscd_mutex_lock + * + * Lock (mutex_lock) a nscd data item. The caller needs + * to call _nscd_mutex_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_mutex_lock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_mutex_lock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_mutex != NULL); + + (void) mutex_lock(access->data_mutex); + + return (ret); +} + + +/* + * FUNCTION: _nscd_mutex_unlock + * + * Unlock a locked nscd data item (that were locked by _nscd_mutex_lock).. + */ +void +_nscd_mutex_unlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_mutex_unlock"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_mutex != NULL); + + (void) mutex_unlock(access->data_mutex); + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_cond_wait + * + * Perform a condition wait with the cond_t and mutex_t associated + * with data. + */ +void +_nscd_cond_wait( + nscd_acc_data_t *data, cond_t *cond) +{ + nscd_access_t *access; + char *me = "_nscd_cond_wait"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_cond != NULL && access->data_mutex != NULL); + + if (cond == NULL) + (void) cond_wait(access->data_cond, access->data_mutex); + else + (void) cond_wait(cond, access->data_mutex); +} + +/* + * FUNCTION: _nscd_cond_signal + * + * Perform a condition signal with the cond_t associated with 'data'. + */ +void +_nscd_cond_signal( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_cond_signal"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_cond != NULL); + + (void) cond_signal(access->data_cond); +} + +/* + * FUNCTION: _nscd_alloc + * + * Allocate a piece of nscd memory. 'data_free' + * is the function to invoke to free the data + * stored in this memory, i.e., the desctrctor. + * 'option' indicate whether a mutex or a + * readers/writer (or both, or none) should also + * be allocated. + */ +nscd_acc_data_t * +_nscd_alloc( + int type, + size_t size, + void (*data_free)(nscd_acc_data_t *data), + int option) +{ + nscd_access_t *access; + nscd_acc_data_t *ptr; + nscd_seq_num_t seq_num; + rwlock_t *rwlock = NULL; + mutex_t *mutex = NULL; + cond_t *cond = NULL; + + if ((ptr = (nscd_acc_data_t *)calloc(1, + size + sizeof_access)) == NULL) + return (NULL); + if (option & NSCD_ALLOC_MUTEX) { + if ((mutex = (mutex_t *)calloc(1, sizeof (mutex_t))) == + NULL) { + free(ptr); + return (NULL); + } else + (void) mutex_init(mutex, USYNC_THREAD, NULL); + } + if (option & NSCD_ALLOC_RWLOCK) { + if ((rwlock = (rwlock_t *)calloc(1, sizeof (rwlock_t))) == + NULL) { + free(ptr); + free(mutex); + return (NULL); + } else + (void) rwlock_init(rwlock, USYNC_THREAD, NULL); + } + if (option & NSCD_ALLOC_COND) { + if ((cond = (cond_t *)calloc(1, sizeof (cond_t))) == + NULL) { + free(ptr); + free(mutex); + free(rwlock); + return (NULL); + } else + (void) cond_init(cond, USYNC_THREAD, NULL); + } + + /* get current sequence number */ + seq_num = _nscd_get_seq_num(); + + access = (nscd_access_t *)ptr; + access->data = (char *)ptr + sizeof_access; + access->data_mutex = mutex; + access->data_rwlock = rwlock; + access->data_cond = cond; + access->nUse = 0; + access->delete = 0; + access->type = type; + access->free_func = data_free; + access->seq_num = seq_num; + + /* add the address to the internal address database */ + if (_nscd_add_int_addr(access->data, type, + seq_num) != NSCD_SUCCESS) { + free(ptr); + return (NULL); + } + + return (access->data); +} + +/* + * FUNCTION: _nscd_free + * + * Free a piece of nscd memory. + */ +static void +_nscd_free( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + ASSERT_ACCESS_DATA; + + /* remove the address from the internal address database */ + _nscd_del_int_addr(access->data, access->seq_num); + + if (access->data_mutex) + free(access->data_mutex); + if (access->data_rwlock) + free(access->data_rwlock); + if (access->data_cond) + free(access->data_cond); + + (void) memset(access, 0, sizeof (*access)); + + free(access); +} |