cb5caa98562cf06753163f558cbcfe30b8f4673adjl * CDDL HEADER START
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * The contents of this file are subject to the terms of the
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Common Development and Distribution License (the "License").
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * You may not use this file except in compliance with the License.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * See the License for the specific language governing permissions
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * and limitations under the License.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * When distributing Covered Code, include this CDDL HEADER in each
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * If applicable, add the following below this CDDL HEADER, with the
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * fields enclosed by brackets "[]" replaced with your own identifying
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * information: Portions Copyright [yyyy] [name of copyright owner]
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * CDDL HEADER END
07925104db56e5c3eacc4865b918bd16af5cec59gww * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Cache routines for nscd
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic nscd_rc_t lookup_cache(nsc_lookup_args_t *, nscd_cfg_cache_t *,
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void delete_entry(nsc_db_t *, nsc_ctx_t *, nsc_entry_t *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void print_entry(nsc_db_t *, time_t, nsc_entry_t *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic nsc_entry_t *hash_find(nsc_db_t *, nsc_entry_t *, uint_t *, nscd_bool_t);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void getxy_keepalive(nsc_ctx_t *, nsc_db_t *, int, int);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void nsc_db_str_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void nsc_db_int_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void nsc_db_any_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic int nsc_db_cis_key_compar(const void *, const void *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic int nsc_db_ces_key_compar(const void *, const void *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic int nsc_db_int_key_compar(const void *, const void *);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic uint_t nsc_db_cis_key_gethash(nss_XbyY_key_t *, int);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic uint_t nsc_db_ces_key_gethash(nss_XbyY_key_t *, int);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic uint_t nsc_db_int_key_gethash(nss_XbyY_key_t *, int);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* no result, copy header only (status, errno, etc) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * lookup result returned, data to copy is the packed
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * header plus result (add 1 for the terminating NULL
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * just in case)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* allocate cache packed buffer */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (dphdr != NULL && d->bufsize <= slen && d->bufsize != 0) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* old buffer too small, free it */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* get new buffer */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic cache_init_ctx_t cache_init_ctx[CACHE_CTX_COUNT] = {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Given database name 'dbname' find cache index
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (i);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (-1);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Given database name 'dbname' retrieve cache context,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if not created yet, allocate and initialize it.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (i == -1)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Generate a log string to identify backend operation in debug logs
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_str_key_getlogstr(char *name, char *whoami, size_t len,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) snprintf(whoami, len, "%s [key=%s]", name, argp->key.name);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_int_key_getlogstr(char *name, char *whoami, size_t len,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.number);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl/*ARGSUSED*/
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_any_key_getlogstr(char *name, char *whoami, size_t len,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Returns cache based on dbop
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * integer compare routine for _NSC_DB_INT_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (_NSC_INT_KEY_CMP(e1->key.number, e2->key.number));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * case sensitive name compare routine for _NSC_DB_CES_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjl res = strncmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * case insensitive name compare routine _NSC_DB_CIS_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjl res = strncasecmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * macro used to generate elf hashes for strings
cb5caa98562cf06753163f558cbcfe30b8f4673adjl while (*str) { \
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * cis hash function
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * ces hash function
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * one-at-a-time hash function
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * case insensitive name gethash routine _NSC_DB_CIS_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_cis_key_gethash(nss_XbyY_key_t *key, int htsize) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * case sensitive name gethash routine _NSC_DB_CES_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_ces_key_gethash(nss_XbyY_key_t *key, int htsize) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * integer gethash routine _NSC_DB_INT_KEY
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_db_int_key_gethash(nss_XbyY_key_t *key, int htsize) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (db_gethash(&key->number, sizeof (key->number), htsize));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Find entry in the hash table
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if cmp == nscd_true)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * return entry only if the keys match
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * return entry in the hash location without checking the keys
cb5caa98562cf06753163f558cbcfe30b8f4673adjlhash_find(nsc_db_t *nscdb, nsc_entry_t *entry, uint_t *hash,
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlprint_entry(nsc_db_t *nscdb, time_t now, nsc_entry_t *entry) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t status: new entry\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t status: update pending\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t status: lookup pending\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t status: discarded entry\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t hits: %u\n"), entry->stats.hits);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) nscdb->getlogstr(nscdb->name, whoami, sizeof (whoami), &args);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t positive hits: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t negative hits: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t positive misses: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t negative misses: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t total entries: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t queries queued: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t queries dropped: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t cache invalidations: %lu\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t cache hit rate: %10.1f\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t per user cache: %s\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t avoid name service: %s\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t check file interval: %d\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t positive ttl: %d\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t negative ttl: %d\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t keep hot count: %d\n"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\t max entries: %lu%s"),
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (entry = avl_first(&nscdb->tree), i = 0; entry != NULL;
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl gettext("Starting with the most recently accessed:\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (entry = nscdb->qtail, i = 0; entry; entry = entry->qnext) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* already in the desired position */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* new queue */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* new entry (prev == NULL AND tail != entry) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* existing entry */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Init cache
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Create cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik int (*compar) (const void *, const void *),
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Assign compare routine */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* The cache is an AVL tree */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl avl_create(&nscdb->tree, nscdb->compar, sizeof (nsc_entry_t),
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Assign log routine */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* The AVL tree based cache uses a hash table for quick access */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (htsize != 0) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Determine hash table size based on type */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Create the hash table */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl nscdb->htable = calloc(htsize, sizeof (*(nscdb->htable)));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Assign gethash routine */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) mutex_init(&nscdb->db_mutex, USYNC_THREAD, NULL);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl/* ARGSUSED */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl/* ARGSUSED */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* group data */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* global config */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* non-global config for all dbs */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* non-global config for a specific db */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* ignore non-caching databases */
18bdb8a7484e018149ac9a2766c97bdea9752c87michen if (get_cache_ctx(nswdb->name, &ctx) != NSCD_SUCCESS)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* individual data */
18bdb8a7484e018149ac9a2766c97bdea9752c87michen if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* global config */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* non-global config for all dbs */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* non-global config for a specific db */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* ignore non-caching databases */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * get stat
cb5caa98562cf06753163f558cbcfe30b8f4673adjl/* ARGSUSED */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if ((rc = get_cache_ctx(nswdb->name, &ctx)) != NSCD_SUCCESS) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * This function should only be called when nscd is
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * not a daemon.
cb5caa98562cf06753163f558cbcfe30b8f4673adjlnsc_info(nsc_ctx_t *ctx, char *dbname, nscd_cfg_cache_t cfg[],
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (me, "%s: unable to create cache context - no memory\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * This function should only be called when nscd is
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * not a daemon.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) fprintf(stdout, gettext("invalid cache name\n"));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl#endif /* NSCD_DEBUG */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * These macros are for exclusive use of nsc_lookup
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Juriknsc_lookup_no_cache(nsc_lookup_args_t *largs, const char *str)
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik (me, "%s: name service lookup (bypassing cache)\n", str);
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik (me, "%s: name service lookup status = %d\n", str, status);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * This function starts the revalidation and reaper threads
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * for a cache
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * kick off the revalidate thread (if necessary)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (thr_create(NULL, NULL, (void *(*)(void *))revalidate,
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik (me, "thr_create (revalidate thread for %s): %s\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * kick off the reaper thread (if necessary)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Examine the packed buffer, see if the front-end parameters
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * indicate that the caller specified nsswitch config should be
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * used for the lookup. Return 1 if yes, otherwise 0.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if ((enum nss_dbp_flags)pdbd->flags & NSS_USE_DEFAULT_CONFIG) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (1);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* return NSS_ERROR if not enough room to copy result */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* some frontend code expects a terminating NULL char */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* if returned, dns ttl is stored in the extended data area */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (-1);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (-1);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl ttl = *(nssuint_t *)((void *)((char *)pbuf + phdr->ext_off));
cb5caa98562cf06753163f558cbcfe30b8f4673adjlcheck_config(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* see if the cached config needs update */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if caller requests lookup using his
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * own nsswitch config, bypass cache
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* no need of cache if we are dealing with 0 ttls */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Invalidate cache if database file has been modified.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * See check_files config param for details.
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
18bdb8a7484e018149ac9a2766c97bdea9752c87michen (me, "%s: file %s has been modified - invalidating cache\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* extract dbop, dbname, key and cred */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl status = nss_packed_getkey(largs->buffer, largs->bufsize, &dbname,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* get the cache context */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (get_cache_ctx(dbname, &largs->ctx) != NSCD_SUCCESS) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Invalidate cache if file has been modified.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Lookup the cache table */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (;;) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl rc = lookup_cache(largs, &cfg, &args, whoami, &this_entry);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Either no entry and avoid name service */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* OR memory error */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* get the stats from the entry */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * What should we do next ?
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* otherwise reuse the entry */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* do we have clearance ? */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* nope. quit */
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: no clearance to wait\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* yes can wait */
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: no clearance for lookup\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* block any threads accessing this entry */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* release lock and do name service lookup */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* signal waiting threads */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * data found in name service
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * update cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: failed to update cache\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * store unpacked key in cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: failed to extract key\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update +ve miss count */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update +ve ttl */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* honor the dns ttl less than postive ttl */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * start the revalidation and reaper threads
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if not already started
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: cache updated with positive entry\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * data not found in name service
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * update cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: ERANGE, cache not updated "
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "with negative entry\n");
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: failed to update cache\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* store unpacked key in cache */
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: failed to extract key\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update -ve ttl */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update -ve miss count */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * start the revalidation and reaper threads
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if not already started
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: cache updated with negative entry\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * name service lookup failed
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "(status=%d, errno=%d)\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * found entry in cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik NSC_LOOKUP_LOG(DEBUG, "%s: no need to update\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (NSCD_GET_STATUS((nss_pheader_t *)this_entry->buffer) ==
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* positive hit */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update response buffer */
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: response buffer insufficient\n");
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: positive entry in cache\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* negative hit */
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "%s: negative entry in cache\n");
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik NSC_LOOKUP_LOG(ERROR, "%s: cache backend failure\n");
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * NSCD cache backend lookup function
cb5caa98562cf06753163f558cbcfe30b8f4673adjl/*ARGSUSED*/
cb5caa98562cf06753163f558cbcfe30b8f4673adjl switch (rc) {
606f6aa3d37f0f8e8282e483c1400bae5275aeebmichen * status and errno should have been set in the phdr,
606f6aa3d37f0f8e8282e483c1400bae5275aeebmichen * if not, set status to NSS_ERROR
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* init locks and semaphores */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) mutex_init(&ctx->file_mutex, USYNC_THREAD, NULL);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) mutex_init(&ctx->stats_mutex, USYNC_THREAD, NULL);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl (void) _nscd_init_cache_sema(&ctx->throttle_sema, cache_name[i]);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (;;) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (count != 0) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjlgetxy_keepalive(nsc_ctx_t *ctx, nsc_db_t *nscdb, int keep, int interval)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* we won't be here if keep == 0 so need to check that */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* leave pending calls alone */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* do_revalidate */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * for positive cache, in addition to the packed
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * header size, allocate twice the size of the
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * existing result (in case the result grows
ad0e80f7538b612141768bfda60009eb76550ee7michen * larger) plus 2K (for the file/compat backend to
ad0e80f7538b612141768bfda60009eb76550ee7michen * process a possible large entry in the /etc files)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * for negative cache, allocate 8K buffer to
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * hold result in case the next lookup may
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * return something (in addition to the
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * packed header size)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* launch update thread for each keep hot entry */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = keep; i > 0; i--) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl continue; /* unused slot in table */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * The update thread will handle freeing of buffer and largs.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Free the table here.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl errnum = thr_create(NULL, NULL, (void *(*)(void*))do_update,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (errnum != 0) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (-1);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl return (0);
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* update the length of the data buffer */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Invalidate cache
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Juriknsc_invalidate(nsc_ctx_t *ctx, char *dbname, nsc_ctx_t **ctxs)
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING)
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (i = 0; i < CACHE_CTX_COUNT; i++) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Invalidate cache by context
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* leave pending calls alone */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Free nsc_entry_t
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Pre-reqs:
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * nscdb->db_mutex lock must be held before calling this function
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjldelete_entry(nsc_db_t *nscdb, nsc_ctx_t *ctx, nsc_entry_t *entry) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjllookup_cache(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp,
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik nss_XbyY_args_t *argp, char *whoami, nsc_entry_t **entry)
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* set the search key */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl find_entry.key = argp->key; /* struct copy (not deep) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* lookup the hash table ==> O(1) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl *entry = hash_find(nscdb, &find_entry, &hash, nscd_true);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* if not found, lookup the AVL tree ==> O(log n) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl *entry = (nsc_entry_t *)avl_find(&nscdb->tree, &find_entry, &pos);
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* move it to the hash table */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* entry not found in the cache */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* allocate memory for new entry (stub) */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl *entry = (nsc_entry_t *)umem_cache_alloc(nsc_entry_cache,
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Note that the actual data for the key is stored within
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * the largs->buffer (input buffer to nsc_lookup).
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * find_entry.key only contains pointers to this data.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * If largs->buffer will be re-allocated by nss_psearch
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * then (*entry)->key will have dangling pointers.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * In such case, the following assignment needs to be
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * replaced by code that duplicates the key.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Add the entry to the cache.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Have we exceeded max entries ? */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl if (cfgp->maxentries > 0 && nentries > cfgp->maxentries) {
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "deleting least recently used entry\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * It's okay if we were not able to find one to delete.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * The reaper (when invoked) will return the cache to a
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * safe level.
cb5caa98562cf06753163f558cbcfe30b8f4673adjlstatic void
cb5caa98562cf06753163f558cbcfe30b8f4673adjl for (;;) {
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* sleep for atleast 60 seconds */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * minimum nodes_per_interval = 256 or 1<<8
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * maximum nodes_per_interval = nsc_entries
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * minimum seconds_per_interval = 32 or 1<<5
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * maximum_seconds_per_interval = ttl
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "seconds per interval = %d, "
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik "nodes per interval = %d\n",
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* delete ST_DISCARD and expired nodes */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Delete entry if its discard flag is
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * set OR if it has expired. Entries
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * with pending updates are not
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * deleted.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * nscdb->reap_node will be adjusted
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * by delete_entry()
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Dynamic adjustment of hash table size.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Hash table size is roughly 1/8th of the
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * total entries. However the size is changed
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * only when the number of entries double or
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * reduced by half
7d7551bcfe5ded1738ddbe3268520996a32023b4Milan Jurik slot < _NSC_HTSIZE_NUM_SLOTS && nentries > value;
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Recommended size is same as the current size. Done */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Dump old hashes because it would be time
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * consuming to rehash them.
cb5caa98562cf06753163f558cbcfe30b8f4673adjl nscdb->htable = calloc(newhtsize, sizeof (*(nscdb->htable)));
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* -1 to try later */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * if cache is almost full then reduce it to a safe level by
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * evicting LRU entries
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* No limit on number of entries. Done */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* what is the percentage of cache used ? */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * cache needs to be reduced to a safe level
cb5caa98562cf06753163f558cbcfe30b8f4673adjl * Reduce each subcache by 'value' percent
cb5caa98562cf06753163f558cbcfe30b8f4673adjl nodes_togo = (value * avl_numnodes(&nscdb->tree)) / 100;
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Start from LRU entry i.e queue head */
cb5caa98562cf06753163f558cbcfe30b8f4673adjl /* Leave nodes with pending updates alone */