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