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