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