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