1cb5caa98Sdjl /* 2cb5caa98Sdjl * CDDL HEADER START 3cb5caa98Sdjl * 4cb5caa98Sdjl * The contents of this file are subject to the terms of the 5cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6cb5caa98Sdjl * You may not use this file except in compliance with the License. 7cb5caa98Sdjl * 8cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10cb5caa98Sdjl * See the License for the specific language governing permissions 11cb5caa98Sdjl * and limitations under the License. 12cb5caa98Sdjl * 13cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18cb5caa98Sdjl * 19cb5caa98Sdjl * CDDL HEADER END 20cb5caa98Sdjl */ 21cb5caa98Sdjl /* 22cb5caa98Sdjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23cb5caa98Sdjl * Use is subject to license terms. 24cb5caa98Sdjl */ 25cb5caa98Sdjl 26cb5caa98Sdjl #pragma ident "%Z%%M% %I% %E% SMI" 27cb5caa98Sdjl 28cb5caa98Sdjl /* 29cb5caa98Sdjl * Cache routines for nscd 30cb5caa98Sdjl */ 31cb5caa98Sdjl #include <assert.h> 32cb5caa98Sdjl #include <errno.h> 33cb5caa98Sdjl #include <memory.h> 34cb5caa98Sdjl #include <signal.h> 35cb5caa98Sdjl #include <stdlib.h> 36cb5caa98Sdjl #include <stddef.h> 37cb5caa98Sdjl #include <stdio.h> 38cb5caa98Sdjl #include <string.h> 39cb5caa98Sdjl #include <sys/stat.h> 40cb5caa98Sdjl #include <sys/time.h> 41cb5caa98Sdjl #include <sys/types.h> 42cb5caa98Sdjl #include <sys/wait.h> 43cb5caa98Sdjl #include <unistd.h> 44cb5caa98Sdjl #include <ucred.h> 45cb5caa98Sdjl #include <nss_common.h> 46cb5caa98Sdjl #include <locale.h> 47cb5caa98Sdjl #include <ctype.h> 48cb5caa98Sdjl #include <strings.h> 49cb5caa98Sdjl #include <string.h> 50cb5caa98Sdjl #include <umem.h> 51cb5caa98Sdjl #include <fcntl.h> 52cb5caa98Sdjl #include "cache.h" 53cb5caa98Sdjl #include "nscd_door.h" 54cb5caa98Sdjl #include "nscd_log.h" 55cb5caa98Sdjl #include "nscd_config.h" 56cb5caa98Sdjl #include "nscd_frontend.h" 57cb5caa98Sdjl #include "nscd_switch.h" 58cb5caa98Sdjl 59cb5caa98Sdjl #define SUCCESS 0 60cb5caa98Sdjl #define NOTFOUND -1 61cb5caa98Sdjl #define SERVERERROR -2 62cb5caa98Sdjl #define NOSERVER -3 63cb5caa98Sdjl #define CONTINUE -4 64cb5caa98Sdjl 65cb5caa98Sdjl static nsc_db_t *nsc_get_db(nsc_ctx_t *, int); 66cb5caa98Sdjl static nscd_rc_t lookup_cache(nsc_lookup_args_t *, nscd_cfg_cache_t *, 67cb5caa98Sdjl nss_XbyY_args_t *, char *, nsc_entry_t **); 68cb5caa98Sdjl static uint_t reap_cache(nsc_ctx_t *, uint_t, uint_t); 69cb5caa98Sdjl static void delete_entry(nsc_db_t *, nsc_ctx_t *, nsc_entry_t *); 70cb5caa98Sdjl static void print_stats(nscd_cfg_stat_cache_t *); 71cb5caa98Sdjl static void print_cfg(nscd_cfg_cache_t *); 72cb5caa98Sdjl static int lookup_int(nsc_lookup_args_t *, int); 73cb5caa98Sdjl 74cb5caa98Sdjl #ifdef NSCD_DEBUG 75cb5caa98Sdjl static void print_entry(nsc_db_t *, time_t, nsc_entry_t *); 76cb5caa98Sdjl static void avl_dump(nsc_db_t *, time_t); 77cb5caa98Sdjl static void hash_dump(nsc_db_t *, time_t); 78cb5caa98Sdjl #endif /* NSCD_DEBUG */ 79cb5caa98Sdjl static nsc_entry_t *hash_find(nsc_db_t *, nsc_entry_t *, uint_t *, nscd_bool_t); 80cb5caa98Sdjl 81cb5caa98Sdjl static void queue_adjust(nsc_db_t *, nsc_entry_t *); 82cb5caa98Sdjl static void queue_remove(nsc_db_t *, nsc_entry_t *); 83cb5caa98Sdjl #ifdef NSCD_DEBUG 84cb5caa98Sdjl static void queue_dump(nsc_db_t *, time_t); 85cb5caa98Sdjl #endif /* NSCD_DEBUG */ 86cb5caa98Sdjl 87cb5caa98Sdjl static int launch_update(nsc_lookup_args_t *); 88cb5caa98Sdjl static void do_update(nsc_lookup_args_t *); 89cb5caa98Sdjl static void getxy_keepalive(nsc_ctx_t *, nsc_db_t *, int, int); 90cb5caa98Sdjl 91cb5caa98Sdjl static void ctx_info(nsc_ctx_t *); 92cb5caa98Sdjl static void ctx_info_nolock(nsc_ctx_t *); 93cb5caa98Sdjl static void ctx_invalidate(nsc_ctx_t *); 94cb5caa98Sdjl 95cb5caa98Sdjl static void nsc_db_str_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); 96cb5caa98Sdjl static void nsc_db_int_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); 97cb5caa98Sdjl static void nsc_db_any_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); 98cb5caa98Sdjl 99cb5caa98Sdjl static int nsc_db_cis_key_compar(const void *, const void *); 100cb5caa98Sdjl static int nsc_db_ces_key_compar(const void *, const void *); 101cb5caa98Sdjl static int nsc_db_int_key_compar(const void *, const void *); 102cb5caa98Sdjl 103cb5caa98Sdjl static uint_t nsc_db_cis_key_gethash(nss_XbyY_key_t *, int); 104cb5caa98Sdjl static uint_t nsc_db_ces_key_gethash(nss_XbyY_key_t *, int); 105cb5caa98Sdjl static uint_t nsc_db_int_key_gethash(nss_XbyY_key_t *, int); 106cb5caa98Sdjl 107cb5caa98Sdjl static umem_cache_t *nsc_entry_cache; 108cb5caa98Sdjl 109cb5caa98Sdjl static nsc_ctx_t *init_cache_ctx(int); 110cb5caa98Sdjl static void reaper(nsc_ctx_t *); 111cb5caa98Sdjl static void revalidate(nsc_ctx_t *); 112cb5caa98Sdjl 113cb5caa98Sdjl static nss_status_t 114cb5caa98Sdjl dup_packed_buffer(void *src, void *dst) { 115cb5caa98Sdjl nsc_lookup_args_t *s = (nsc_lookup_args_t *)src; 116cb5caa98Sdjl nsc_entry_t *d = (nsc_entry_t *)dst; 117cb5caa98Sdjl nss_pheader_t *sphdr = (nss_pheader_t *)s->buffer; 118cb5caa98Sdjl nss_pheader_t *dphdr = (nss_pheader_t *)d->buffer; 119cb5caa98Sdjl int slen, new_pbufsiz = 0; 120cb5caa98Sdjl 121cb5caa98Sdjl if (NSCD_GET_STATUS(sphdr) != NSS_SUCCESS) { 122cb5caa98Sdjl 123cb5caa98Sdjl /* no result, copy header only (status, errno, etc) */ 124cb5caa98Sdjl slen = sphdr->data_off; 125cb5caa98Sdjl } else { 126cb5caa98Sdjl /* 127cb5caa98Sdjl * lookup result returned, data to copy is the packed 128cb5caa98Sdjl * header plus result (add 1 for the terminating NULL 129cb5caa98Sdjl * just in case) 130cb5caa98Sdjl */ 131cb5caa98Sdjl slen = sphdr->data_off + sphdr->data_len + 1; 132cb5caa98Sdjl } 133cb5caa98Sdjl 134cb5caa98Sdjl /* allocate cache packed buffer */ 135cb5caa98Sdjl if (dphdr != NULL && d->bufsize <= slen && d->bufsize != 0) { 136cb5caa98Sdjl /* old buffer too small, free it */ 137cb5caa98Sdjl free(dphdr); 138cb5caa98Sdjl d->buffer = NULL; 139cb5caa98Sdjl d->bufsize = 0; 140cb5caa98Sdjl dphdr = NULL; 141cb5caa98Sdjl } 142cb5caa98Sdjl if (dphdr == NULL) { 143cb5caa98Sdjl /* get new buffer */ 144cb5caa98Sdjl dphdr = calloc(1, slen + 1); 145cb5caa98Sdjl if (dphdr == NULL) 146cb5caa98Sdjl return (NSS_ERROR); 147cb5caa98Sdjl d->buffer = dphdr; 148cb5caa98Sdjl d->bufsize = slen + 1; 149cb5caa98Sdjl new_pbufsiz = slen + 1; 150cb5caa98Sdjl } 151cb5caa98Sdjl 152cb5caa98Sdjl (void) memcpy(dphdr, sphdr, slen); 153cb5caa98Sdjl if (new_pbufsiz != 0) 154cb5caa98Sdjl dphdr->pbufsiz = new_pbufsiz; 155cb5caa98Sdjl 156cb5caa98Sdjl return (NSS_SUCCESS); 157cb5caa98Sdjl } 158cb5caa98Sdjl 159cb5caa98Sdjl char *cache_name[CACHE_CTX_COUNT] = { 160cb5caa98Sdjl NSS_DBNAM_PASSWD, 161cb5caa98Sdjl NSS_DBNAM_GROUP, 162cb5caa98Sdjl NSS_DBNAM_HOSTS, 163cb5caa98Sdjl NSS_DBNAM_IPNODES, 164cb5caa98Sdjl NSS_DBNAM_EXECATTR, 165cb5caa98Sdjl NSS_DBNAM_PROFATTR, 166cb5caa98Sdjl NSS_DBNAM_USERATTR, 167cb5caa98Sdjl NSS_DBNAM_ETHERS, 168cb5caa98Sdjl NSS_DBNAM_RPC, 169cb5caa98Sdjl NSS_DBNAM_PROTOCOLS, 170cb5caa98Sdjl NSS_DBNAM_NETWORKS, 171cb5caa98Sdjl NSS_DBNAM_BOOTPARAMS, 172cb5caa98Sdjl NSS_DBNAM_AUDITUSER, 173cb5caa98Sdjl NSS_DBNAM_AUTHATTR, 174cb5caa98Sdjl NSS_DBNAM_SERVICES, 175cb5caa98Sdjl NSS_DBNAM_NETMASKS, 176cb5caa98Sdjl NSS_DBNAM_PRINTERS, 177cb5caa98Sdjl NSS_DBNAM_PROJECT, 178cb5caa98Sdjl NSS_DBNAM_TSOL_TP, 179cb5caa98Sdjl NSS_DBNAM_TSOL_RH 180cb5caa98Sdjl }; 181cb5caa98Sdjl 182cb5caa98Sdjl typedef void (*cache_init_ctx_t)(nsc_ctx_t *); 183cb5caa98Sdjl static cache_init_ctx_t cache_init_ctx[CACHE_CTX_COUNT] = { 184cb5caa98Sdjl passwd_init_ctx, 185cb5caa98Sdjl group_init_ctx, 186cb5caa98Sdjl host_init_ctx, 187cb5caa98Sdjl ipnode_init_ctx, 188cb5caa98Sdjl exec_init_ctx, 189cb5caa98Sdjl prof_init_ctx, 190cb5caa98Sdjl user_init_ctx, 191cb5caa98Sdjl ether_init_ctx, 192cb5caa98Sdjl rpc_init_ctx, 193cb5caa98Sdjl proto_init_ctx, 194cb5caa98Sdjl net_init_ctx, 195cb5caa98Sdjl bootp_init_ctx, 196cb5caa98Sdjl auuser_init_ctx, 197cb5caa98Sdjl auth_init_ctx, 198cb5caa98Sdjl serv_init_ctx, 199cb5caa98Sdjl netmask_init_ctx, 200cb5caa98Sdjl printer_init_ctx, 201cb5caa98Sdjl project_init_ctx, 202cb5caa98Sdjl tnrhtp_init_ctx, 203cb5caa98Sdjl tnrhdb_init_ctx 204cb5caa98Sdjl }; 205cb5caa98Sdjl 206cb5caa98Sdjl nsc_ctx_t *cache_ctx_p[CACHE_CTX_COUNT] = { 0 }; 207cb5caa98Sdjl static nscd_cfg_stat_cache_t null_stats = { 0 }; 208cb5caa98Sdjl static nscd_cfg_global_cache_t global_cfg; 209cb5caa98Sdjl 210cb5caa98Sdjl /* 211cb5caa98Sdjl * Given database name 'dbname' find cache index 212cb5caa98Sdjl */ 213cb5caa98Sdjl int 214cb5caa98Sdjl get_cache_idx(char *dbname) { 215cb5caa98Sdjl int i; 216cb5caa98Sdjl char *nsc_name; 217cb5caa98Sdjl 218cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 219cb5caa98Sdjl nsc_name = cache_name[i]; 220cb5caa98Sdjl if (strcmp(nsc_name, dbname) == 0) 221cb5caa98Sdjl return (i); 222cb5caa98Sdjl } 223cb5caa98Sdjl return (-1); 224cb5caa98Sdjl } 225cb5caa98Sdjl 226cb5caa98Sdjl /* 227cb5caa98Sdjl * Given database name 'dbname' retrieve cache context, 228cb5caa98Sdjl * if not created yet, allocate and initialize it. 229cb5caa98Sdjl */ 230cb5caa98Sdjl static nscd_rc_t 231cb5caa98Sdjl get_cache_ctx(char *dbname, nsc_ctx_t **ctx) { 232cb5caa98Sdjl int i; 233cb5caa98Sdjl 234cb5caa98Sdjl *ctx = NULL; 235cb5caa98Sdjl 236cb5caa98Sdjl i = get_cache_idx(dbname); 237cb5caa98Sdjl if (i == -1) 238cb5caa98Sdjl return (NSCD_INVALID_ARGUMENT); 239cb5caa98Sdjl if ((*ctx = cache_ctx_p[i]) == NULL) { 240cb5caa98Sdjl *ctx = init_cache_ctx(i); 241cb5caa98Sdjl if (*ctx == NULL) 242cb5caa98Sdjl return (NSCD_NO_MEMORY); 243cb5caa98Sdjl } 244cb5caa98Sdjl 245cb5caa98Sdjl return (NSCD_SUCCESS); 246cb5caa98Sdjl } 247cb5caa98Sdjl 248cb5caa98Sdjl /* 249cb5caa98Sdjl * Generate a log string to identify backend operation in debug logs 250cb5caa98Sdjl */ 251cb5caa98Sdjl static void 252cb5caa98Sdjl nsc_db_str_key_getlogstr(char *name, char *whoami, size_t len, 253cb5caa98Sdjl nss_XbyY_args_t *argp) { 254cb5caa98Sdjl (void) snprintf(whoami, len, "%s [key=%s]", name, argp->key.name); 255cb5caa98Sdjl } 256cb5caa98Sdjl 257cb5caa98Sdjl 258cb5caa98Sdjl static void 259cb5caa98Sdjl nsc_db_int_key_getlogstr(char *name, char *whoami, size_t len, 260cb5caa98Sdjl nss_XbyY_args_t *argp) { 261cb5caa98Sdjl (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.number); 262cb5caa98Sdjl } 263cb5caa98Sdjl 264cb5caa98Sdjl /*ARGSUSED*/ 265cb5caa98Sdjl static void 266cb5caa98Sdjl nsc_db_any_key_getlogstr(char *name, char *whoami, size_t len, 267cb5caa98Sdjl nss_XbyY_args_t *argp) { 268cb5caa98Sdjl (void) snprintf(whoami, len, "%s", name); 269cb5caa98Sdjl } 270cb5caa98Sdjl 271cb5caa98Sdjl 272cb5caa98Sdjl /* 273cb5caa98Sdjl * Returns cache based on dbop 274cb5caa98Sdjl */ 275cb5caa98Sdjl static nsc_db_t * 276cb5caa98Sdjl nsc_get_db(nsc_ctx_t *ctx, int dbop) { 277cb5caa98Sdjl int i; 278cb5caa98Sdjl 279cb5caa98Sdjl for (i = 0; i < ctx->db_count; i++) { 280cb5caa98Sdjl if (ctx->nsc_db[i] && dbop == ctx->nsc_db[i]->dbop) 281cb5caa98Sdjl return (ctx->nsc_db[i]); 282cb5caa98Sdjl } 283cb5caa98Sdjl return (NULL); 284cb5caa98Sdjl } 285cb5caa98Sdjl 286cb5caa98Sdjl 287cb5caa98Sdjl /* 288cb5caa98Sdjl * integer compare routine for _NSC_DB_INT_KEY 289cb5caa98Sdjl */ 290cb5caa98Sdjl static int 291cb5caa98Sdjl nsc_db_int_key_compar(const void *n1, const void *n2) { 292cb5caa98Sdjl nsc_entry_t *e1, *e2; 293cb5caa98Sdjl 294cb5caa98Sdjl e1 = (nsc_entry_t *)n1; 295cb5caa98Sdjl e2 = (nsc_entry_t *)n2; 296cb5caa98Sdjl return (_NSC_INT_KEY_CMP(e1->key.number, e2->key.number)); 297cb5caa98Sdjl } 298cb5caa98Sdjl 299cb5caa98Sdjl 300cb5caa98Sdjl /* 301cb5caa98Sdjl * case sensitive name compare routine for _NSC_DB_CES_KEY 302cb5caa98Sdjl */ 303cb5caa98Sdjl static int 304cb5caa98Sdjl nsc_db_ces_key_compar(const void *n1, const void *n2) { 305cb5caa98Sdjl nsc_entry_t *e1, *e2; 306cb5caa98Sdjl int res, l1, l2; 307cb5caa98Sdjl 308cb5caa98Sdjl e1 = (nsc_entry_t *)n1; 309cb5caa98Sdjl e2 = (nsc_entry_t *)n2; 310cb5caa98Sdjl l1 = strlen(e1->key.name); 311cb5caa98Sdjl l2 = strlen(e2->key.name); 312cb5caa98Sdjl res = strncmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2); 313cb5caa98Sdjl return (_NSC_INT_KEY_CMP(res, 0)); 314cb5caa98Sdjl } 315cb5caa98Sdjl 316cb5caa98Sdjl 317cb5caa98Sdjl /* 318cb5caa98Sdjl * case insensitive name compare routine _NSC_DB_CIS_KEY 319cb5caa98Sdjl */ 320cb5caa98Sdjl static int 321cb5caa98Sdjl nsc_db_cis_key_compar(const void *n1, const void *n2) { 322cb5caa98Sdjl nsc_entry_t *e1, *e2; 323cb5caa98Sdjl int res, l1, l2; 324cb5caa98Sdjl 325cb5caa98Sdjl e1 = (nsc_entry_t *)n1; 326cb5caa98Sdjl e2 = (nsc_entry_t *)n2; 327cb5caa98Sdjl l1 = strlen(e1->key.name); 328cb5caa98Sdjl l2 = strlen(e2->key.name); 329cb5caa98Sdjl res = strncasecmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2); 330cb5caa98Sdjl return (_NSC_INT_KEY_CMP(res, 0)); 331cb5caa98Sdjl } 332cb5caa98Sdjl 333cb5caa98Sdjl /* 334cb5caa98Sdjl * macro used to generate elf hashes for strings 335cb5caa98Sdjl */ 336cb5caa98Sdjl #define _NSC_ELF_STR_GETHASH(func, str, htsize, hval) \ 337cb5caa98Sdjl hval = 0; \ 338cb5caa98Sdjl while (*str) { \ 339cb5caa98Sdjl uint_t g; \ 340cb5caa98Sdjl hval = (hval << 4) + func(*str++); \ 341cb5caa98Sdjl if ((g = (hval & 0xf0000000)) != 0) \ 342cb5caa98Sdjl hval ^= g >> 24; \ 343cb5caa98Sdjl hval &= ~g; \ 344cb5caa98Sdjl } \ 345cb5caa98Sdjl hval %= htsize; 346cb5caa98Sdjl 347cb5caa98Sdjl 348cb5caa98Sdjl /* 349cb5caa98Sdjl * cis hash function 350cb5caa98Sdjl */ 351cb5caa98Sdjl uint_t 352cb5caa98Sdjl cis_gethash(const char *key, int htsize) { 353cb5caa98Sdjl uint_t hval; 354cb5caa98Sdjl if (key == NULL) 355cb5caa98Sdjl return (0); 356cb5caa98Sdjl _NSC_ELF_STR_GETHASH(tolower, key, htsize, hval); 357cb5caa98Sdjl return (hval); 358cb5caa98Sdjl } 359cb5caa98Sdjl 360cb5caa98Sdjl 361cb5caa98Sdjl /* 362cb5caa98Sdjl * ces hash function 363cb5caa98Sdjl */ 364cb5caa98Sdjl uint_t 365cb5caa98Sdjl ces_gethash(const char *key, int htsize) { 366cb5caa98Sdjl uint_t hval; 367cb5caa98Sdjl if (key == NULL) 368cb5caa98Sdjl return (0); 369cb5caa98Sdjl _NSC_ELF_STR_GETHASH(, key, htsize, hval); 370cb5caa98Sdjl return (hval); 371cb5caa98Sdjl } 372cb5caa98Sdjl 373cb5caa98Sdjl 374cb5caa98Sdjl /* 375cb5caa98Sdjl * one-at-a-time hash function 376cb5caa98Sdjl */ 377cb5caa98Sdjl uint_t 378cb5caa98Sdjl db_gethash(const void *key, int len, int htsize) { 379cb5caa98Sdjl uint_t hval, i; 380cb5caa98Sdjl const char *str = key; 381cb5caa98Sdjl 382cb5caa98Sdjl if (str == NULL) 383cb5caa98Sdjl return (0); 384cb5caa98Sdjl 385cb5caa98Sdjl for (hval = 0, i = 0; i < len; i++) { 386cb5caa98Sdjl hval += str[i]; 387cb5caa98Sdjl hval += (hval << 10); 388cb5caa98Sdjl hval ^= (hval >> 6); 389cb5caa98Sdjl } 390cb5caa98Sdjl hval += (hval << 3); 391cb5caa98Sdjl hval ^= (hval >> 11); 392cb5caa98Sdjl hval += (hval << 15); 393cb5caa98Sdjl return (hval % htsize); 394cb5caa98Sdjl } 395cb5caa98Sdjl 396cb5caa98Sdjl 397cb5caa98Sdjl /* 398cb5caa98Sdjl * case insensitive name gethash routine _NSC_DB_CIS_KEY 399cb5caa98Sdjl */ 400cb5caa98Sdjl static uint_t 401cb5caa98Sdjl nsc_db_cis_key_gethash(nss_XbyY_key_t *key, int htsize) { 402cb5caa98Sdjl return (cis_gethash(key->name, htsize)); 403cb5caa98Sdjl } 404cb5caa98Sdjl 405cb5caa98Sdjl 406cb5caa98Sdjl /* 407cb5caa98Sdjl * case sensitive name gethash routine _NSC_DB_CES_KEY 408cb5caa98Sdjl */ 409cb5caa98Sdjl static uint_t 410cb5caa98Sdjl nsc_db_ces_key_gethash(nss_XbyY_key_t *key, int htsize) { 411cb5caa98Sdjl return (ces_gethash(key->name, htsize)); 412cb5caa98Sdjl } 413cb5caa98Sdjl 414cb5caa98Sdjl 415cb5caa98Sdjl /* 416cb5caa98Sdjl * integer gethash routine _NSC_DB_INT_KEY 417cb5caa98Sdjl */ 418cb5caa98Sdjl static uint_t 419cb5caa98Sdjl nsc_db_int_key_gethash(nss_XbyY_key_t *key, int htsize) { 420cb5caa98Sdjl return (db_gethash(&key->number, sizeof (key->number), htsize)); 421cb5caa98Sdjl } 422cb5caa98Sdjl 423cb5caa98Sdjl 424cb5caa98Sdjl /* 425cb5caa98Sdjl * Find entry in the hash table 426cb5caa98Sdjl * if cmp == nscd_true) 427cb5caa98Sdjl * return entry only if the keys match 428cb5caa98Sdjl * else 429cb5caa98Sdjl * return entry in the hash location without checking the keys 430cb5caa98Sdjl * 431cb5caa98Sdjl */ 432cb5caa98Sdjl static nsc_entry_t * 433cb5caa98Sdjl hash_find(nsc_db_t *nscdb, nsc_entry_t *entry, uint_t *hash, 434cb5caa98Sdjl nscd_bool_t cmp) { 435cb5caa98Sdjl 436cb5caa98Sdjl nsc_entry_t *hashentry; 437cb5caa98Sdjl 438cb5caa98Sdjl if (nscdb->gethash) 439cb5caa98Sdjl *hash = nscdb->gethash(&entry->key, nscdb->htsize); 440cb5caa98Sdjl else 441cb5caa98Sdjl return (NULL); 442cb5caa98Sdjl 443cb5caa98Sdjl hashentry = nscdb->htable[*hash]; 444cb5caa98Sdjl if (cmp == nscd_false || hashentry == NULL) 445cb5caa98Sdjl return (hashentry); 446cb5caa98Sdjl if (nscdb->compar) { 447cb5caa98Sdjl if (nscdb->compar(entry, hashentry) == 0) 448cb5caa98Sdjl return (hashentry); 449cb5caa98Sdjl } 450cb5caa98Sdjl return (NULL); 451cb5caa98Sdjl } 452cb5caa98Sdjl 453cb5caa98Sdjl 454cb5caa98Sdjl #define HASH_REMOVE(nscdb, entry, hash, cmp) \ 455cb5caa98Sdjl if (nscdb->htable) { \ 456cb5caa98Sdjl if (entry == hash_find(nscdb, entry, &hash, cmp)) \ 457cb5caa98Sdjl nscdb->htable[hash] = NULL; \ 458cb5caa98Sdjl } 459cb5caa98Sdjl 460cb5caa98Sdjl 461cb5caa98Sdjl #define HASH_INSERT(nscdb, entry, hash, cmp) \ 462cb5caa98Sdjl if (nscdb->htable) { \ 463cb5caa98Sdjl (void) hash_find(nscdb, entry, &hash, cmp); \ 464cb5caa98Sdjl nscdb->htable[hash] = entry; \ 465cb5caa98Sdjl } 466cb5caa98Sdjl 467cb5caa98Sdjl 468cb5caa98Sdjl #ifdef NSCD_DEBUG 469cb5caa98Sdjl static void 470cb5caa98Sdjl print_entry(nsc_db_t *nscdb, time_t now, nsc_entry_t *entry) { 471cb5caa98Sdjl nss_XbyY_args_t args; 472cb5caa98Sdjl char whoami[512]; 473cb5caa98Sdjl 474cb5caa98Sdjl switch (entry->stats.status) { 475cb5caa98Sdjl case ST_NEW_ENTRY: 476cb5caa98Sdjl (void) fprintf(stdout, gettext("\t status: new entry\n")); 477cb5caa98Sdjl return; 478cb5caa98Sdjl case ST_UPDATE_PENDING: 479cb5caa98Sdjl (void) fprintf(stdout, gettext("\t status: update pending\n")); 480cb5caa98Sdjl return; 481cb5caa98Sdjl case ST_LOOKUP_PENDING: 482cb5caa98Sdjl (void) fprintf(stdout, gettext("\t status: lookup pending\n")); 483cb5caa98Sdjl return; 484cb5caa98Sdjl case ST_DISCARD: 485cb5caa98Sdjl (void) fprintf(stdout, gettext("\t status: discarded entry\n")); 486cb5caa98Sdjl return; 487cb5caa98Sdjl default: 488cb5caa98Sdjl if (entry->stats.timestamp < now) 489cb5caa98Sdjl (void) fprintf(stdout, 490cb5caa98Sdjl gettext("\t status: expired (%d seconds ago)\n"), 491cb5caa98Sdjl now - entry->stats.timestamp); 492cb5caa98Sdjl else 493cb5caa98Sdjl (void) fprintf(stdout, 494cb5caa98Sdjl gettext("\t status: valid (expiry in %d seconds)\n"), 495cb5caa98Sdjl entry->stats.timestamp - now); 496cb5caa98Sdjl break; 497cb5caa98Sdjl } 498cb5caa98Sdjl (void) fprintf(stdout, gettext("\t hits: %u\n"), entry->stats.hits); 499cb5caa98Sdjl args.key = entry->key; 500cb5caa98Sdjl (void) nscdb->getlogstr(nscdb->name, whoami, sizeof (whoami), &args); 501cb5caa98Sdjl (void) fprintf(stdout, "\t %s\n", whoami); 502cb5caa98Sdjl } 503cb5caa98Sdjl #endif /* NSCD_DEBUG */ 504cb5caa98Sdjl 505cb5caa98Sdjl static void 506cb5caa98Sdjl print_stats(nscd_cfg_stat_cache_t *statsp) { 507cb5caa98Sdjl 508cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\t STATISTICS:\n")); 509cb5caa98Sdjl (void) fprintf(stdout, gettext("\t positive hits: %lu\n"), 510cb5caa98Sdjl statsp->pos_hits); 511cb5caa98Sdjl (void) fprintf(stdout, gettext("\t negative hits: %lu\n"), 512cb5caa98Sdjl statsp->neg_hits); 513cb5caa98Sdjl (void) fprintf(stdout, gettext("\t positive misses: %lu\n"), 514cb5caa98Sdjl statsp->pos_misses); 515cb5caa98Sdjl (void) fprintf(stdout, gettext("\t negative misses: %lu\n"), 516cb5caa98Sdjl statsp->neg_misses); 517cb5caa98Sdjl (void) fprintf(stdout, gettext("\t total entries: %lu\n"), 518cb5caa98Sdjl statsp->entries); 519cb5caa98Sdjl (void) fprintf(stdout, gettext("\t queries queued: %lu\n"), 520cb5caa98Sdjl statsp->wait_count); 521cb5caa98Sdjl (void) fprintf(stdout, gettext("\t queries dropped: %lu\n"), 522cb5caa98Sdjl statsp->drop_count); 523cb5caa98Sdjl (void) fprintf(stdout, gettext("\t cache invalidations: %lu\n"), 524cb5caa98Sdjl statsp->invalidate_count); 525cb5caa98Sdjl 526cb5caa98Sdjl _NSC_GET_HITRATE(statsp); 527cb5caa98Sdjl (void) fprintf(stdout, gettext("\t cache hit rate: %10.1f\n"), 528cb5caa98Sdjl statsp->hitrate); 529cb5caa98Sdjl } 530cb5caa98Sdjl 531cb5caa98Sdjl 532cb5caa98Sdjl static void 533cb5caa98Sdjl print_cfg(nscd_cfg_cache_t *cfgp) { 534cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\t CONFIG:\n")); 535cb5caa98Sdjl (void) fprintf(stdout, gettext("\t enabled: %s\n"), 536cb5caa98Sdjl yes_no(cfgp->enable)); 537cb5caa98Sdjl (void) fprintf(stdout, gettext("\t per user cache: %s\n"), 538cb5caa98Sdjl yes_no(cfgp->per_user)); 539cb5caa98Sdjl (void) fprintf(stdout, gettext("\t avoid name service: %s\n"), 540cb5caa98Sdjl yes_no(cfgp->avoid_ns)); 541cb5caa98Sdjl (void) fprintf(stdout, gettext("\t check file: %s\n"), 542cb5caa98Sdjl yes_no(cfgp->check_files)); 543cb5caa98Sdjl (void) fprintf(stdout, gettext("\t check file interval: %d\n"), 544cb5caa98Sdjl cfgp->check_interval); 545cb5caa98Sdjl (void) fprintf(stdout, gettext("\t positive ttl: %d\n"), 546cb5caa98Sdjl cfgp->pos_ttl); 547cb5caa98Sdjl (void) fprintf(stdout, gettext("\t negative ttl: %d\n"), 548cb5caa98Sdjl cfgp->neg_ttl); 549cb5caa98Sdjl (void) fprintf(stdout, gettext("\t keep hot count: %d\n"), 550cb5caa98Sdjl cfgp->keephot); 551cb5caa98Sdjl (void) fprintf(stdout, gettext("\t hint size: %d\n"), 552cb5caa98Sdjl cfgp->hint_size); 553cb5caa98Sdjl (void) fprintf(stdout, gettext("\t max entries: %lu%s"), 554cb5caa98Sdjl cfgp->maxentries, 555cb5caa98Sdjl cfgp->maxentries?"\n":" (unlimited)\n"); 556cb5caa98Sdjl } 557cb5caa98Sdjl 558cb5caa98Sdjl 559cb5caa98Sdjl #ifdef NSCD_DEBUG 560cb5caa98Sdjl static void 561cb5caa98Sdjl hash_dump(nsc_db_t *nscdb, time_t now) { 562cb5caa98Sdjl nsc_entry_t *entry; 563cb5caa98Sdjl int i; 564cb5caa98Sdjl 565cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\nHASH TABLE:\n")); 566cb5caa98Sdjl for (i = 0; i < nscdb->htsize; i++) { 567cb5caa98Sdjl if ((entry = nscdb->htable[i]) != NULL) { 568cb5caa98Sdjl (void) fprintf(stdout, "hash[%d]:\n", i); 569cb5caa98Sdjl print_entry(nscdb, now, entry); 570cb5caa98Sdjl } 571cb5caa98Sdjl } 572cb5caa98Sdjl } 573cb5caa98Sdjl #endif /* NSCD_DEBUG */ 574cb5caa98Sdjl 575cb5caa98Sdjl 576cb5caa98Sdjl #ifdef NSCD_DEBUG 577cb5caa98Sdjl static void 578cb5caa98Sdjl avl_dump(nsc_db_t *nscdb, time_t now) { 579cb5caa98Sdjl nsc_entry_t *entry; 580cb5caa98Sdjl int i; 581cb5caa98Sdjl 582cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\nAVL TREE:\n")); 583cb5caa98Sdjl for (entry = avl_first(&nscdb->tree), i = 0; entry != NULL; 584cb5caa98Sdjl entry = avl_walk(&nscdb->tree, entry, AVL_AFTER)) { 585cb5caa98Sdjl (void) fprintf(stdout, "avl node[%d]:\n", i++); 586cb5caa98Sdjl print_entry(nscdb, now, entry); 587cb5caa98Sdjl } 588cb5caa98Sdjl } 589cb5caa98Sdjl #endif /* NSCD_DEBUG */ 590cb5caa98Sdjl 591cb5caa98Sdjl 592cb5caa98Sdjl #ifdef NSCD_DEBUG 593cb5caa98Sdjl static void 594cb5caa98Sdjl queue_dump(nsc_db_t *nscdb, time_t now) { 595cb5caa98Sdjl nsc_entry_t *entry; 596cb5caa98Sdjl int i; 597cb5caa98Sdjl 598cb5caa98Sdjl (void) fprintf(stdout, 599cb5caa98Sdjl gettext("\n\nCACHE [name=%s, nodes=%lu]:\n"), 600cb5caa98Sdjl nscdb->name, avl_numnodes(&nscdb->tree)); 601cb5caa98Sdjl 602cb5caa98Sdjl (void) fprintf(stdout, 603cb5caa98Sdjl gettext("Starting with the most recently accessed:\n")); 604cb5caa98Sdjl 605cb5caa98Sdjl for (entry = nscdb->qtail, i = 0; entry; entry = entry->qnext) { 606cb5caa98Sdjl (void) fprintf(stdout, "entry[%d]:\n", i++); 607cb5caa98Sdjl print_entry(nscdb, now, entry); 608cb5caa98Sdjl } 609cb5caa98Sdjl } 610cb5caa98Sdjl #endif /* NSCD_DEBUG */ 611cb5caa98Sdjl 612cb5caa98Sdjl static void 613cb5caa98Sdjl queue_remove(nsc_db_t *nscdb, nsc_entry_t *entry) { 614cb5caa98Sdjl 615cb5caa98Sdjl if (nscdb->qtail == entry) 616cb5caa98Sdjl nscdb->qtail = entry->qnext; 617cb5caa98Sdjl else 618cb5caa98Sdjl entry->qprev->qnext = entry->qnext; 619cb5caa98Sdjl 620cb5caa98Sdjl if (nscdb->qhead == entry) 621cb5caa98Sdjl nscdb->qhead = entry->qprev; 622cb5caa98Sdjl else 623cb5caa98Sdjl entry->qnext->qprev = entry->qprev; 624cb5caa98Sdjl 625cb5caa98Sdjl if (nscdb->reap_node == entry) 626cb5caa98Sdjl nscdb->reap_node = entry->qnext; 627cb5caa98Sdjl entry->qnext = entry->qprev = NULL; 628cb5caa98Sdjl } 629cb5caa98Sdjl 630cb5caa98Sdjl 631cb5caa98Sdjl static void 632cb5caa98Sdjl queue_adjust(nsc_db_t *nscdb, nsc_entry_t *entry) { 633cb5caa98Sdjl 634cb5caa98Sdjl #ifdef NSCD_DEBUG 635cb5caa98Sdjl assert(nscdb->qtail || entry->qnext == NULL && 636cb5caa98Sdjl entry->qprev == NULL); 637cb5caa98Sdjl 638cb5caa98Sdjl assert(nscdb->qtail && nscdb->qhead || 639cb5caa98Sdjl nscdb->qtail == NULL && nscdb->qhead == NULL); 640cb5caa98Sdjl 641cb5caa98Sdjl assert(entry->qprev || entry->qnext == NULL || 642cb5caa98Sdjl nscdb->qtail == entry); 643cb5caa98Sdjl #endif /* NSCD_DEBUG */ 644cb5caa98Sdjl 645cb5caa98Sdjl /* already in the desired position */ 646cb5caa98Sdjl if (nscdb->qtail == entry) 647cb5caa98Sdjl return; 648cb5caa98Sdjl 649cb5caa98Sdjl /* new queue */ 650cb5caa98Sdjl if (nscdb->qtail == NULL) { 651cb5caa98Sdjl nscdb->qhead = nscdb->qtail = entry; 652cb5caa98Sdjl return; 653cb5caa98Sdjl } 654cb5caa98Sdjl 655cb5caa98Sdjl /* new entry (prev == NULL AND tail != entry) */ 656cb5caa98Sdjl if (entry->qprev == NULL) { 657cb5caa98Sdjl nscdb->qtail->qprev = entry; 658cb5caa98Sdjl entry->qnext = nscdb->qtail; 659cb5caa98Sdjl nscdb->qtail = entry; 660cb5caa98Sdjl return; 661cb5caa98Sdjl } 662cb5caa98Sdjl 663cb5caa98Sdjl /* existing entry */ 664cb5caa98Sdjl if (nscdb->reap_node == entry) 665cb5caa98Sdjl nscdb->reap_node = entry->qnext; 666cb5caa98Sdjl if (nscdb->qhead == entry) 667cb5caa98Sdjl nscdb->qhead = entry->qprev; 668cb5caa98Sdjl else 669cb5caa98Sdjl entry->qnext->qprev = entry->qprev; 670cb5caa98Sdjl entry->qprev->qnext = entry->qnext; 671cb5caa98Sdjl entry->qprev = NULL; 672cb5caa98Sdjl entry->qnext = nscdb->qtail; 673cb5caa98Sdjl nscdb->qtail->qprev = entry; 674cb5caa98Sdjl nscdb->qtail = entry; 675cb5caa98Sdjl } 676cb5caa98Sdjl 677cb5caa98Sdjl 678cb5caa98Sdjl /* 679cb5caa98Sdjl * Init cache 680cb5caa98Sdjl */ 681cb5caa98Sdjl nscd_rc_t 682cb5caa98Sdjl init_cache(int debug_level) { 683cb5caa98Sdjl int cflags; 684cb5caa98Sdjl 685cb5caa98Sdjl cflags = (debug_level > 0)?0:UMC_NODEBUG; 686cb5caa98Sdjl nsc_entry_cache = umem_cache_create("nsc_entry_cache", 687cb5caa98Sdjl sizeof (nsc_entry_t), 0, NULL, NULL, NULL, 688cb5caa98Sdjl NULL, NULL, cflags); 689cb5caa98Sdjl if (nsc_entry_cache == NULL) 690cb5caa98Sdjl return (NSCD_NO_MEMORY); 691cb5caa98Sdjl return (NSCD_SUCCESS); 692cb5caa98Sdjl } 693cb5caa98Sdjl 694cb5caa98Sdjl 695cb5caa98Sdjl /* 696cb5caa98Sdjl * Create cache 697cb5caa98Sdjl */ 698cb5caa98Sdjl nsc_db_t * 699cb5caa98Sdjl make_cache(enum db_type dbtype, int dbop, char *name, 700cb5caa98Sdjl int (*compar) (const void *, const void *), 701cb5caa98Sdjl void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *), 702cb5caa98Sdjl uint_t (*gethash)(nss_XbyY_key_t *, int), 703cb5caa98Sdjl enum hash_type httype, int htsize) { 704cb5caa98Sdjl 705cb5caa98Sdjl nsc_db_t *nscdb; 706cb5caa98Sdjl char *me = "make_cache"; 707cb5caa98Sdjl 708cb5caa98Sdjl nscdb = (nsc_db_t *)malloc(sizeof (*nscdb)); 709cb5caa98Sdjl if (nscdb == NULL) { 710cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 711cb5caa98Sdjl (me, "%s: memory allocation failure\n", name); 712cb5caa98Sdjl goto out; 713cb5caa98Sdjl } 714cb5caa98Sdjl (void) memset(nscdb, 0, sizeof (*nscdb)); 715cb5caa98Sdjl 716cb5caa98Sdjl nscdb->dbop = dbop; 717cb5caa98Sdjl nscdb->name = name; 718cb5caa98Sdjl nscdb->db_type = dbtype; 719cb5caa98Sdjl 720cb5caa98Sdjl /* Assign compare routine */ 721cb5caa98Sdjl if (compar == NULL) { 722cb5caa98Sdjl if (_NSC_DB_CES_KEY(nscdb)) 723cb5caa98Sdjl nscdb->compar = nsc_db_ces_key_compar; 724cb5caa98Sdjl else if (_NSC_DB_CIS_KEY(nscdb)) 725cb5caa98Sdjl nscdb->compar = nsc_db_cis_key_compar; 726cb5caa98Sdjl else if (_NSC_DB_INT_KEY(nscdb)) 727cb5caa98Sdjl nscdb->compar = nsc_db_int_key_compar; 728cb5caa98Sdjl else 729cb5caa98Sdjl assert(0); 730cb5caa98Sdjl } else { 731cb5caa98Sdjl nscdb->compar = compar; 732cb5caa98Sdjl } 733cb5caa98Sdjl 734cb5caa98Sdjl /* The cache is an AVL tree */ 735cb5caa98Sdjl avl_create(&nscdb->tree, nscdb->compar, sizeof (nsc_entry_t), 736cb5caa98Sdjl offsetof(nsc_entry_t, avl_link)); 737cb5caa98Sdjl 738cb5caa98Sdjl /* Assign log routine */ 739cb5caa98Sdjl if (getlogstr == NULL) { 740cb5caa98Sdjl if (_NSC_DB_STR_KEY(nscdb)) 741cb5caa98Sdjl nscdb->getlogstr = nsc_db_str_key_getlogstr; 742cb5caa98Sdjl else if (_NSC_DB_INT_KEY(nscdb)) 743cb5caa98Sdjl nscdb->getlogstr = nsc_db_int_key_getlogstr; 744cb5caa98Sdjl else 745cb5caa98Sdjl nscdb->getlogstr = nsc_db_any_key_getlogstr; 746cb5caa98Sdjl } else { 747cb5caa98Sdjl nscdb->getlogstr = getlogstr; 748cb5caa98Sdjl } 749cb5caa98Sdjl 750cb5caa98Sdjl /* The AVL tree based cache uses a hash table for quick access */ 751cb5caa98Sdjl if (htsize != 0) { 752cb5caa98Sdjl /* Determine hash table size based on type */ 753cb5caa98Sdjl nscdb->hash_type = httype; 754cb5caa98Sdjl if (htsize < 0) { 755cb5caa98Sdjl switch (httype) { 756cb5caa98Sdjl case nsc_ht_power2: 757cb5caa98Sdjl htsize = _NSC_INIT_HTSIZE_POWER2; 758cb5caa98Sdjl break; 759cb5caa98Sdjl case nsc_ht_prime: 760cb5caa98Sdjl case nsc_ht_default: 761cb5caa98Sdjl default: 762cb5caa98Sdjl htsize = _NSC_INIT_HTSIZE_PRIME; 763cb5caa98Sdjl } 764cb5caa98Sdjl } 765cb5caa98Sdjl nscdb->htsize = htsize; 766cb5caa98Sdjl 767cb5caa98Sdjl /* Create the hash table */ 768cb5caa98Sdjl nscdb->htable = calloc(htsize, sizeof (*(nscdb->htable))); 769cb5caa98Sdjl if (nscdb->htable == NULL) { 770cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 771cb5caa98Sdjl (me, "%s: memory allocation failure\n", name); 772cb5caa98Sdjl goto out; 773cb5caa98Sdjl } 774cb5caa98Sdjl 775cb5caa98Sdjl /* Assign gethash routine */ 776cb5caa98Sdjl if (gethash == NULL) { 777cb5caa98Sdjl if (_NSC_DB_CES_KEY(nscdb)) 778cb5caa98Sdjl nscdb->gethash = nsc_db_ces_key_gethash; 779cb5caa98Sdjl else if (_NSC_DB_CIS_KEY(nscdb)) 780cb5caa98Sdjl nscdb->gethash = nsc_db_cis_key_gethash; 781cb5caa98Sdjl else if (_NSC_DB_INT_KEY(nscdb)) 782cb5caa98Sdjl nscdb->gethash = nsc_db_int_key_gethash; 783cb5caa98Sdjl else 784cb5caa98Sdjl assert(0); 785cb5caa98Sdjl } else { 786cb5caa98Sdjl nscdb->gethash = gethash; 787cb5caa98Sdjl } 788cb5caa98Sdjl } 789cb5caa98Sdjl 790cb5caa98Sdjl (void) mutex_init(&nscdb->db_mutex, USYNC_THREAD, NULL); 791cb5caa98Sdjl return (nscdb); 792cb5caa98Sdjl 793cb5caa98Sdjl out: 794cb5caa98Sdjl if (nscdb->htable) 795cb5caa98Sdjl free(nscdb->htable); 796cb5caa98Sdjl if (nscdb) 797cb5caa98Sdjl free(nscdb); 798cb5caa98Sdjl return (NULL); 799cb5caa98Sdjl } 800cb5caa98Sdjl 801cb5caa98Sdjl 802cb5caa98Sdjl /* 803cb5caa98Sdjl * verify 804cb5caa98Sdjl */ 805cb5caa98Sdjl /* ARGSUSED */ 806cb5caa98Sdjl nscd_rc_t 807cb5caa98Sdjl _nscd_cfg_cache_verify( 808cb5caa98Sdjl void *data, 809cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc, 810cb5caa98Sdjl nscd_cfg_id_t *nswdb, 811cb5caa98Sdjl nscd_cfg_flag_t dflag, 812cb5caa98Sdjl nscd_cfg_error_t **errorp, 813cb5caa98Sdjl void **cookie) 814cb5caa98Sdjl { 815cb5caa98Sdjl 816cb5caa98Sdjl return (NSCD_SUCCESS); 817cb5caa98Sdjl } 818cb5caa98Sdjl 819cb5caa98Sdjl /* 820cb5caa98Sdjl * notify 821cb5caa98Sdjl */ 822cb5caa98Sdjl /* ARGSUSED */ 823cb5caa98Sdjl nscd_rc_t 824cb5caa98Sdjl _nscd_cfg_cache_notify( 825cb5caa98Sdjl void *data, 826cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc, 827cb5caa98Sdjl nscd_cfg_id_t *nswdb, 828cb5caa98Sdjl nscd_cfg_flag_t dflag, 829cb5caa98Sdjl nscd_cfg_error_t **errorp, 830cb5caa98Sdjl void **cookie) 831cb5caa98Sdjl { 832cb5caa98Sdjl nsc_ctx_t *ctx; 833cb5caa98Sdjl void *dp; 834cb5caa98Sdjl int i; 835cb5caa98Sdjl 836cb5caa98Sdjl /* group data */ 837cb5caa98Sdjl if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { 838cb5caa98Sdjl if (_nscd_cfg_flag_is_set(pdesc->pflag, 839cb5caa98Sdjl NSCD_CFG_PFLAG_GLOBAL)) { 840cb5caa98Sdjl /* global config */ 841cb5caa98Sdjl global_cfg = *(nscd_cfg_global_cache_t *)data; 842cb5caa98Sdjl } else if (_nscd_cfg_flag_is_set(dflag, 843cb5caa98Sdjl NSCD_CFG_DFLAG_SET_ALL_DB)) { 844cb5caa98Sdjl /* non-global config for all dbs */ 845cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 846cb5caa98Sdjl ctx = cache_ctx_p[i]; 847cb5caa98Sdjl if (ctx == NULL) 848cb5caa98Sdjl return (NSCD_CTX_NOT_FOUND); 849cb5caa98Sdjl (void) rw_wrlock(&ctx->cfg_rwlp); 850cb5caa98Sdjl ctx->cfg = *(nscd_cfg_cache_t *)data; 851cb5caa98Sdjl ctx->cfg_mtime = time(NULL); 852cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 853cb5caa98Sdjl } 854cb5caa98Sdjl } else { 855cb5caa98Sdjl /* non-global config for a specific db */ 856cb5caa98Sdjl 857cb5caa98Sdjl /* ignore non-caching databases */ 858cb5caa98Sdjl if (get_cache_ctx(nswdb->name, &ctx) != 859cb5caa98Sdjl NSCD_SUCCESS) 860cb5caa98Sdjl return (NSCD_SUCCESS); 861cb5caa98Sdjl (void) rw_wrlock(&ctx->cfg_rwlp); 862cb5caa98Sdjl ctx->cfg = *(nscd_cfg_cache_t *)data; 863cb5caa98Sdjl ctx->cfg_mtime = time(NULL); 864cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 865cb5caa98Sdjl } 866cb5caa98Sdjl return (NSCD_SUCCESS); 867cb5caa98Sdjl } 868cb5caa98Sdjl 869cb5caa98Sdjl /* individual data */ 870cb5caa98Sdjl if (_nscd_cfg_flag_is_set(pdesc->pflag, 871cb5caa98Sdjl NSCD_CFG_PFLAG_GLOBAL)) { 872cb5caa98Sdjl /* global config */ 873cb5caa98Sdjl dp = (char *)&global_cfg + pdesc->p_offset; 874cb5caa98Sdjl (void) memcpy(dp, data, pdesc->p_size); 875cb5caa98Sdjl } else if (_nscd_cfg_flag_is_set(dflag, 876cb5caa98Sdjl NSCD_CFG_DFLAG_SET_ALL_DB)) { 877cb5caa98Sdjl /* non-global config for all dbs */ 878cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 879cb5caa98Sdjl ctx = cache_ctx_p[i]; 880cb5caa98Sdjl if (ctx == NULL) 881cb5caa98Sdjl return (NSCD_CTX_NOT_FOUND); 882cb5caa98Sdjl dp = (char *)&ctx->cfg + pdesc->p_offset; 883cb5caa98Sdjl (void) rw_wrlock(&ctx->cfg_rwlp); 884cb5caa98Sdjl (void) memcpy(dp, data, pdesc->p_size); 885cb5caa98Sdjl ctx->cfg_mtime = time(NULL); 886cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 887cb5caa98Sdjl } 888cb5caa98Sdjl } else { 889cb5caa98Sdjl /* non-global config for a specific db */ 890cb5caa98Sdjl 891cb5caa98Sdjl /* ignore non-caching databases */ 892cb5caa98Sdjl if (get_cache_ctx(nswdb->name, &ctx) != NSCD_SUCCESS) 893cb5caa98Sdjl return (NSCD_SUCCESS); 894cb5caa98Sdjl dp = (char *)&ctx->cfg + pdesc->p_offset; 895cb5caa98Sdjl (void) rw_wrlock(&ctx->cfg_rwlp); 896cb5caa98Sdjl (void) memcpy(dp, data, pdesc->p_size); 897cb5caa98Sdjl ctx->cfg_mtime = time(NULL); 898cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 899cb5caa98Sdjl } 900cb5caa98Sdjl return (NSCD_SUCCESS); 901cb5caa98Sdjl } 902cb5caa98Sdjl 903cb5caa98Sdjl 904cb5caa98Sdjl /* 905cb5caa98Sdjl * get stat 906cb5caa98Sdjl */ 907cb5caa98Sdjl /* ARGSUSED */ 908cb5caa98Sdjl nscd_rc_t 909cb5caa98Sdjl _nscd_cfg_cache_get_stat( 910cb5caa98Sdjl void **stat, 911cb5caa98Sdjl struct nscd_cfg_stat_desc *sdesc, 912cb5caa98Sdjl nscd_cfg_id_t *nswdb, 913cb5caa98Sdjl nscd_cfg_flag_t *dflag, 914cb5caa98Sdjl void (**free_stat)(void *stat), 915cb5caa98Sdjl nscd_cfg_error_t **errorp) 916cb5caa98Sdjl { 917cb5caa98Sdjl nscd_cfg_stat_cache_t *statsp, stats; 918cb5caa98Sdjl nsc_ctx_t *ctx; 919cb5caa98Sdjl int i; 920cb5caa98Sdjl nscd_rc_t rc; 921cb5caa98Sdjl 922cb5caa98Sdjl statsp = calloc(1, sizeof (*statsp)); 923cb5caa98Sdjl if (statsp == NULL) 924cb5caa98Sdjl return (NSCD_NO_MEMORY); 925cb5caa98Sdjl 926cb5caa98Sdjl if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) { 927cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 928cb5caa98Sdjl if (cache_ctx_p[i] == NULL) 929cb5caa98Sdjl stats = null_stats; 930cb5caa98Sdjl else { 931cb5caa98Sdjl (void) mutex_lock(&cache_ctx_p[i]->stats_mutex); 932cb5caa98Sdjl stats = cache_ctx_p[i]->stats; 933cb5caa98Sdjl (void) mutex_unlock( 934cb5caa98Sdjl &cache_ctx_p[i]->stats_mutex); 935cb5caa98Sdjl } 936cb5caa98Sdjl statsp->pos_hits += stats.pos_hits; 937cb5caa98Sdjl statsp->neg_hits += stats.neg_hits; 938cb5caa98Sdjl statsp->pos_misses += stats.pos_misses; 939cb5caa98Sdjl statsp->neg_misses += stats.neg_misses; 940cb5caa98Sdjl statsp->entries += stats.entries; 941cb5caa98Sdjl statsp->drop_count += stats.drop_count; 942cb5caa98Sdjl statsp->wait_count += stats.wait_count; 943cb5caa98Sdjl statsp->invalidate_count += 944cb5caa98Sdjl stats.invalidate_count; 945cb5caa98Sdjl } 946cb5caa98Sdjl } else { 947cb5caa98Sdjl if ((rc = get_cache_ctx(nswdb->name, &ctx)) != NSCD_SUCCESS) { 948cb5caa98Sdjl free(statsp); 949cb5caa98Sdjl return (rc); 950cb5caa98Sdjl } 951cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 952cb5caa98Sdjl *statsp = ctx->stats; 953cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 954cb5caa98Sdjl } 955cb5caa98Sdjl 956cb5caa98Sdjl _NSC_GET_HITRATE(statsp); 957cb5caa98Sdjl *stat = statsp; 958cb5caa98Sdjl return (NSCD_SUCCESS); 959cb5caa98Sdjl } 960cb5caa98Sdjl 961cb5caa98Sdjl /* 962cb5caa98Sdjl * This function should only be called when nscd is 963cb5caa98Sdjl * not a daemon. 964cb5caa98Sdjl */ 965cb5caa98Sdjl void 966cb5caa98Sdjl nsc_info(nsc_ctx_t *ctx, char *dbname, nscd_cfg_cache_t cfg[], 967cb5caa98Sdjl nscd_cfg_stat_cache_t stats[]) 968cb5caa98Sdjl { 969cb5caa98Sdjl int i; 970cb5caa98Sdjl char *me = "nsc_info"; 971cb5caa98Sdjl nsc_ctx_t *ctx1; 972cb5caa98Sdjl nsc_ctx_t ctx2; 973cb5caa98Sdjl nscd_rc_t rc; 974cb5caa98Sdjl 975cb5caa98Sdjl if (ctx) { 976cb5caa98Sdjl ctx_info(ctx); 977cb5caa98Sdjl return; 978cb5caa98Sdjl } 979cb5caa98Sdjl 980cb5caa98Sdjl if (dbname) { 981cb5caa98Sdjl rc = get_cache_ctx(dbname, &ctx1); 982cb5caa98Sdjl if (rc == NSCD_INVALID_ARGUMENT) { 983cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 984cb5caa98Sdjl (me, "%s: no cache context found\n", dbname); 985cb5caa98Sdjl return; 986cb5caa98Sdjl } else if (rc == NSCD_NO_MEMORY) { 987cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 988cb5caa98Sdjl (me, "%s: unable to create cache context - no memory\n", 989cb5caa98Sdjl dbname); 990cb5caa98Sdjl return; 991cb5caa98Sdjl } 992cb5caa98Sdjl ctx_info(ctx1); 993cb5caa98Sdjl return; 994cb5caa98Sdjl } 995cb5caa98Sdjl 996cb5caa98Sdjl if (cfg == NULL || stats == NULL) 997cb5caa98Sdjl return; 998cb5caa98Sdjl 999cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 1000cb5caa98Sdjl 1001cb5caa98Sdjl ctx2.dbname = cache_name[i]; 1002cb5caa98Sdjl ctx2.cfg = cfg[i]; 1003cb5caa98Sdjl ctx2.stats = stats[i]; 1004cb5caa98Sdjl ctx_info_nolock(&ctx2); 1005cb5caa98Sdjl } 1006cb5caa98Sdjl } 1007cb5caa98Sdjl 1008cb5caa98Sdjl static void 1009cb5caa98Sdjl ctx_info_nolock(nsc_ctx_t *ctx) { 1010cb5caa98Sdjl nscd_cfg_cache_t cfg; 1011cb5caa98Sdjl nscd_cfg_stat_cache_t stats; 1012cb5caa98Sdjl 1013cb5caa98Sdjl cfg = ctx->cfg; 1014cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname); 1015cb5caa98Sdjl (void) print_cfg(&cfg); 1016cb5caa98Sdjl 1017cb5caa98Sdjl if (cfg.enable == nscd_false) 1018cb5caa98Sdjl return; 1019cb5caa98Sdjl 1020cb5caa98Sdjl stats = ctx->stats; 1021cb5caa98Sdjl (void) print_stats(&stats); 1022cb5caa98Sdjl } 1023cb5caa98Sdjl 1024cb5caa98Sdjl static void 1025cb5caa98Sdjl ctx_info(nsc_ctx_t *ctx) { 1026cb5caa98Sdjl nscd_cfg_cache_t cfg; 1027cb5caa98Sdjl nscd_cfg_stat_cache_t stats; 1028cb5caa98Sdjl 1029cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 1030cb5caa98Sdjl cfg = ctx->cfg; 1031cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 1032cb5caa98Sdjl (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname); 1033cb5caa98Sdjl (void) print_cfg(&cfg); 1034cb5caa98Sdjl 1035cb5caa98Sdjl if (cfg.enable == nscd_false) 1036cb5caa98Sdjl return; 1037cb5caa98Sdjl 1038cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1039cb5caa98Sdjl stats = ctx->stats; 1040cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1041cb5caa98Sdjl (void) print_stats(&stats); 1042cb5caa98Sdjl } 1043cb5caa98Sdjl 1044cb5caa98Sdjl #ifdef NSCD_DEBUG 1045cb5caa98Sdjl /* 1046cb5caa98Sdjl * This function should only be called when nscd is 1047cb5caa98Sdjl * not a daemon. 1048cb5caa98Sdjl */ 1049cb5caa98Sdjl int 1050cb5caa98Sdjl nsc_dump(char *dbname, int dbop) { 1051cb5caa98Sdjl nsc_ctx_t *ctx; 1052cb5caa98Sdjl nsc_db_t *nscdb; 1053cb5caa98Sdjl nscd_bool_t enabled; 1054cb5caa98Sdjl time_t now; 1055cb5caa98Sdjl char *me = "nsc_dump"; 1056cb5caa98Sdjl int i; 1057cb5caa98Sdjl 1058cb5caa98Sdjl if ((i = get_cache_idx(dbname)) == -1) { 1059cb5caa98Sdjl (void) fprintf(stdout, gettext("invalid cache name\n")); 1060cb5caa98Sdjl 1061cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1062cb5caa98Sdjl (me, "%s: invalid cache name\n", dbname); 1063cb5caa98Sdjl return (NSCD_CACHE_INVALID_CACHE_NAME); 1064cb5caa98Sdjl } 1065cb5caa98Sdjl 1066cb5caa98Sdjl if ((ctx = cache_ctx_p[i]) == NULL) { 1067cb5caa98Sdjl (void) fprintf(stdout, gettext("no cache context\n")); 1068cb5caa98Sdjl 1069cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1070cb5caa98Sdjl (me, "%s: no cache context\n", dbname); 1071cb5caa98Sdjl return (NSCD_CACHE_NO_CACHE_CTX); 1072cb5caa98Sdjl } 1073cb5caa98Sdjl 1074cb5caa98Sdjl now = time(NULL); 1075cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 1076cb5caa98Sdjl enabled = ctx->cfg.enable; 1077cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 1078cb5caa98Sdjl 1079cb5caa98Sdjl if (enabled == nscd_false) 1080cb5caa98Sdjl return (NSCD_CACHE_DISABLED); 1081cb5caa98Sdjl 1082cb5caa98Sdjl nscdb = nsc_get_db(ctx, dbop); 1083cb5caa98Sdjl if (nscdb == NULL) { 1084cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1085cb5caa98Sdjl (me, "%s:%d: no cache found\n", dbname, dbop); 1086cb5caa98Sdjl return (NSCD_CACHE_NO_CACHE_FOUND); 1087cb5caa98Sdjl } 1088cb5caa98Sdjl 1089cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 1090cb5caa98Sdjl (void) queue_dump(nscdb, now); 1091cb5caa98Sdjl (void) hash_dump(nscdb, now); 1092cb5caa98Sdjl (void) avl_dump(nscdb, now); 1093cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1094cb5caa98Sdjl return (NSCD_SUCCESS); 1095cb5caa98Sdjl } 1096cb5caa98Sdjl #endif /* NSCD_DEBUG */ 1097cb5caa98Sdjl 1098cb5caa98Sdjl /* 1099cb5caa98Sdjl * These macros are for exclusive use of nsc_lookup 1100cb5caa98Sdjl */ 1101cb5caa98Sdjl #define NSC_LOOKUP_RETURN(retcode, loglevel, fmt) \ 1102cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); \ 1103cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_##loglevel) \ 1104cb5caa98Sdjl (me, fmt, whoami); \ 1105cb5caa98Sdjl return (retcode); 1106cb5caa98Sdjl 1107cb5caa98Sdjl #define NSC_LOOKUP_NO_CACHE(str) \ 1108cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) \ 1109cb5caa98Sdjl (me, "%s: name service lookup (bypassing cache\n", \ 1110cb5caa98Sdjl str); \ 1111cb5caa98Sdjl nss_psearch(largs->buffer, largs->bufsize); \ 1112cb5caa98Sdjl status = NSCD_GET_STATUS(largs->buffer); \ 1113cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) \ 1114cb5caa98Sdjl (me, "%s: name service lookup status = %d\n", \ 1115cb5caa98Sdjl str, status); \ 1116cb5caa98Sdjl if (status == NSS_SUCCESS) { \ 1117cb5caa98Sdjl return (SUCCESS); \ 1118cb5caa98Sdjl } else if (status == NSS_NOTFOUND) \ 1119cb5caa98Sdjl return (NOTFOUND); \ 1120cb5caa98Sdjl else \ 1121cb5caa98Sdjl return (SERVERERROR); 1122cb5caa98Sdjl 1123cb5caa98Sdjl /* 1124cb5caa98Sdjl * This function starts the revalidation and reaper threads 1125cb5caa98Sdjl * for a cache 1126cb5caa98Sdjl */ 1127cb5caa98Sdjl static void 1128cb5caa98Sdjl start_threads(nsc_ctx_t *ctx) { 1129cb5caa98Sdjl 1130cb5caa98Sdjl int errnum; 1131cb5caa98Sdjl char *me = "start_threads"; 1132cb5caa98Sdjl 1133cb5caa98Sdjl /* 1134cb5caa98Sdjl * kick off the revalidate thread (if necessary) 1135cb5caa98Sdjl */ 1136cb5caa98Sdjl if (ctx->revalidate_on != nscd_true) { 1137cb5caa98Sdjl if (thr_create(NULL, NULL, (void *(*)(void *))revalidate, 1138cb5caa98Sdjl ctx, 0, NULL) != 0) { 1139cb5caa98Sdjl errnum = errno; 1140cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1141cb5caa98Sdjl (me, "thr_create (revalidate thread for %s): %s\n", 1142cb5caa98Sdjl ctx->dbname, strerror(errnum)); 1143cb5caa98Sdjl exit(1); 1144cb5caa98Sdjl } 1145cb5caa98Sdjl ctx->revalidate_on = nscd_true; 1146cb5caa98Sdjl } 1147cb5caa98Sdjl 1148cb5caa98Sdjl /* 1149cb5caa98Sdjl * kick off the reaper thread (if necessary) 1150cb5caa98Sdjl */ 1151cb5caa98Sdjl if (ctx->reaper_on != nscd_true) { 1152cb5caa98Sdjl if (thr_create(NULL, NULL, (void *(*)(void *))reaper, 1153cb5caa98Sdjl ctx, 0, NULL) != 0) { 1154cb5caa98Sdjl errnum = errno; 1155cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1156cb5caa98Sdjl (me, "thr_create (reaper thread for %s): %s\n", 1157cb5caa98Sdjl ctx->dbname, strerror(errnum)); 1158cb5caa98Sdjl exit(1); 1159cb5caa98Sdjl } 1160cb5caa98Sdjl ctx->reaper_on = nscd_true; 1161cb5caa98Sdjl } 1162cb5caa98Sdjl } 1163cb5caa98Sdjl 1164cb5caa98Sdjl /* 1165cb5caa98Sdjl * Examine the packed buffer, see if the front-end parameters 1166cb5caa98Sdjl * indicate that the caller specified nsswitch config should be 1167cb5caa98Sdjl * used for the lookup. Return 1 if yes, otherwise 0. 1168cb5caa98Sdjl */ 1169cb5caa98Sdjl static int 1170cb5caa98Sdjl nsw_config_in_phdr(void *buf) 1171cb5caa98Sdjl { 1172cb5caa98Sdjl nss_pheader_t *pbuf = (nss_pheader_t *)buf; 1173cb5caa98Sdjl nssuint_t off; 1174cb5caa98Sdjl nss_dbd_t *pdbd; 1175cb5caa98Sdjl char *me = "nsw_config_in_phdr"; 1176cb5caa98Sdjl 1177cb5caa98Sdjl off = pbuf->dbd_off; 1178cb5caa98Sdjl if (off == 0) 1179cb5caa98Sdjl return (0); 1180cb5caa98Sdjl pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off)); 1181cb5caa98Sdjl if (pdbd->o_default_config == 0) 1182cb5caa98Sdjl return (0); 1183cb5caa98Sdjl 1184cb5caa98Sdjl if ((enum nss_dbp_flags)pdbd->flags & NSS_USE_DEFAULT_CONFIG) { 1185cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1186cb5caa98Sdjl (me, "use caller specified nsswitch config\n"); 1187cb5caa98Sdjl return (1); 1188cb5caa98Sdjl } else 1189cb5caa98Sdjl return (0); 1190cb5caa98Sdjl } 1191cb5caa98Sdjl 1192cb5caa98Sdjl static nss_status_t 1193cb5caa98Sdjl copy_result(void *rbuf, void *cbuf) 1194cb5caa98Sdjl { 1195cb5caa98Sdjl nss_pheader_t *rphdr = (nss_pheader_t *)rbuf; 1196cb5caa98Sdjl nss_pheader_t *cphdr = (nss_pheader_t *)cbuf; 1197cb5caa98Sdjl char *me = "copy_result"; 1198cb5caa98Sdjl 1199cb5caa98Sdjl /* return NSS_ERROR if not enough room to copy result */ 1200cb5caa98Sdjl if (cphdr->data_len + 1 > rphdr->data_len) { 1201cb5caa98Sdjl NSCD_SET_STATUS(rphdr, NSS_ERROR, ERANGE); 1202cb5caa98Sdjl return (NSS_ERROR); 1203cb5caa98Sdjl } else { 1204cb5caa98Sdjl char *dst; 1205cb5caa98Sdjl 1206cb5caa98Sdjl if (cphdr->data_len == 0) 1207cb5caa98Sdjl return (NSS_SUCCESS); 1208cb5caa98Sdjl 1209cb5caa98Sdjl dst = (char *)rphdr + rphdr->data_off; 1210cb5caa98Sdjl (void) memcpy(dst, (char *)cphdr + cphdr->data_off, 1211cb5caa98Sdjl cphdr->data_len); 1212cb5caa98Sdjl rphdr->data_len = cphdr->data_len; 1213cb5caa98Sdjl /* some frontend code expects a terminating NULL char */ 1214cb5caa98Sdjl *(dst + rphdr->data_len) = '\0'; 1215cb5caa98Sdjl 1216cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1217*e37190e5Smichen (me, "cache data (len = %lld): >>%s<<\n", 1218cb5caa98Sdjl cphdr->data_len, (char *)cphdr + cphdr->data_off); 1219cb5caa98Sdjl 1220cb5caa98Sdjl return (NSS_SUCCESS); 1221cb5caa98Sdjl } 1222cb5caa98Sdjl } 1223cb5caa98Sdjl 1224cb5caa98Sdjl static int 1225cb5caa98Sdjl get_dns_ttl(void *pbuf, char *dbname) 1226cb5caa98Sdjl { 1227cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)pbuf; 1228cb5caa98Sdjl int ttl; 1229cb5caa98Sdjl char *me = "get_dns_ttl"; 1230cb5caa98Sdjl 1231cb5caa98Sdjl /* if returned, dns ttl is stored in the extended data area */ 1232cb5caa98Sdjl if (phdr->ext_off == 0) 1233cb5caa98Sdjl return (-1); 1234cb5caa98Sdjl 1235cb5caa98Sdjl if (strcmp(dbname, NSS_DBNAM_HOSTS) != 0 && 1236cb5caa98Sdjl strcmp(dbname, NSS_DBNAM_IPNODES) != 0) 1237cb5caa98Sdjl return (-1); 1238cb5caa98Sdjl 1239cb5caa98Sdjl ttl = *(nssuint_t *)((void *)((char *)pbuf + phdr->ext_off)); 1240cb5caa98Sdjl 1241cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1242cb5caa98Sdjl (me, "dns ttl is %d seconds\n", ttl); 1243cb5caa98Sdjl 1244cb5caa98Sdjl return (ttl); 1245cb5caa98Sdjl } 1246cb5caa98Sdjl 1247cb5caa98Sdjl static int 1248cb5caa98Sdjl check_config(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp, 1249cb5caa98Sdjl char *whoami, int flag) 1250cb5caa98Sdjl { 1251cb5caa98Sdjl nsc_db_t *nscdb; 1252cb5caa98Sdjl nsc_ctx_t *ctx; 1253cb5caa98Sdjl nss_status_t status; 1254cb5caa98Sdjl char *me = "check_config"; 1255cb5caa98Sdjl 1256cb5caa98Sdjl ctx = largs->ctx; 1257cb5caa98Sdjl nscdb = largs->nscdb; 1258cb5caa98Sdjl 1259cb5caa98Sdjl /* see if the cached config needs update */ 1260cb5caa98Sdjl if (nscdb->cfg_mtime != ctx->cfg_mtime) { 1261cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 1262cb5caa98Sdjl nscdb->cfg = ctx->cfg; 1263cb5caa98Sdjl nscdb->cfg_mtime = ctx->cfg_mtime; 1264cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 1265cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1266cb5caa98Sdjl (me, "config for context %s, database %s updated\n", 1267cb5caa98Sdjl ctx->dbname, nscdb->name); 1268cb5caa98Sdjl } 1269cb5caa98Sdjl *cfgp = nscdb->cfg; 1270cb5caa98Sdjl 1271cb5caa98Sdjl if (cfgp->enable == nscd_false) { 1272cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1273cb5caa98Sdjl (me, "%s: cache disabled\n", ctx->dbname); 1274cb5caa98Sdjl 1275cb5caa98Sdjl if (UPDATEBIT & flag) 1276cb5caa98Sdjl return (NOTFOUND); 1277cb5caa98Sdjl else { 1278cb5caa98Sdjl NSC_LOOKUP_NO_CACHE(whoami); 1279cb5caa98Sdjl } 1280cb5caa98Sdjl } 1281cb5caa98Sdjl 1282cb5caa98Sdjl /* 1283cb5caa98Sdjl * if caller requests lookup using his 1284cb5caa98Sdjl * own nsswitch config, bypass cache 1285cb5caa98Sdjl */ 1286cb5caa98Sdjl if (nsw_config_in_phdr(largs->buffer)) { 1287cb5caa98Sdjl NSC_LOOKUP_NO_CACHE(whoami); 1288cb5caa98Sdjl } 1289cb5caa98Sdjl 1290cb5caa98Sdjl /* no need of cache if we are dealing with 0 ttls */ 1291cb5caa98Sdjl if (cfgp->pos_ttl <= 0 && cfgp->neg_ttl <= 0) { 1292cb5caa98Sdjl if (flag & UPDATEBIT) 1293cb5caa98Sdjl return (NOTFOUND); 1294cb5caa98Sdjl else if (cfgp->avoid_ns == nscd_true) 1295cb5caa98Sdjl return (SERVERERROR); 1296cb5caa98Sdjl NSC_LOOKUP_NO_CACHE(whoami); 1297cb5caa98Sdjl } 1298cb5caa98Sdjl 1299cb5caa98Sdjl return (CONTINUE); 1300cb5caa98Sdjl } 1301cb5caa98Sdjl 1302cb5caa98Sdjl /* 1303cb5caa98Sdjl * Invalidate cache if database file has been modified. 1304cb5caa98Sdjl * See check_files config param for details. 1305cb5caa98Sdjl */ 1306cb5caa98Sdjl static void 1307cb5caa98Sdjl check_db_file(nsc_ctx_t *ctx, nscd_cfg_cache_t cfg, 1308cb5caa98Sdjl char *whoami, time_t now) 1309cb5caa98Sdjl { 1310cb5caa98Sdjl struct stat buf; 1311cb5caa98Sdjl nscd_bool_t file_modified = nscd_false; 1312cb5caa98Sdjl char *me = "check_db_file"; 1313cb5caa98Sdjl 1314cb5caa98Sdjl if (cfg.check_interval != 0 && 1315cb5caa98Sdjl (now - ctx->file_chktime) < cfg.check_interval) 1316cb5caa98Sdjl return; 1317cb5caa98Sdjl 1318cb5caa98Sdjl ctx->file_chktime = now; 1319cb5caa98Sdjl if (stat(ctx->file_name, &buf) == 0) { 1320cb5caa98Sdjl if (ctx->file_mtime == 0) { 1321cb5caa98Sdjl (void) mutex_lock(&ctx->file_mutex); 1322cb5caa98Sdjl if (ctx->file_mtime == 0) { 1323cb5caa98Sdjl ctx->file_mtime = buf.st_mtime; 1324cb5caa98Sdjl ctx->file_size = buf.st_size; 1325cb5caa98Sdjl ctx->file_ino = buf.st_ino; 1326cb5caa98Sdjl } 1327cb5caa98Sdjl (void) mutex_unlock(&ctx->file_mutex); 1328cb5caa98Sdjl } else if (ctx->file_mtime < buf.st_mtime || 1329cb5caa98Sdjl ctx->file_size != buf.st_size || 1330cb5caa98Sdjl ctx->file_ino != buf.st_ino) { 1331cb5caa98Sdjl (void) mutex_lock(&ctx->file_mutex); 1332cb5caa98Sdjl if (ctx->file_mtime < buf.st_mtime || 1333cb5caa98Sdjl ctx->file_size != buf.st_size || 1334cb5caa98Sdjl ctx->file_ino != buf.st_ino) { 1335cb5caa98Sdjl file_modified = nscd_true; 1336cb5caa98Sdjl ctx->file_mtime = buf.st_mtime; 1337cb5caa98Sdjl ctx->file_size = buf.st_size; 1338cb5caa98Sdjl ctx->file_ino = buf.st_ino; 1339cb5caa98Sdjl } 1340cb5caa98Sdjl (void) mutex_unlock(&ctx->file_mutex); 1341cb5caa98Sdjl } 1342cb5caa98Sdjl } 1343cb5caa98Sdjl 1344cb5caa98Sdjl if (file_modified == nscd_true) { 1345cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1346cb5caa98Sdjl (me, "%s: file %s has been modified - invalidating cache\n", 1347cb5caa98Sdjl whoami, ctx->file_name); 1348cb5caa98Sdjl ctx_invalidate(ctx); 1349cb5caa98Sdjl } 1350cb5caa98Sdjl } 1351cb5caa98Sdjl 1352cb5caa98Sdjl static int 1353cb5caa98Sdjl lookup_int(nsc_lookup_args_t *largs, int flag) { 1354cb5caa98Sdjl 1355cb5caa98Sdjl nsc_ctx_t *ctx; 1356cb5caa98Sdjl nsc_db_t *nscdb; 1357cb5caa98Sdjl nscd_cfg_cache_t cfg; 1358cb5caa98Sdjl nsc_entry_t *this_entry; 1359cb5caa98Sdjl nsc_entry_stat_t *this_stats; 1360cb5caa98Sdjl nsc_action_t next_action; 1361cb5caa98Sdjl nss_status_t status; 1362cb5caa98Sdjl nscd_bool_t delete; 1363cb5caa98Sdjl nscd_rc_t rc; 1364cb5caa98Sdjl char *dbname; 1365cb5caa98Sdjl int dbop, errnum; 1366cb5caa98Sdjl int cfg_rc; 1367cb5caa98Sdjl nss_XbyY_args_t args; 1368cb5caa98Sdjl char whoami[128]; 1369cb5caa98Sdjl time_t now = time(NULL); /* current time */ 1370cb5caa98Sdjl char *me = "lookup_int"; 1371cb5caa98Sdjl 1372cb5caa98Sdjl /* extract dbop, dbname, key and cred */ 1373cb5caa98Sdjl status = nss_packed_getkey(largs->buffer, largs->bufsize, &dbname, 1374cb5caa98Sdjl &dbop, &args); 1375cb5caa98Sdjl if (status != NSS_SUCCESS) { 1376cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1377cb5caa98Sdjl (me, "nss_packed_getkey failure (%d)\n", status); 1378cb5caa98Sdjl return (SERVERERROR); 1379cb5caa98Sdjl } 1380cb5caa98Sdjl 1381cb5caa98Sdjl /* get the cache context */ 1382cb5caa98Sdjl if (largs->ctx == NULL) { 1383cb5caa98Sdjl if (get_cache_ctx(dbname, &largs->ctx) != NSCD_SUCCESS) { 1384cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1385cb5caa98Sdjl (me, "%s: no cache context found\n", dbname); 1386cb5caa98Sdjl 1387cb5caa98Sdjl if (UPDATEBIT & flag) 1388cb5caa98Sdjl return (NOTFOUND); 1389cb5caa98Sdjl else { 1390cb5caa98Sdjl NSC_LOOKUP_NO_CACHE(dbname); 1391cb5caa98Sdjl } 1392cb5caa98Sdjl } 1393cb5caa98Sdjl } 1394cb5caa98Sdjl ctx = largs->ctx; 1395cb5caa98Sdjl 1396cb5caa98Sdjl if (largs->nscdb == NULL) { 1397cb5caa98Sdjl if ((largs->nscdb = nsc_get_db(ctx, dbop)) == NULL) { 1398cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1399cb5caa98Sdjl (me, "%s:%d: no cache found\n", 1400cb5caa98Sdjl dbname, dbop); 1401cb5caa98Sdjl 1402cb5caa98Sdjl if (UPDATEBIT & flag) 1403cb5caa98Sdjl return (NOTFOUND); 1404cb5caa98Sdjl else { 1405cb5caa98Sdjl NSC_LOOKUP_NO_CACHE(dbname); 1406cb5caa98Sdjl } 1407cb5caa98Sdjl } 1408cb5caa98Sdjl } 1409cb5caa98Sdjl 1410cb5caa98Sdjl nscdb = largs->nscdb; 1411cb5caa98Sdjl 1412cb5caa98Sdjl _NSCD_LOG_IF(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ALL) { 1413cb5caa98Sdjl (void) nscdb->getlogstr(nscdb->name, whoami, 1414cb5caa98Sdjl sizeof (whoami), &args); 1415cb5caa98Sdjl } 1416cb5caa98Sdjl 1417cb5caa98Sdjl if (UPDATEBIT & flag) { 1418cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1419cb5caa98Sdjl (me, "%s: refresh start\n", whoami); 1420cb5caa98Sdjl } else { 1421cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1422cb5caa98Sdjl (me, "%s: lookup start\n", whoami); 1423cb5caa98Sdjl } 1424cb5caa98Sdjl 1425cb5caa98Sdjl cfg_rc = check_config(largs, &cfg, whoami, flag); 1426cb5caa98Sdjl if (cfg_rc != CONTINUE) 1427cb5caa98Sdjl return (cfg_rc); 1428cb5caa98Sdjl 1429cb5caa98Sdjl /* 1430cb5caa98Sdjl * Invalidate cache if file has been modified. 1431cb5caa98Sdjl */ 1432cb5caa98Sdjl if (cfg.check_files == nscd_true) 1433cb5caa98Sdjl check_db_file(ctx, cfg, whoami, now); 1434cb5caa98Sdjl 1435cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 1436cb5caa98Sdjl 1437cb5caa98Sdjl /* Lookup the cache table */ 1438cb5caa98Sdjl for (;;) { 1439cb5caa98Sdjl delete = nscd_false; 1440cb5caa98Sdjl rc = lookup_cache(largs, &cfg, &args, whoami, &this_entry); 1441cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 1442cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1443cb5caa98Sdjl 1444cb5caa98Sdjl /* Either no entry and avoid name service */ 1445cb5caa98Sdjl if (rc == NSCD_DB_ENTRY_NOT_FOUND || 1446cb5caa98Sdjl rc == NSCD_INVALID_ARGUMENT) 1447cb5caa98Sdjl return (NOTFOUND); 1448cb5caa98Sdjl 1449cb5caa98Sdjl /* OR memory error */ 1450cb5caa98Sdjl return (SERVERERROR); 1451cb5caa98Sdjl } 1452cb5caa98Sdjl 1453cb5caa98Sdjl /* get the stats from the entry */ 1454cb5caa98Sdjl this_stats = &this_entry->stats; 1455cb5caa98Sdjl 1456cb5caa98Sdjl /* 1457cb5caa98Sdjl * What should we do next ? 1458cb5caa98Sdjl */ 1459cb5caa98Sdjl switch (this_stats->status) { 1460cb5caa98Sdjl case ST_NEW_ENTRY: 1461cb5caa98Sdjl delete = nscd_true; 1462cb5caa98Sdjl next_action = _NSC_NSLOOKUP; 1463cb5caa98Sdjl break; 1464cb5caa98Sdjl case ST_UPDATE_PENDING: 1465cb5caa98Sdjl if (flag & UPDATEBIT) { 1466cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1467cb5caa98Sdjl return (NOTFOUND); 1468cb5caa98Sdjl } else if (this_stats->timestamp < now) 1469cb5caa98Sdjl next_action = _NSC_WAIT; 1470cb5caa98Sdjl else 1471cb5caa98Sdjl next_action = _NSC_USECACHED; 1472cb5caa98Sdjl break; 1473cb5caa98Sdjl case ST_LOOKUP_PENDING: 1474cb5caa98Sdjl if (flag & UPDATEBIT) { 1475cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1476cb5caa98Sdjl return (NOTFOUND); 1477cb5caa98Sdjl } 1478cb5caa98Sdjl next_action = _NSC_WAIT; 1479cb5caa98Sdjl break; 1480cb5caa98Sdjl case ST_DISCARD: 1481cb5caa98Sdjl if (cfg.avoid_ns == nscd_true) { 1482cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1483cb5caa98Sdjl return (NOTFOUND); 1484cb5caa98Sdjl } 1485cb5caa98Sdjl /* otherwise reuse the entry */ 1486cb5caa98Sdjl (void) memset(this_stats, 0, sizeof (*this_stats)); 1487cb5caa98Sdjl next_action = _NSC_NSLOOKUP; 1488cb5caa98Sdjl break; 1489cb5caa98Sdjl default: 1490cb5caa98Sdjl if (cfg.avoid_ns == nscd_true) 1491cb5caa98Sdjl next_action = _NSC_USECACHED; 1492cb5caa98Sdjl else if ((flag & UPDATEBIT) || 1493cb5caa98Sdjl (this_stats->timestamp < now)) { 1494cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1495cb5caa98Sdjl (me, "%s: cached entry needs to be updated\n", 1496cb5caa98Sdjl whoami); 1497cb5caa98Sdjl next_action = _NSC_NSLOOKUP; 1498cb5caa98Sdjl } else 1499cb5caa98Sdjl next_action = _NSC_USECACHED; 1500cb5caa98Sdjl break; 1501cb5caa98Sdjl } 1502cb5caa98Sdjl 1503cb5caa98Sdjl if (next_action == _NSC_WAIT) { 1504cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1505cb5caa98Sdjl (me, "%s: need to wait\n", whoami); 1506cb5caa98Sdjl 1507cb5caa98Sdjl /* do we have clearance ? */ 1508cb5caa98Sdjl if (_nscd_get_clearance(&ctx->throttle_sema) != 0) { 1509cb5caa98Sdjl /* nope. quit */ 1510cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1511cb5caa98Sdjl ctx->stats.drop_count++; 1512cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1513cb5caa98Sdjl NSC_LOOKUP_RETURN(NOSERVER, WARNING, 1514cb5caa98Sdjl "%s: no clearance to wait\n"); 1515cb5caa98Sdjl } 1516cb5caa98Sdjl /* yes can wait */ 1517cb5caa98Sdjl (void) nscd_wait(&ctx->wait, &nscdb->db_mutex, 1518cb5caa98Sdjl &this_stats->status); 1519cb5caa98Sdjl (void) _nscd_release_clearance(&ctx->throttle_sema); 1520cb5caa98Sdjl continue; 1521cb5caa98Sdjl } 1522cb5caa98Sdjl 1523cb5caa98Sdjl break; 1524cb5caa98Sdjl } 1525cb5caa98Sdjl 1526cb5caa98Sdjl 1527cb5caa98Sdjl if (!(UPDATEBIT & flag)) 1528cb5caa98Sdjl this_stats->hits++; /* update hit count */ 1529cb5caa98Sdjl 1530cb5caa98Sdjl if (next_action == _NSC_NSLOOKUP) { 1531cb5caa98Sdjl 1532cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1533cb5caa98Sdjl (me, "%s: name service lookup required\n", whoami); 1534cb5caa98Sdjl 1535cb5caa98Sdjl if (_nscd_get_clearance(&ctx->throttle_sema) != 0) { 1536cb5caa98Sdjl if (delete == nscd_true) 1537cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1538cb5caa98Sdjl else 1539cb5caa98Sdjl this_stats->status = ST_DISCARD; 1540cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1541cb5caa98Sdjl ctx->stats.drop_count++; 1542cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1543cb5caa98Sdjl NSC_LOOKUP_RETURN(NOSERVER, WARNING, 1544cb5caa98Sdjl "%s: no clearance for lookup\n"); 1545cb5caa98Sdjl } 1546cb5caa98Sdjl 1547cb5caa98Sdjl /* block any threads accessing this entry */ 1548cb5caa98Sdjl this_stats->status = (flag & UPDATEBIT)? 1549cb5caa98Sdjl ST_UPDATE_PENDING:ST_LOOKUP_PENDING; 1550cb5caa98Sdjl 1551cb5caa98Sdjl /* release lock and do name service lookup */ 1552cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1553cb5caa98Sdjl nss_psearch(largs->buffer, largs->bufsize); 1554cb5caa98Sdjl status = NSCD_GET_STATUS(largs->buffer); 1555cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 1556cb5caa98Sdjl this_stats->status = 0; 1557cb5caa98Sdjl (void) _nscd_release_clearance(&ctx->throttle_sema); 1558cb5caa98Sdjl 1559cb5caa98Sdjl /* signal waiting threads */ 1560cb5caa98Sdjl (void) nscd_signal(&ctx->wait, &this_stats->status); 1561cb5caa98Sdjl 1562cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1563cb5caa98Sdjl (me, "%s: name service lookup status = %d\n", 1564cb5caa98Sdjl whoami, status); 1565cb5caa98Sdjl 1566cb5caa98Sdjl if (status == NSS_SUCCESS) { 1567cb5caa98Sdjl int ttl; 1568cb5caa98Sdjl 1569cb5caa98Sdjl /* 1570cb5caa98Sdjl * data found in name service 1571cb5caa98Sdjl * update cache 1572cb5caa98Sdjl */ 1573cb5caa98Sdjl status = dup_packed_buffer(largs, this_entry); 1574cb5caa98Sdjl if (status != NSS_SUCCESS) { 1575cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1576cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1577cb5caa98Sdjl "%s: failed to update cache\n"); 1578cb5caa98Sdjl } 1579cb5caa98Sdjl 1580cb5caa98Sdjl /* 1581cb5caa98Sdjl * store unpacked key in cache 1582cb5caa98Sdjl */ 1583cb5caa98Sdjl status = nss_packed_getkey(this_entry->buffer, 1584cb5caa98Sdjl this_entry->bufsize, 1585cb5caa98Sdjl &dbname, &dbop, &args); 1586cb5caa98Sdjl if (status != NSS_SUCCESS) { 1587cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1588cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1589cb5caa98Sdjl "%s: failed to extract key\n"); 1590cb5caa98Sdjl } 1591cb5caa98Sdjl this_entry->key = args.key; /* struct copy */ 1592cb5caa98Sdjl 1593cb5caa98Sdjl /* update +ve miss count */ 1594cb5caa98Sdjl if (!(UPDATEBIT & flag)) { 1595cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1596cb5caa98Sdjl ctx->stats.pos_misses++; 1597cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1598cb5caa98Sdjl } 1599cb5caa98Sdjl 1600cb5caa98Sdjl /* update +ve ttl */ 1601cb5caa98Sdjl ttl = get_dns_ttl(largs->buffer, dbname); 1602cb5caa98Sdjl /* honor the dns ttl less than postive ttl */ 1603cb5caa98Sdjl if (ttl < 0 || ttl > cfg.pos_ttl) 1604cb5caa98Sdjl ttl = cfg.pos_ttl; 1605cb5caa98Sdjl this_stats->timestamp = time(NULL) + ttl; 1606cb5caa98Sdjl 1607cb5caa98Sdjl /* 1608cb5caa98Sdjl * start the revalidation and reaper threads 1609cb5caa98Sdjl * if not already started 1610cb5caa98Sdjl */ 1611cb5caa98Sdjl start_threads(ctx); 1612cb5caa98Sdjl 1613cb5caa98Sdjl NSC_LOOKUP_RETURN(SUCCESS, DEBUG, 1614cb5caa98Sdjl "%s: cache updated with positive entry\n"); 1615cb5caa98Sdjl } else if (status == NSS_NOTFOUND) { 1616cb5caa98Sdjl /* 1617cb5caa98Sdjl * data not found in name service 1618cb5caa98Sdjl * update cache 1619cb5caa98Sdjl */ 1620cb5caa98Sdjl 1621cb5caa98Sdjl if (NSCD_GET_ERRNO(largs->buffer) == ERANGE) { 1622cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1623cb5caa98Sdjl NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, 1624cb5caa98Sdjl "%s: ERANGE, cache not updated with negative entry\n"); 1625cb5caa98Sdjl } 1626cb5caa98Sdjl 1627cb5caa98Sdjl status = dup_packed_buffer(largs, this_entry); 1628cb5caa98Sdjl if (status != NSS_SUCCESS) { 1629cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1630cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1631cb5caa98Sdjl "%s: failed to update cache\n"); 1632cb5caa98Sdjl } 1633cb5caa98Sdjl 1634cb5caa98Sdjl /* store unpacked key in cache */ 1635cb5caa98Sdjl status = nss_packed_getkey(this_entry->buffer, 1636cb5caa98Sdjl this_entry->bufsize, 1637cb5caa98Sdjl &dbname, &dbop, &args); 1638cb5caa98Sdjl if (status != NSS_SUCCESS) { 1639cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1640cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1641cb5caa98Sdjl "%s: failed to extract key\n"); 1642cb5caa98Sdjl } 1643cb5caa98Sdjl this_entry->key = args.key; /* struct copy */ 1644cb5caa98Sdjl 1645cb5caa98Sdjl /* update -ve ttl */ 1646cb5caa98Sdjl this_stats->timestamp = time(NULL) + cfg.neg_ttl; 1647cb5caa98Sdjl 1648cb5caa98Sdjl /* update -ve miss count */ 1649cb5caa98Sdjl if (!(UPDATEBIT & flag)) { 1650cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1651cb5caa98Sdjl ctx->stats.neg_misses++; 1652cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1653cb5caa98Sdjl } 1654cb5caa98Sdjl 1655cb5caa98Sdjl /* 1656cb5caa98Sdjl * start the revalidation and reaper threads 1657cb5caa98Sdjl * if not already started 1658cb5caa98Sdjl */ 1659cb5caa98Sdjl start_threads(ctx); 1660cb5caa98Sdjl 1661cb5caa98Sdjl NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, 1662cb5caa98Sdjl "%s: cache updated with negative entry\n"); 1663cb5caa98Sdjl } else { 1664cb5caa98Sdjl /* 1665cb5caa98Sdjl * name service lookup failed 1666cb5caa98Sdjl */ 1667cb5caa98Sdjl errnum = NSCD_GET_ERRNO(largs->buffer); 1668cb5caa98Sdjl if (delete == nscd_true) 1669cb5caa98Sdjl delete_entry(nscdb, ctx, this_entry); 1670cb5caa98Sdjl else 1671cb5caa98Sdjl this_stats->status = ST_DISCARD; 1672cb5caa98Sdjl 1673cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1674cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) 1675cb5caa98Sdjl (me, "%s: name service lookup failed (status=%d, errno=%d)\n", 1676cb5caa98Sdjl whoami, status, errnum); 1677cb5caa98Sdjl 1678cb5caa98Sdjl return (SERVERERROR); 1679cb5caa98Sdjl } 1680cb5caa98Sdjl } else if (next_action == _NSC_USECACHED) { 1681cb5caa98Sdjl /* 1682cb5caa98Sdjl * found entry in cache 1683cb5caa98Sdjl */ 1684cb5caa98Sdjl if (UPDATEBIT & flag) { 1685cb5caa98Sdjl NSC_LOOKUP_RETURN(SUCCESS, DEBUG, 1686cb5caa98Sdjl "%s: no need to update\n"); 1687cb5caa98Sdjl } 1688cb5caa98Sdjl 1689cb5caa98Sdjl if (NSCD_GET_STATUS((nss_pheader_t *)this_entry->buffer) == 1690cb5caa98Sdjl NSS_SUCCESS) { 1691cb5caa98Sdjl /* positive hit */ 1692cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1693cb5caa98Sdjl ctx->stats.pos_hits++; 1694cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1695cb5caa98Sdjl 1696cb5caa98Sdjl /* update response buffer */ 1697cb5caa98Sdjl if (copy_result(largs->buffer, 1698cb5caa98Sdjl this_entry->buffer) != NSS_SUCCESS) { 1699cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1700cb5caa98Sdjl "%s: response buffer insufficient\n"); 1701cb5caa98Sdjl } 1702cb5caa98Sdjl 1703cb5caa98Sdjl NSC_LOOKUP_RETURN(SUCCESS, DEBUG, 1704cb5caa98Sdjl "%s: positive entry in cache\n"); 1705cb5caa98Sdjl } else { 1706cb5caa98Sdjl /* negative hit */ 1707cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 1708cb5caa98Sdjl ctx->stats.neg_hits++; 1709cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 1710cb5caa98Sdjl 1711cb5caa98Sdjl NSCD_SET_STATUS((nss_pheader_t *)largs->buffer, 1712cb5caa98Sdjl NSCD_GET_STATUS(this_entry->buffer), 1713cb5caa98Sdjl NSCD_GET_ERRNO(this_entry->buffer)); 1714cb5caa98Sdjl NSCD_SET_HERRNO((nss_pheader_t *)largs->buffer, 1715cb5caa98Sdjl NSCD_GET_HERRNO(this_entry->buffer)); 1716cb5caa98Sdjl 1717cb5caa98Sdjl NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, 1718cb5caa98Sdjl "%s: negative entry in cache\n"); 1719cb5caa98Sdjl } 1720cb5caa98Sdjl } 1721cb5caa98Sdjl 1722cb5caa98Sdjl NSC_LOOKUP_RETURN(SERVERERROR, ERROR, 1723cb5caa98Sdjl "%s: cache backend failure\n"); 1724cb5caa98Sdjl } 1725cb5caa98Sdjl 1726cb5caa98Sdjl /* 1727cb5caa98Sdjl * NSCD cache backend lookup function 1728cb5caa98Sdjl */ 1729cb5caa98Sdjl /*ARGSUSED*/ 1730cb5caa98Sdjl void 1731cb5caa98Sdjl nsc_lookup(nsc_lookup_args_t *largs, int flag) { 1732cb5caa98Sdjl 1733cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)largs->buffer; 1734cb5caa98Sdjl int rc; 1735cb5caa98Sdjl 1736cb5caa98Sdjl rc = lookup_int(largs, 0); 1737cb5caa98Sdjl 1738cb5caa98Sdjl if (NSCD_GET_STATUS(phdr) == NSS_TRYLOCAL) 1739cb5caa98Sdjl return; 1740cb5caa98Sdjl 1741cb5caa98Sdjl switch (rc) { 1742cb5caa98Sdjl 1743cb5caa98Sdjl case SUCCESS: 1744cb5caa98Sdjl NSCD_RETURN_STATUS(phdr, NSS_SUCCESS, 0); 1745cb5caa98Sdjl break; 1746cb5caa98Sdjl 1747cb5caa98Sdjl case NOTFOUND: 1748cb5caa98Sdjl NSCD_RETURN_STATUS(phdr, NSS_NOTFOUND, -1); 1749cb5caa98Sdjl break; 1750cb5caa98Sdjl 1751cb5caa98Sdjl case SERVERERROR: 1752cb5caa98Sdjl /* status and errno already set in the phdr */ 1753cb5caa98Sdjl break; 1754cb5caa98Sdjl 1755cb5caa98Sdjl case NOSERVER: 1756*e37190e5Smichen NSCD_RETURN_STATUS(phdr, NSS_TRYLOCAL, -1); 1757cb5caa98Sdjl break; 1758cb5caa98Sdjl } 1759cb5caa98Sdjl } 1760cb5caa98Sdjl 1761cb5caa98Sdjl 1762cb5caa98Sdjl static nsc_ctx_t * 1763cb5caa98Sdjl init_cache_ctx(int i) { 1764cb5caa98Sdjl nsc_ctx_t *ctx; 1765cb5caa98Sdjl 1766cb5caa98Sdjl ctx = calloc(1, sizeof (nsc_ctx_t)); 1767cb5caa98Sdjl if (ctx == NULL) 1768cb5caa98Sdjl return (NULL); 1769cb5caa98Sdjl 1770cb5caa98Sdjl /* init locks and semaphores */ 1771cb5caa98Sdjl (void) mutex_init(&ctx->file_mutex, USYNC_THREAD, NULL); 1772cb5caa98Sdjl (void) rwlock_init(&ctx->cfg_rwlp, USYNC_THREAD, NULL); 1773cb5caa98Sdjl (void) mutex_init(&ctx->stats_mutex, USYNC_THREAD, NULL); 1774cb5caa98Sdjl (void) _nscd_init_cache_sema(&ctx->throttle_sema, cache_name[i]); 1775cb5caa98Sdjl cache_init_ctx[i](ctx); 1776cb5caa98Sdjl cache_ctx_p[i] = ctx; 1777cb5caa98Sdjl 1778cb5caa98Sdjl return (ctx); 1779cb5caa98Sdjl } 1780cb5caa98Sdjl 1781cb5caa98Sdjl 1782cb5caa98Sdjl static void 1783cb5caa98Sdjl revalidate(nsc_ctx_t *ctx) 1784cb5caa98Sdjl { 1785cb5caa98Sdjl for (;;) { 1786cb5caa98Sdjl int i, slp, interval, count; 1787cb5caa98Sdjl 1788cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 1789cb5caa98Sdjl slp = ctx->cfg.pos_ttl; 1790cb5caa98Sdjl count = ctx->cfg.keephot; 1791cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 1792cb5caa98Sdjl 1793cb5caa98Sdjl if (slp < 60) 1794cb5caa98Sdjl slp = 60; 1795cb5caa98Sdjl if (count != 0) { 1796cb5caa98Sdjl interval = (slp/2)/count; 1797cb5caa98Sdjl if (interval == 0) 1798cb5caa98Sdjl interval = 1; 1799cb5caa98Sdjl (void) sleep(slp*2/3); 1800cb5caa98Sdjl for (i = 0; i < ctx->db_count; i++) { 1801cb5caa98Sdjl getxy_keepalive(ctx, ctx->nsc_db[i], 1802cb5caa98Sdjl count, interval); 1803cb5caa98Sdjl } 1804cb5caa98Sdjl } else { 1805cb5caa98Sdjl (void) sleep(slp); 1806cb5caa98Sdjl } 1807cb5caa98Sdjl } 1808cb5caa98Sdjl } 1809cb5caa98Sdjl 1810cb5caa98Sdjl 1811cb5caa98Sdjl static void 1812cb5caa98Sdjl getxy_keepalive(nsc_ctx_t *ctx, nsc_db_t *nscdb, int keep, int interval) 1813cb5caa98Sdjl { 1814cb5caa98Sdjl nsc_keephot_t *table; 1815cb5caa98Sdjl nsc_entry_t *entry, *ptr; 1816cb5caa98Sdjl int i; 1817cb5caa98Sdjl nsc_lookup_args_t *largs; 1818cb5caa98Sdjl nss_pheader_t *phdr; 1819cb5caa98Sdjl int bufsiz; 1820cb5caa98Sdjl char *me = "getxy_keepalive"; 1821cb5caa98Sdjl 1822cb5caa98Sdjl /* we won't be here if keep == 0 so need to check that */ 1823cb5caa98Sdjl 1824cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1825cb5caa98Sdjl (me, "%s: keep alive\n", nscdb->name); 1826cb5caa98Sdjl 1827cb5caa98Sdjl if ((table = maken(keep)) == NULL) { 1828cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1829cb5caa98Sdjl (me, "memory allocation failure\n"); 1830cb5caa98Sdjl exit(1); 1831cb5caa98Sdjl } 1832cb5caa98Sdjl 1833cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 1834cb5caa98Sdjl entry = nscdb->qtail; 1835cb5caa98Sdjl while (entry != NULL) { 1836cb5caa98Sdjl /* leave pending calls alone */ 1837cb5caa98Sdjl if (!(entry->stats.status & ST_PENDING)) { 1838cb5caa98Sdjl /* do_revalidate */ 1839cb5caa98Sdjl (void) insertn(table, entry->stats.hits, 1840cb5caa98Sdjl entry); 1841cb5caa98Sdjl } 1842cb5caa98Sdjl entry = entry->qnext; 1843cb5caa98Sdjl } 1844cb5caa98Sdjl for (i = 1; i <= keep; i++) { 1845cb5caa98Sdjl if (table[i].ptr == NULL) 1846cb5caa98Sdjl continue; 1847cb5caa98Sdjl ptr = (nsc_entry_t *)table[i].ptr; 1848cb5caa98Sdjl phdr = (nss_pheader_t *)ptr->buffer; 1849cb5caa98Sdjl if (NSCD_GET_STATUS(phdr) == NSS_SUCCESS) 1850cb5caa98Sdjl /* 1851cb5caa98Sdjl * for positive cache, in addition to the packed 1852cb5caa98Sdjl * header size, allocate twice the size of the 1853cb5caa98Sdjl * existing result (in case the result grows 1854ad0e80f7Smichen * larger) plus 2K (for the file/compat backend to 1855ad0e80f7Smichen * process a possible large entry in the /etc files) 1856cb5caa98Sdjl */ 1857ad0e80f7Smichen bufsiz = phdr->data_off + 2 * phdr->data_len + 2048; 1858cb5caa98Sdjl else 1859cb5caa98Sdjl /* 1860cb5caa98Sdjl * for negative cache, allocate 8K buffer to 1861cb5caa98Sdjl * hold result in case the next lookup may 1862cb5caa98Sdjl * return something (in addition to the 1863cb5caa98Sdjl * packed header size) 1864cb5caa98Sdjl */ 1865cb5caa98Sdjl bufsiz = phdr->data_off + 8096; 1866cb5caa98Sdjl table[i].ptr = malloc(bufsiz); 1867cb5caa98Sdjl if (table[i].ptr == NULL) { 1868cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1869cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1870cb5caa98Sdjl (me, "memory allocation failure\n"); 1871cb5caa98Sdjl exit(1); 1872cb5caa98Sdjl } 1873cb5caa98Sdjl (void) memcpy(table[i].ptr, ptr->buffer, ptr->bufsize); 1874cb5caa98Sdjl ((nss_pheader_t *)table[i].ptr)->pbufsiz = bufsiz; 1875cb5caa98Sdjl table[i].num = bufsiz; 1876cb5caa98Sdjl } 1877cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 1878cb5caa98Sdjl 1879cb5caa98Sdjl /* launch update thread for each keep hot entry */ 1880cb5caa98Sdjl for (i = keep; i > 0; i--) { 1881cb5caa98Sdjl if (table[i].ptr == NULL) 1882cb5caa98Sdjl continue; /* unused slot in table */ 1883cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1884cb5caa98Sdjl (me, "%s: launching update\n", nscdb->name); 1885cb5caa98Sdjl largs = (nsc_lookup_args_t *)malloc(sizeof (*largs)); 1886cb5caa98Sdjl if (largs == NULL) { 1887cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1888cb5caa98Sdjl (me, "memory allocation failure\n"); 1889cb5caa98Sdjl exit(1); 1890cb5caa98Sdjl } 1891cb5caa98Sdjl largs->buffer = table[i].ptr; 1892cb5caa98Sdjl largs->bufsize = table[i].num; 1893cb5caa98Sdjl largs->ctx = ctx; 1894cb5caa98Sdjl largs->nscdb = nscdb; 1895cb5caa98Sdjl if (launch_update(largs) < 0) 1896cb5caa98Sdjl exit(1); 1897cb5caa98Sdjl (void) sleep(interval); 1898cb5caa98Sdjl } 1899cb5caa98Sdjl 1900cb5caa98Sdjl /* 1901cb5caa98Sdjl * The update thread will handle freeing of buffer and largs. 1902cb5caa98Sdjl * Free the table here. 1903cb5caa98Sdjl */ 1904cb5caa98Sdjl free(table); 1905cb5caa98Sdjl } 1906cb5caa98Sdjl 1907cb5caa98Sdjl 1908cb5caa98Sdjl static int 1909cb5caa98Sdjl launch_update(nsc_lookup_args_t *in) 1910cb5caa98Sdjl { 1911cb5caa98Sdjl char *me = "launch_update"; 1912cb5caa98Sdjl int errnum; 1913cb5caa98Sdjl 1914cb5caa98Sdjl errnum = thr_create(NULL, NULL, (void *(*)(void*))do_update, 1915cb5caa98Sdjl in, 0|THR_DETACHED, NULL); 1916cb5caa98Sdjl if (errnum != 0) { 1917cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 1918cb5caa98Sdjl (me, "%s: thread creation failure (%d)\n", 1919cb5caa98Sdjl in->nscdb->name, errnum); 1920cb5caa98Sdjl return (-1); 1921cb5caa98Sdjl } 1922cb5caa98Sdjl return (0); 1923cb5caa98Sdjl } 1924cb5caa98Sdjl 1925cb5caa98Sdjl 1926cb5caa98Sdjl static void 1927cb5caa98Sdjl do_update(nsc_lookup_args_t *in) { 1928cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)in->buffer; 1929cb5caa98Sdjl 1930cb5caa98Sdjl /* update the length of the data buffer */ 1931cb5caa98Sdjl phdr->data_len = phdr->pbufsiz - phdr->data_off; 1932cb5caa98Sdjl 1933cb5caa98Sdjl (void) lookup_int(in, UPDATEBIT); 1934cb5caa98Sdjl if (in->buffer) 1935cb5caa98Sdjl free(in->buffer); 1936cb5caa98Sdjl free(in); 1937cb5caa98Sdjl } 1938cb5caa98Sdjl 1939cb5caa98Sdjl 1940cb5caa98Sdjl /* 1941cb5caa98Sdjl * Invalidate cache 1942cb5caa98Sdjl */ 1943cb5caa98Sdjl void 1944cb5caa98Sdjl nsc_invalidate(nsc_ctx_t *ctx, char *dbname, nsc_ctx_t **ctxs) { 1945cb5caa98Sdjl int i; 1946cb5caa98Sdjl char *me = "nsc_invalidate"; 1947cb5caa98Sdjl 1948cb5caa98Sdjl if (ctx) { 1949cb5caa98Sdjl ctx_invalidate(ctx); 1950cb5caa98Sdjl return; 1951cb5caa98Sdjl } 1952cb5caa98Sdjl 1953cb5caa98Sdjl if (dbname) { 1954cb5caa98Sdjl if ((i = get_cache_idx(dbname)) == -1) { 1955cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, 1956cb5caa98Sdjl NSCD_LOG_LEVEL_WARNING) 1957cb5caa98Sdjl (me, "%s: invalid cache name\n", dbname); 1958cb5caa98Sdjl return; 1959cb5caa98Sdjl } 1960cb5caa98Sdjl if ((ctx = cache_ctx_p[i]) == NULL) { 1961cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, 1962cb5caa98Sdjl NSCD_LOG_LEVEL_WARNING) 1963cb5caa98Sdjl (me, "%s: no cache context found\n", 1964cb5caa98Sdjl dbname); 1965cb5caa98Sdjl return; 1966cb5caa98Sdjl } 1967cb5caa98Sdjl ctx_invalidate(ctx); 1968cb5caa98Sdjl return; 1969cb5caa98Sdjl } 1970cb5caa98Sdjl 1971cb5caa98Sdjl if (ctxs == NULL) 1972cb5caa98Sdjl ctxs = cache_ctx_p; 1973cb5caa98Sdjl 1974cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 1975cb5caa98Sdjl if (ctxs[i] != NULL) 1976cb5caa98Sdjl ctx_invalidate(ctxs[i]); 1977cb5caa98Sdjl } 1978cb5caa98Sdjl } 1979cb5caa98Sdjl 1980cb5caa98Sdjl 1981cb5caa98Sdjl /* 1982cb5caa98Sdjl * Invalidate cache by context 1983cb5caa98Sdjl */ 1984cb5caa98Sdjl static void 1985cb5caa98Sdjl ctx_invalidate(nsc_ctx_t *ctx) { 1986cb5caa98Sdjl int i; 1987cb5caa98Sdjl nsc_entry_t *entry; 1988cb5caa98Sdjl char *me = "ctx_invalidate"; 1989cb5caa98Sdjl 1990cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 1991cb5caa98Sdjl (me, "%s: invalidate cache\n", ctx->dbname); 1992cb5caa98Sdjl 1993cb5caa98Sdjl for (i = 0; i < ctx->db_count; i++) { 1994cb5caa98Sdjl if (ctx->nsc_db[i] == NULL) 1995cb5caa98Sdjl continue; 1996cb5caa98Sdjl (void) mutex_lock(&ctx->nsc_db[i]->db_mutex); 1997cb5caa98Sdjl entry = ctx->nsc_db[i]->qtail; 1998cb5caa98Sdjl while (entry != NULL) { 1999cb5caa98Sdjl /* leave pending calls alone */ 2000cb5caa98Sdjl if (!(entry->stats.status & ST_PENDING)) 2001cb5caa98Sdjl entry->stats.status = ST_DISCARD; 2002cb5caa98Sdjl entry = entry->qnext; 2003cb5caa98Sdjl } 2004cb5caa98Sdjl (void) mutex_unlock(&ctx->nsc_db[i]->db_mutex); 2005cb5caa98Sdjl } 2006cb5caa98Sdjl 2007cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 2008cb5caa98Sdjl ctx->stats.invalidate_count++; 2009cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 2010cb5caa98Sdjl } 2011cb5caa98Sdjl 2012cb5caa98Sdjl 2013cb5caa98Sdjl /* 2014cb5caa98Sdjl * Free nsc_entry_t 2015cb5caa98Sdjl * 2016cb5caa98Sdjl * Pre-reqs: 2017cb5caa98Sdjl * nscdb->db_mutex lock must be held before calling this function 2018cb5caa98Sdjl */ 2019cb5caa98Sdjl static void 2020cb5caa98Sdjl delete_entry(nsc_db_t *nscdb, nsc_ctx_t *ctx, nsc_entry_t *entry) { 2021cb5caa98Sdjl uint_t hash; 2022cb5caa98Sdjl 2023cb5caa98Sdjl avl_remove(&nscdb->tree, entry); 2024cb5caa98Sdjl HASH_REMOVE(nscdb, entry, hash, nscd_false); 2025cb5caa98Sdjl queue_remove(nscdb, entry); 2026cb5caa98Sdjl if (entry->buffer != NULL) { 2027cb5caa98Sdjl free(entry->buffer); 2028cb5caa98Sdjl entry->buffer = NULL; 2029cb5caa98Sdjl } 2030cb5caa98Sdjl umem_cache_free(nsc_entry_cache, entry); 2031cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 2032cb5caa98Sdjl ctx->stats.entries--; 2033cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 2034cb5caa98Sdjl } 2035cb5caa98Sdjl 2036cb5caa98Sdjl 2037cb5caa98Sdjl static nscd_rc_t 2038cb5caa98Sdjl lookup_cache(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp, 2039cb5caa98Sdjl nss_XbyY_args_t *argp, char *whoami, nsc_entry_t **entry) { 2040cb5caa98Sdjl 2041cb5caa98Sdjl nsc_db_t *nscdb; 2042cb5caa98Sdjl nsc_ctx_t *ctx; 2043cb5caa98Sdjl uint_t hash; 2044cb5caa98Sdjl avl_index_t pos; 2045cb5caa98Sdjl ulong_t nentries; 2046cb5caa98Sdjl nsc_entry_t find_entry, *node; 2047cb5caa98Sdjl char *me = "lookup_cache"; 2048cb5caa98Sdjl 2049cb5caa98Sdjl ctx = largs->ctx; 2050cb5caa98Sdjl nscdb = largs->nscdb; 2051cb5caa98Sdjl 2052cb5caa98Sdjl /* set the search key */ 2053cb5caa98Sdjl find_entry.key = argp->key; /* struct copy (not deep) */ 2054cb5caa98Sdjl 2055cb5caa98Sdjl /* lookup the hash table ==> O(1) */ 2056cb5caa98Sdjl if (nscdb->htable) { 2057cb5caa98Sdjl *entry = hash_find(nscdb, &find_entry, &hash, nscd_true); 2058cb5caa98Sdjl if (*entry != NULL) { 2059cb5caa98Sdjl (void) queue_adjust(nscdb, *entry); 2060cb5caa98Sdjl return (NSCD_SUCCESS); 2061cb5caa98Sdjl } 2062cb5caa98Sdjl } 2063cb5caa98Sdjl 2064cb5caa98Sdjl /* if not found, lookup the AVL tree ==> O(log n) */ 2065cb5caa98Sdjl *entry = (nsc_entry_t *)avl_find(&nscdb->tree, &find_entry, &pos); 2066cb5caa98Sdjl if (*entry != NULL) { 2067cb5caa98Sdjl (void) queue_adjust(nscdb, *entry); 2068cb5caa98Sdjl /* move it to the hash table */ 2069cb5caa98Sdjl if (nscdb->htable) { 2070cb5caa98Sdjl if (nscdb->htable[hash] == NULL || 2071cb5caa98Sdjl (*entry)->stats.hits >= 2072cb5caa98Sdjl nscdb->htable[hash]->stats.hits) { 2073cb5caa98Sdjl nscdb->htable[hash] = *entry; 2074cb5caa98Sdjl } 2075cb5caa98Sdjl } 2076cb5caa98Sdjl return (NSCD_SUCCESS); 2077cb5caa98Sdjl } 2078cb5caa98Sdjl 2079cb5caa98Sdjl /* entry not found in the cache */ 2080cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2081cb5caa98Sdjl (me, "%s: cache miss\n", whoami); 2082cb5caa98Sdjl 2083cb5caa98Sdjl if (cfgp->avoid_ns == nscd_true) { 2084cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, 2085cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 2086cb5caa98Sdjl (me, "%s: avoid name service\n", whoami); 2087cb5caa98Sdjl return (NSCD_DB_ENTRY_NOT_FOUND); 2088cb5caa98Sdjl } 2089cb5caa98Sdjl 2090cb5caa98Sdjl /* allocate memory for new entry (stub) */ 2091cb5caa98Sdjl *entry = (nsc_entry_t *)umem_cache_alloc(nsc_entry_cache, 2092cb5caa98Sdjl UMEM_DEFAULT); 2093cb5caa98Sdjl if (*entry == NULL) { 2094cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, 2095cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 2096cb5caa98Sdjl (me, "%s: memory allocation failure\n", whoami); 2097cb5caa98Sdjl return (NSCD_NO_MEMORY); 2098cb5caa98Sdjl } 2099cb5caa98Sdjl (void) memset(*entry, 0, sizeof (**entry)); 2100cb5caa98Sdjl 2101cb5caa98Sdjl /* 2102cb5caa98Sdjl * Note that the actual data for the key is stored within 2103cb5caa98Sdjl * the largs->buffer (input buffer to nsc_lookup). 2104cb5caa98Sdjl * find_entry.key only contains pointers to this data. 2105cb5caa98Sdjl * 2106cb5caa98Sdjl * If largs->buffer will be re-allocated by nss_psearch 2107cb5caa98Sdjl * then (*entry)->key will have dangling pointers. 2108cb5caa98Sdjl * In such case, the following assignment needs to be 2109cb5caa98Sdjl * replaced by code that duplicates the key. 2110cb5caa98Sdjl */ 2111cb5caa98Sdjl (*entry)->key = find_entry.key; 2112cb5caa98Sdjl 2113cb5caa98Sdjl /* 2114cb5caa98Sdjl * Add the entry to the cache. 2115cb5caa98Sdjl */ 2116cb5caa98Sdjl avl_insert(&nscdb->tree, *entry, pos); /* O(log n) */ 2117cb5caa98Sdjl (void) queue_adjust(nscdb, *entry); /* constant */ 2118cb5caa98Sdjl if (nscdb->htable) /* constant */ 2119cb5caa98Sdjl nscdb->htable[hash] = *entry; 2120cb5caa98Sdjl (*entry)->stats.status = ST_NEW_ENTRY; 2121cb5caa98Sdjl 2122cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 2123cb5caa98Sdjl nentries = ++(ctx->stats.entries); 2124cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 2125cb5caa98Sdjl 2126cb5caa98Sdjl /* Have we exceeded max entries ? */ 2127cb5caa98Sdjl if (cfgp->maxentries > 0 && nentries > cfgp->maxentries) { 2128cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2129cb5caa98Sdjl (me, "%s: maximum entries exceeded -- " 2130cb5caa98Sdjl "deleting least recently used entry\n", 2131cb5caa98Sdjl whoami); 2132cb5caa98Sdjl 2133cb5caa98Sdjl node = nscdb->qhead; 2134cb5caa98Sdjl while (node != NULL && node != *entry) { 2135cb5caa98Sdjl if (node->stats.status == ST_DISCARD || 2136cb5caa98Sdjl !(node->stats.status & ST_PENDING)) { 2137cb5caa98Sdjl delete_entry(nscdb, ctx, node); 2138cb5caa98Sdjl break; 2139cb5caa98Sdjl } 2140cb5caa98Sdjl node = node->qprev; 2141cb5caa98Sdjl } 2142cb5caa98Sdjl 2143cb5caa98Sdjl /* 2144cb5caa98Sdjl * It's okay if we were not able to find one to delete. 2145cb5caa98Sdjl * The reaper (when invoked) will return the cache to a 2146cb5caa98Sdjl * safe level. 2147cb5caa98Sdjl */ 2148cb5caa98Sdjl } 2149cb5caa98Sdjl 2150cb5caa98Sdjl return (NSCD_SUCCESS); 2151cb5caa98Sdjl } 2152cb5caa98Sdjl 2153cb5caa98Sdjl static void 2154cb5caa98Sdjl reaper(nsc_ctx_t *ctx) { 2155cb5caa98Sdjl uint_t ttl, extra_sleep, total_sleep, intervals; 2156cb5caa98Sdjl uint_t nodes_per_interval, seconds_per_interval; 2157cb5caa98Sdjl ulong_t nsc_entries; 2158cb5caa98Sdjl char *me = "reaper"; 2159cb5caa98Sdjl 2160cb5caa98Sdjl for (;;) { 2161cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 2162cb5caa98Sdjl nsc_entries = ctx->stats.entries; 2163cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 2164cb5caa98Sdjl 2165cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 2166cb5caa98Sdjl ttl = ctx->cfg.pos_ttl; 2167cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 2168cb5caa98Sdjl 2169cb5caa98Sdjl if (nsc_entries == 0) { 2170cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2171cb5caa98Sdjl (me, "%s: nothing to reap\n", ctx->dbname); 2172cb5caa98Sdjl 2173cb5caa98Sdjl /* sleep for atleast 60 seconds */ 2174cb5caa98Sdjl if (ttl < 60) 2175cb5caa98Sdjl ttl = 60; 2176cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2177cb5caa98Sdjl (me, "%s: sleep %d\n", ctx->dbname, ttl); 2178cb5caa98Sdjl (void) sleep(ttl); 2179cb5caa98Sdjl continue; 2180cb5caa98Sdjl } 2181cb5caa98Sdjl 2182cb5caa98Sdjl if (ttl < 32) ttl = 32; 2183cb5caa98Sdjl if (ttl > (1<<28)) ttl = 1<<28; 2184cb5caa98Sdjl 2185cb5caa98Sdjl /* 2186cb5caa98Sdjl * minimum nodes_per_interval = 256 or 1<<8 2187cb5caa98Sdjl * maximum nodes_per_interval = nsc_entries 2188cb5caa98Sdjl * minimum seconds_per_interval = 32 or 1<<5 2189cb5caa98Sdjl * maximum_seconds_per_interval = ttl 2190cb5caa98Sdjl */ 2191cb5caa98Sdjl if (nsc_entries <= ttl) { 2192cb5caa98Sdjl intervals = (nsc_entries >> 8) + 1; 2193cb5caa98Sdjl seconds_per_interval = ttl / intervals; 2194cb5caa98Sdjl nodes_per_interval = 256; 2195cb5caa98Sdjl } else { 2196cb5caa98Sdjl intervals = (ttl >> 5) + 1; 2197cb5caa98Sdjl seconds_per_interval = 32; 2198cb5caa98Sdjl nodes_per_interval = nsc_entries / intervals; 2199cb5caa98Sdjl if (nodes_per_interval < 256) 2200cb5caa98Sdjl nodes_per_interval = 256; 2201cb5caa98Sdjl } 2202cb5caa98Sdjl 2203cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2204cb5caa98Sdjl (me, "%s: total entries = %d, " 2205cb5caa98Sdjl "seconds per interval = %d, " 2206cb5caa98Sdjl "nodes per interval = %d\n", 2207cb5caa98Sdjl ctx->dbname, nsc_entries, seconds_per_interval, 2208cb5caa98Sdjl nodes_per_interval); 2209cb5caa98Sdjl total_sleep = reap_cache(ctx, nodes_per_interval, 2210cb5caa98Sdjl seconds_per_interval); 2211cb5caa98Sdjl extra_sleep = 1 + ttl - total_sleep; 2212cb5caa98Sdjl if (extra_sleep > 0) 2213cb5caa98Sdjl (void) sleep(extra_sleep); 2214cb5caa98Sdjl } 2215cb5caa98Sdjl } 2216cb5caa98Sdjl 2217cb5caa98Sdjl 2218cb5caa98Sdjl static uint_t 2219cb5caa98Sdjl reap_cache(nsc_ctx_t *ctx, uint_t nodes_per_interval, 2220cb5caa98Sdjl uint_t seconds_per_interval) { 2221cb5caa98Sdjl uint_t nodes_togo, total_sleep; 2222cb5caa98Sdjl time_t now; 2223cb5caa98Sdjl nsc_entry_t *node, *next_node; 2224cb5caa98Sdjl nsc_db_t *nscdb; 2225cb5caa98Sdjl uint_t primes[] = {_NSC_HTSIZE_PRIMES}; 2226cb5caa98Sdjl ulong_t count, nentries, maxentries; 2227cb5caa98Sdjl int i, slot, value, newhtsize; 2228cb5caa98Sdjl char *me = "reap_cache"; 2229cb5caa98Sdjl 2230cb5caa98Sdjl count = 0; 2231cb5caa98Sdjl total_sleep = 0; 2232cb5caa98Sdjl nodes_togo = nodes_per_interval; 2233cb5caa98Sdjl now = time(NULL); 2234cb5caa98Sdjl 2235cb5caa98Sdjl for (i = 0; i < ctx->db_count; i++) { 2236cb5caa98Sdjl nscdb = ctx->nsc_db[i]; 2237cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 2238cb5caa98Sdjl nscdb->reap_node = nscdb->qtail; 2239cb5caa98Sdjl while (nscdb->reap_node != NULL) { 2240cb5caa98Sdjl if (nodes_togo == 0) { 2241cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 2242cb5caa98Sdjl (void) sleep(seconds_per_interval); 2243cb5caa98Sdjl total_sleep += seconds_per_interval; 2244cb5caa98Sdjl nodes_togo = nodes_per_interval; 2245cb5caa98Sdjl now = time(NULL); 2246cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 2247cb5caa98Sdjl } 2248cb5caa98Sdjl /* delete ST_DISCARD and expired nodes */ 2249cb5caa98Sdjl if ((node = nscdb->reap_node) == NULL) 2250cb5caa98Sdjl break; 2251cb5caa98Sdjl if (node->stats.status == ST_DISCARD || 2252cb5caa98Sdjl (!(node->stats.status & ST_PENDING) && 2253cb5caa98Sdjl node->stats.timestamp < now)) { 2254cb5caa98Sdjl /* 2255cb5caa98Sdjl * Delete entry if its discard flag is 2256cb5caa98Sdjl * set OR if it has expired. Entries 2257cb5caa98Sdjl * with pending updates are not 2258cb5caa98Sdjl * deleted. 2259cb5caa98Sdjl * nscdb->reap_node will be adjusted 2260cb5caa98Sdjl * by delete_entry() 2261cb5caa98Sdjl */ 2262cb5caa98Sdjl delete_entry(nscdb, ctx, node); 2263cb5caa98Sdjl count++; 2264cb5caa98Sdjl } else { 2265cb5caa98Sdjl nscdb->reap_node = node->qnext; 2266cb5caa98Sdjl } 2267cb5caa98Sdjl nodes_togo--; 2268cb5caa98Sdjl } 2269cb5caa98Sdjl 2270cb5caa98Sdjl if (nscdb->htsize == 0) { 2271cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 2272cb5caa98Sdjl continue; 2273cb5caa98Sdjl } 2274cb5caa98Sdjl 2275cb5caa98Sdjl /* 2276cb5caa98Sdjl * Dynamic adjustment of hash table size. 2277cb5caa98Sdjl * 2278cb5caa98Sdjl * Hash table size is roughly 1/8th of the 2279cb5caa98Sdjl * total entries. However the size is changed 2280cb5caa98Sdjl * only when the number of entries double or 2281cb5caa98Sdjl * reduced by half 2282cb5caa98Sdjl */ 2283cb5caa98Sdjl nentries = avl_numnodes(&nscdb->tree); 2284cb5caa98Sdjl for (slot = 0, value = _NSC_INIT_HTSIZE_SLOT_VALUE; 2285cb5caa98Sdjl slot < _NSC_HTSIZE_NUM_SLOTS && nentries > value; 2286cb5caa98Sdjl value = (value << 1) + 1, slot++); 2287cb5caa98Sdjl if (nscdb->hash_type == nsc_ht_power2) 2288cb5caa98Sdjl newhtsize = _NSC_INIT_HTSIZE_POWER2 << slot; 2289cb5caa98Sdjl else 2290cb5caa98Sdjl newhtsize = primes[slot]; 2291cb5caa98Sdjl 2292cb5caa98Sdjl /* Recommended size is same as the current size. Done */ 2293cb5caa98Sdjl if (nscdb->htsize == newhtsize) { 2294cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 2295cb5caa98Sdjl continue; 2296cb5caa98Sdjl } 2297cb5caa98Sdjl 2298cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2299cb5caa98Sdjl (me, "%s: resizing hash table from %d to %d\n", 2300cb5caa98Sdjl nscdb->name, nscdb->htsize, newhtsize); 2301cb5caa98Sdjl 2302cb5caa98Sdjl /* 2303cb5caa98Sdjl * Dump old hashes because it would be time 2304cb5caa98Sdjl * consuming to rehash them. 2305cb5caa98Sdjl */ 2306cb5caa98Sdjl (void) free(nscdb->htable); 2307cb5caa98Sdjl nscdb->htable = calloc(newhtsize, sizeof (*(nscdb->htable))); 2308cb5caa98Sdjl if (nscdb->htable == NULL) { 2309cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) 2310cb5caa98Sdjl (me, 2311cb5caa98Sdjl "%s: memory allocation failure\n", 2312cb5caa98Sdjl nscdb->name); 2313cb5caa98Sdjl /* -1 to try later */ 2314cb5caa98Sdjl nscdb->htsize = -1; 2315cb5caa98Sdjl } else { 2316cb5caa98Sdjl nscdb->htsize = newhtsize; 2317cb5caa98Sdjl } 2318cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 2319cb5caa98Sdjl } 2320cb5caa98Sdjl 2321cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2322cb5caa98Sdjl (me, "%s: reaped %lu entries\n", ctx->dbname, count); 2323cb5caa98Sdjl 2324cb5caa98Sdjl /* 2325cb5caa98Sdjl * if cache is almost full then reduce it to a safe level by 2326cb5caa98Sdjl * evicting LRU entries 2327cb5caa98Sdjl */ 2328cb5caa98Sdjl 2329cb5caa98Sdjl (void) rw_rdlock(&ctx->cfg_rwlp); 2330cb5caa98Sdjl maxentries = ctx->cfg.maxentries; 2331cb5caa98Sdjl (void) rw_unlock(&ctx->cfg_rwlp); 2332cb5caa98Sdjl 2333cb5caa98Sdjl /* No limit on number of entries. Done */ 2334cb5caa98Sdjl if (maxentries == 0) 2335cb5caa98Sdjl goto out; 2336cb5caa98Sdjl 2337cb5caa98Sdjl (void) mutex_lock(&ctx->stats_mutex); 2338cb5caa98Sdjl nentries = ctx->stats.entries; 2339cb5caa98Sdjl (void) mutex_unlock(&ctx->stats_mutex); 2340cb5caa98Sdjl 2341cb5caa98Sdjl /* what is the percentage of cache used ? */ 2342cb5caa98Sdjl value = (nentries * 100) / maxentries; 2343cb5caa98Sdjl if (value < _NSC_EVICTION_START_LEVEL) 2344cb5caa98Sdjl goto out; 2345cb5caa98Sdjl 2346cb5caa98Sdjl /* 2347cb5caa98Sdjl * cache needs to be reduced to a safe level 2348cb5caa98Sdjl */ 2349cb5caa98Sdjl value -= _NSC_EVICTION_SAFE_LEVEL; 2350cb5caa98Sdjl for (i = 0, count = 0; i < ctx->db_count; i++) { 2351cb5caa98Sdjl /* 2352cb5caa98Sdjl * Reduce each subcache by 'value' percent 2353cb5caa98Sdjl */ 2354cb5caa98Sdjl nscdb = ctx->nsc_db[i]; 2355cb5caa98Sdjl (void) mutex_lock(&nscdb->db_mutex); 2356cb5caa98Sdjl nodes_togo = (value * avl_numnodes(&nscdb->tree)) / 100; 2357cb5caa98Sdjl 2358cb5caa98Sdjl /* Start from LRU entry i.e queue head */ 2359cb5caa98Sdjl next_node = nscdb->qhead; 2360cb5caa98Sdjl while (nodes_togo > 0 && next_node != NULL) { 2361cb5caa98Sdjl node = next_node; 2362cb5caa98Sdjl next_node = next_node->qprev; 2363cb5caa98Sdjl if (node->stats.status == ST_DISCARD || 2364cb5caa98Sdjl !(node->stats.status & ST_PENDING)) { 2365cb5caa98Sdjl /* Leave nodes with pending updates alone */ 2366cb5caa98Sdjl delete_entry(nscdb, ctx, node); 2367cb5caa98Sdjl count++; 2368cb5caa98Sdjl nodes_togo--; 2369cb5caa98Sdjl } 2370cb5caa98Sdjl } 2371cb5caa98Sdjl (void) mutex_unlock(&nscdb->db_mutex); 2372cb5caa98Sdjl } 2373cb5caa98Sdjl 2374cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) 2375cb5caa98Sdjl (me, "%s: evicted %lu LRU entries\n", ctx->dbname, count); 2376cb5caa98Sdjl 2377cb5caa98Sdjl out: 2378cb5caa98Sdjl return (total_sleep); 2379cb5caa98Sdjl } 2380