summaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-12-12 18:13:35 +0000
committerJakub Jelinek <jakub@redhat.com>2007-12-12 18:13:35 +0000
commit574e283890a6ca92325a06dafa76ff307a8019a2 (patch)
tree055e44e24a55fb4863e5d9cdc04e320cde52ffe9 /nscd
parenta162e5955f7e324be82d9318bbcbe869c66ffb86 (diff)
Updated to fedora-glibc-20071212T1051
Diffstat (limited to 'nscd')
-rw-r--r--nscd/Makefile4
-rw-r--r--nscd/aicache.c21
-rw-r--r--nscd/cache.c68
-rw-r--r--nscd/connections.c234
-rw-r--r--nscd/gai.c2
-rw-r--r--nscd/gethstbyad_r.c15
-rw-r--r--nscd/gethstbynm3_r.c (renamed from nscd/gethstbynm2_r.c)14
-rw-r--r--nscd/grpcache.c2
-rw-r--r--nscd/hstcache.c33
-rw-r--r--nscd/initgrcache.c4
-rw-r--r--nscd/mem.c55
-rw-r--r--nscd/nscd.c4
-rw-r--r--nscd/nscd.conf6
-rw-r--r--nscd/nscd.h21
-rw-r--r--nscd/nscd.init9
-rw-r--r--nscd/nscd_setup_thread.c3
-rw-r--r--nscd/pwdcache.c2
-rw-r--r--nscd/selinux.c8
-rw-r--r--nscd/servicescache.c2
19 files changed, 319 insertions, 188 deletions
diff --git a/nscd/Makefile b/nscd/Makefile
index ecd8c89998..f83e40049a 100644
--- a/nscd/Makefile
+++ b/nscd/Makefile
@@ -32,7 +32,7 @@ include ../Makeconfig
vpath %.c ../locale/programs
nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
- getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm2_r \
+ getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
getsrvbynm_r getsrvbypt_r servicescache \
dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
xmalloc xstrdup aicache initgrcache gai res_hconf
@@ -106,7 +106,7 @@ CFLAGS-getgrnam_r.c += $(nscd-cflags)
CFLAGS-getgrgid_r.c += $(nscd-cflags)
CFLAGS-hstcache.c += $(nscd-cflags)
CFLAGS-gethstbyad_r.c += $(nscd-cflags)
-CFLAGS-gethstbynm2_r.c += $(nscd-cflags)
+CFLAGS-gethstbynm3_r.c += $(nscd-cflags)
CFLAGS-dbg_log.c += $(nscd-cflags)
CFLAGS-nscd_conf.c += $(nscd-cflags)
CFLAGS-nscd_stat.c += $(nscd-cflags)
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 0dc892bc74..a69a7781d3 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -110,7 +110,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
size_t tmpbuf4len = 0;
char *tmpbuf4 = NULL;
char *canon = NULL;
- int32_t ttl = UINT32_MAX;
+ int32_t ttl = INT32_MAX;
ssize_t total = 0;
char *key_copy = NULL;
bool alloca_used = false;
@@ -157,20 +157,20 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
tmpbuf4 = tmpbuf6;
}
- /* Next collect IPv4 information first. */
+ /* Next collect IPv4 information. */
while (1)
{
rc4 = 0;
status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4,
tmpbuf4len, &rc4, &herrno,
- ttl == UINT32_MAX ? &ttl : NULL,
+ ttl == INT32_MAX ? &ttl : NULL,
canon == NULL ? &canon : NULL));
if (rc4 != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
}
- if (rc4 != 0 || herrno == NETDB_INTERNAL)
+ if (rc4 != 0 && herrno == NETDB_INTERNAL)
goto out;
if (status[0] == NSS_STATUS_SUCCESS
@@ -233,9 +233,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
int rc;
while (1)
{
- rc = __gethostbyaddr_r (addr, addrlen, addrfamily,
- &he_mem, tmpbuf, tmpbuflen,
- &he, &herrno);
+ rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
+ &he_mem, tmpbuf, tmpbuflen,
+ &he, &herrno, NULL);
if (rc != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
@@ -285,7 +285,8 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = true;
/* Compute the timeout time. */
- dataset->head.timeout = time (NULL) + MIN (db->postimeout, ttl);
+ dataset->head.timeout = time (NULL) + (ttl == INT32_MAX
+ ? db->postimeout : ttl);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -338,7 +339,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
= (struct dataset *) mempool_alloc (db,
total
+ req->key_len);
- if (newp != NULL)
+ if (__builtin_expect (newp != NULL, 1))
{
/* Adjust pointer into the memory block. */
key_copy = (char *) newp + (key_copy
@@ -348,6 +349,8 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
total + req->key_len);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
diff --git a/nscd/cache.c b/nscd/cache.c
index 56198f6b6e..12c4f01e40 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -36,6 +36,10 @@
#include "dbg_log.h"
+/* Wrapper functions with error checking for standard functions. */
+extern void *xcalloc (size_t n, size_t s);
+
+
/* Number of times a value is reloaded without being used. UINT_MAX
means unlimited. */
unsigned int reload_count = DEFAULT_RELOAD_LIMIT;
@@ -197,6 +201,20 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
(char *) &table->head->array[hash] - (char *) table->head
+ sizeof (ref_t), MS_ASYNC);
+ /* Perhaps the prune thread for the data is not running in a long
+ time. Wake it if necessary. */
+ time_t next_wakeup = table->wakeup_time;
+ while (next_wakeup + CACHE_PRUNE_INTERVAL > packet->timeout)
+ if (atomic_compare_and_exchange_bool_acq (&table->wakeup_time,
+ packet->timeout,
+ next_wakeup) == 0)
+ {
+ pthread_cond_signal (&table->prune_cond);
+ break;
+ }
+ else
+ next_wakeup = table->wakeup_time;
+
return 0;
}
@@ -212,7 +230,7 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
actually remove them. This is complicated by the way we have to
free the data structures since some hash table entries share the same
data. */
-void
+time_t
prune_cache (struct database_dyn *table, time_t now, int fd)
{
size_t cnt = table->head->module;
@@ -226,25 +244,14 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
int32_t resp = 0;
writeall (fd, &resp, sizeof (resp));
}
- return;
- }
- /* This function can be called from the cleanup thread but also in
- response to an invalidate command. Make sure only one thread is
- running. When not serving INVALIDATE request, no need for the
- second to wait around. */
- if (fd == -1)
- {
- if (pthread_mutex_trylock (&table->prunelock) != 0)
- /* The work is already being done. */
- return;
+ /* No need to do this again anytime soon. */
+ return 24 * 60 * 60;
}
- else
- pthread_mutex_lock (&table->prunelock);
/* If we check for the modification of the underlying file we invalidate
the entries also in this case. */
- if (table->check_file)
+ if (table->check_file && now != LONG_MAX)
{
struct stat64 st;
@@ -275,7 +282,20 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
we don't need to get any lock. It is at all timed assured that the
linked lists are set up correctly and that no second thread prunes
the cache. */
- bool mark[cnt];
+ bool *mark;
+ size_t memory_needed = cnt * sizeof (bool);
+ bool mark_use_alloca;
+ if (__builtin_expect (memory_needed <= MAX_STACK_USE, 1))
+ {
+ mark = alloca (cnt * sizeof (bool));
+ memset (mark, '\0', memory_needed);
+ mark_use_alloca = true;
+ }
+ else
+ {
+ mark = xcalloc (1, memory_needed);
+ mark_use_alloca = false;
+ }
size_t first = cnt + 1;
size_t last = 0;
char *const data = table->data;
@@ -285,6 +305,8 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
dbg_log (_("pruning %s cache; time %ld"),
dbnames[table - dbs], (long int) now);
+#define NO_TIMEOUT LONG_MAX
+ time_t next_timeout = NO_TIMEOUT;
do
{
ref_t run = table->head->array[--cnt];
@@ -363,14 +385,17 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
}
}
else
- assert (dh->usable);
+ {
+ assert (dh->usable);
+ next_timeout = MIN (next_timeout, dh->timeout);
+ }
run = runp->next;
}
}
while (cnt > 0);
- if (fd != -1)
+ if (__builtin_expect (fd != -1, 0))
{
/* Reply to the INVALIDATE initiator that the cache has been
invalidated. */
@@ -463,9 +488,14 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
}
}
+ if (__builtin_expect (! mark_use_alloca, 0))
+ free (mark);
+
/* Run garbage collection if any entry has been removed or replaced. */
if (any)
gc (table);
- pthread_mutex_unlock (&table->prunelock);
+ /* If there is no entry in the database and we therefore have no new
+ timeout value, tell the caller to wake up in 24 hours. */
+ return next_timeout == NO_TIMEOUT ? 24 * 60 * 60 : next_timeout - now;
}
diff --git a/nscd/connections.c b/nscd/connections.c
index 89a1ea4967..3d98889eba 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -69,7 +69,6 @@ static gid_t *server_groups;
# define NGROUPS 32
#endif
static int server_ngroups;
-static volatile int sighup_pending;
static pthread_attr_t attr;
@@ -105,7 +104,7 @@ struct database_dyn dbs[lastdb] =
{
[pwddb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
@@ -124,7 +123,7 @@ struct database_dyn dbs[lastdb] =
},
[grpdb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
@@ -143,7 +142,7 @@ struct database_dyn dbs[lastdb] =
},
[hstdb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
@@ -162,7 +161,7 @@ struct database_dyn dbs[lastdb] =
},
[servdb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
@@ -211,10 +210,6 @@ static struct
};
-/* Number of seconds between two cache pruning runs. */
-#define CACHE_PRUNE_INTERVAL 15
-
-
/* Initial number of threads to use. */
int nthreads = -1;
/* Maximum number of threads to use. */
@@ -496,7 +491,7 @@ nscd_init (void)
if (nthreads == -1)
/* No configuration for this value, assume a default. */
- nthreads = 2 * lastdb;
+ nthreads = 4;
for (size_t cnt = 0; cnt < lastdb; ++cnt)
if (dbs[cnt].enabled)
@@ -899,7 +894,11 @@ invalidate_cache (char *key, int fd)
}
if (dbs[number].enabled)
- prune_cache (&dbs[number], LONG_MAX, fd);
+ {
+ pthread_mutex_lock (&dbs[number].prune_lock);
+ prune_cache (&dbs[number], LONG_MAX, fd);
+ pthread_mutex_unlock (&dbs[number].prune_lock);
+ }
else
{
resp = 0;
@@ -971,9 +970,13 @@ cannot handle old request version %d; current version is %d"),
return;
}
- /* Make the SELinux check before we go on to the standard checks. */
+ /* Perform the SELinux check before we go on to the standard checks. */
if (selinux_enabled && nscd_request_avc_has_perm (fd, req->type) != 0)
- return;
+ {
+ if (debug_level > 0)
+ dbg_log (_("request not handled due to missing permission"));
+ return;
+ }
struct database_dyn *db = reqinfo[req->type].db;
@@ -1337,7 +1340,7 @@ static struct fdlist *readylist;
/* Conditional variable and mutex to signal availability of entries in
READYLIST. The condvar is initialized dynamically since we might
use a different clock depending on availability. */
-static pthread_cond_t readylist_cond;
+static pthread_cond_t readylist_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
/* The clock to use with the condvar. */
@@ -1347,32 +1350,76 @@ static clockid_t timeout_clock = CLOCK_REALTIME;
static unsigned long int nready;
-/* This is the main loop. It is replicated in different threads but the
- `poll' call makes sure only one thread handles an incoming connection. */
+/* Function for the clean-up threads. */
static void *
__attribute__ ((__noreturn__))
-nscd_run (void *p)
+nscd_run_prune (void *p)
{
const long int my_number = (long int) p;
- const int run_prune = my_number < lastdb && dbs[my_number].enabled;
+ assert (dbs[my_number].enabled);
+
+ int dont_need_update = setup_thread (&dbs[my_number]);
+
+ /* We are running. */
+ dbs[my_number].head->timestamp = time (NULL);
+
struct timespec prune_ts;
- int to = 0;
- char buf[256];
+ if (clock_gettime (timeout_clock, &prune_ts) == -1)
+ /* Should never happen. */
+ abort ();
- if (run_prune)
+ /* Compute the initial timeout time. Prevent all the timers to go
+ off at the same time by adding a db-based value. */
+ prune_ts.tv_sec += CACHE_PRUNE_INTERVAL + my_number;
+
+ pthread_mutex_lock (&dbs[my_number].prune_lock);
+ while (1)
{
- setup_thread (&dbs[my_number]);
+ /* Wait, but not forever. */
+ int e = pthread_cond_timedwait (&dbs[my_number].prune_cond,
+ &dbs[my_number].prune_lock,
+ &prune_ts);
+ assert (e == 0 || e == ETIMEDOUT);
- /* We are running. */
- dbs[my_number].head->timestamp = time (NULL);
+ time_t next_wait;
+ time_t now = time (NULL);
+ if (e == ETIMEDOUT now >= dbs[my_number].wakeup_time)
+ {
+ next_wait = prune_cache (&dbs[my_number], now, -1);
+ next_wait = MAX (next_wait, CACHE_PRUNE_INTERVAL);
+ /* If clients cannot determine for sure whether nscd is running
+ we need to wake up occasionally to update the timestamp.
+ Wait 90% of the update period. */
+#define UPDATE_MAPPING_TIMEOUT (MAPPING_TIMEOUT * 9 / 10)
+ if (__builtin_expect (! dont_need_update, 0))
+ next_wait = MIN (UPDATE_MAPPING_TIMEOUT, next_wait);
+
+ /* Make it known when we will wake up again. */
+ dbs[my_number].wakeup_time = now + next_wait;
+ }
+ else
+ /* The cache was just pruned. Do not do it again now. Just
+ use the new timeout value. */
+ next_wait = dbs[my_number].wakeup_time - now;
if (clock_gettime (timeout_clock, &prune_ts) == -1)
/* Should never happen. */
abort ();
- /* Compute timeout time. */
- prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
+ /* Compute next timeout time. */
+ prune_ts.tv_sec += next_wait;
}
+}
+
+
+/* This is the main loop. It is replicated in different threads but
+ the the use of the ready list makes sure only one thread handles an
+ incoming connection. */
+static void *
+__attribute__ ((__noreturn__))
+nscd_run_worker (void *p)
+{
+ char buf[256];
/* Initial locking. */
pthread_mutex_lock (&readylist_lock);
@@ -1383,58 +1430,7 @@ nscd_run (void *p)
while (1)
{
while (readylist == NULL)
- {
- if (run_prune)
- {
- /* Wait, but not forever. */
- to = pthread_cond_timedwait (&readylist_cond, &readylist_lock,
- &prune_ts);
-
- /* If we were woken and there is no work to be done,
- just start pruning. */
- if (readylist == NULL && to == ETIMEDOUT)
- {
- --nready;
-
- if (sighup_pending)
- goto sighup_prune;
-
- pthread_mutex_unlock (&readylist_lock);
- goto only_prune;
- }
- }
- else
- /* No need to timeout. */
- pthread_cond_wait (&readylist_cond, &readylist_lock);
- }
-
- if (sighup_pending)
- {
- --nready;
- pthread_cond_signal (&readylist_cond);
- sighup_prune:
- sighup_pending = 0;
- pthread_mutex_unlock (&readylist_lock);
-
- /* Prune the password database. */
- if (dbs[pwddb].enabled)
- prune_cache (&dbs[pwddb], LONG_MAX, -1);
-
- /* Prune the group database. */
- if (dbs[grpdb].enabled)
- prune_cache (&dbs[grpdb], LONG_MAX, -1);
-
- /* Prune the host database. */
- if (dbs[hstdb].enabled)
- prune_cache (&dbs[hstdb], LONG_MAX, -1);
-
- /* Re-locking. */
- pthread_mutex_lock (&readylist_lock);
-
- /* One more thread available. */
- ++nready;
- continue;
- }
+ pthread_cond_wait (&readylist_cond, &readylist_lock);
struct fdlist *it = readylist->next;
if (readylist->next == readylist)
@@ -1537,28 +1533,6 @@ handle_request: request received (Version = %d)"), req.version);
/* We are done. */
close (fd);
- /* Check whether we should be pruning the cache. */
- assert (run_prune || to == 0);
- if (to == ETIMEDOUT)
- {
- only_prune:
- /* The pthread_cond_timedwait() call timed out. It is time
- to clean up the cache. */
- assert (my_number < lastdb);
- prune_cache (&dbs[my_number], time (NULL), -1);
-
- if (clock_gettime (timeout_clock, &prune_ts) == -1)
- /* Should never happen. */
- abort ();
-
- /* Compute next timeout time. */
- prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
-
- /* In case the list is emtpy we do not want to run the prune
- code right away again. */
- to = 0;
- }
-
/* Re-locking. */
pthread_mutex_lock (&readylist_lock);
@@ -1601,7 +1575,7 @@ fd_ready (int fd)
/* Try to start another thread to help out. */
pthread_t th;
if (nthreads < max_nthreads
- && pthread_create (&th, &attr, nscd_run,
+ && pthread_create (&th, &attr, nscd_run_worker,
(void *) (long int) nthreads) == 0)
{
/* We got another thread. */
@@ -1861,34 +1835,57 @@ start_threads (void)
timeout_clock = CLOCK_MONOTONIC;
#endif
- pthread_cond_init (&readylist_cond, &condattr);
- pthread_condattr_destroy (&condattr);
-
-
/* Create the attribute for the threads. They are all created
detached. */
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
/* Use 1MB stacks, twice as much for 64-bit architectures. */
- pthread_attr_setstacksize (&attr, 1024 * 1024 * (sizeof (void *) / 4));
+ pthread_attr_setstacksize (&attr, NSCD_THREAD_STACKSIZE);
/* We allow less than LASTDB threads only for debugging. */
if (debug_level == 0)
nthreads = MAX (nthreads, lastdb);
- int nfailed = 0;
- for (long int i = 0; i < nthreads; ++i)
+ /* Create the threads which prune the databases. */
+ // XXX Ideally this work would be done by some of the worker threads.
+ // XXX But this is problematic since we would need to be able to wake
+ // XXX them up explicitly as well as part of the group handling the
+ // XXX ready-list. This requires an operation where we can wait on
+ // XXX two conditional variables at the same time. This operation
+ // XXX does not exist (yet).
+ for (long int i = 0; i < lastdb; ++i)
{
+ /* Initialize the conditional variable. */
+ if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0)
+ {
+ dbg_log (_("could not initialize conditional variable"));
+ exit (1);
+ }
+
pthread_t th;
- if (pthread_create (&th, &attr, nscd_run, (void *) (i - nfailed)) != 0)
- ++nfailed;
+ if (dbs[i].enabled
+ && pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0)
+ {
+ dbg_log (_("could not start clean-up thread; terminating"));
+ exit (1);
+ }
}
- if (nthreads - nfailed < lastdb)
+
+ pthread_condattr_destroy (&condattr);
+
+ for (long int i = 0; i < nthreads; ++i)
{
- /* We could not start enough threads. */
- dbg_log (_("could only start %d threads; terminating"),
- nthreads - nfailed);
- exit (1);
+ pthread_t th;
+ if (pthread_create (&th, &attr, nscd_run_worker, NULL) != 0)
+ {
+ if (i == 0)
+ {
+ dbg_log (_("could not start any worker thread; terminating"));
+ exit (1);
+ }
+
+ break;
+ }
}
/* Determine how much room for descriptors we should initially
@@ -2011,10 +2008,3 @@ finish_drop_privileges (void)
install_real_capabilities (new_caps);
#endif
}
-
-/* Handle the HUP signal which will force a dump of the cache */
-void
-sighup_handler (int signum)
-{
- sighup_pending = 1;
-}
diff --git a/nscd/gai.c b/nscd/gai.c
index f2db5299aa..7bea8c4294 100644
--- a/nscd/gai.c
+++ b/nscd/gai.c
@@ -22,6 +22,7 @@
/* This file uses the getaddrinfo code but it compiles it without NSCD
support. We just need a few symbol renames. */
#define __inet_aton inet_aton
+#define __ioctl ioctl
#define __getsockname getsockname
#define __socket socket
#define __recvmsg recvmsg
@@ -36,6 +37,7 @@
/* Support code. */
#include <check_pf.c>
+#include <check_native.c>
#ifdef HAVE_LIBIDN
# include <libidn/idn-stub.c>
#endif
diff --git a/nscd/gethstbyad_r.c b/nscd/gethstbyad_r.c
index e2e8dfe2cc..2e7a09c2bd 100644
--- a/nscd/gethstbyad_r.c
+++ b/nscd/gethstbyad_r.c
@@ -20,12 +20,25 @@
#define LOOKUP_TYPE struct hostent
-#define FUNCTION_NAME gethostbyaddr
+#define FUNCTION_NAME gethostbyaddr2
+#define FUNCTION2_NAME gethostbyaddr
#define DATABASE_NAME hosts
#define ADD_PARAMS const void *addr, socklen_t len, int type
+#define EXTRA_PARAMS , int32_t *ttlp
#define ADD_VARIABLES addr, len, type
+#define EXTRA_VARIABLES , ttlp
#define NEED_H_ERRNO 1
#define NEED__RES 1
#define NEED__RES_HCONF 1
#include "../nss/getXXbyYY_r.c"
+
+
+int
+__gethostbyaddr_r (const void *addr, socklen_t len, int type,
+ struct hostent *result_buf, char *buf, size_t buflen,
+ struct hostent **result, int *h_errnop)
+{
+ return __gethostbyaddr2_r (addr, len, type, result_buf, buf, buflen,
+ result, h_errnop, NULL);
+}
diff --git a/nscd/gethstbynm2_r.c b/nscd/gethstbynm3_r.c
index 85e95d4a63..a917f893b1 100644
--- a/nscd/gethstbynm2_r.c
+++ b/nscd/gethstbynm3_r.c
@@ -25,10 +25,13 @@
#define LOOKUP_TYPE struct hostent
-#define FUNCTION_NAME gethostbyname2
+#define FUNCTION_NAME gethostbyname3
+#define FUNCTION2_NAME gethostbyname2
#define DATABASE_NAME hosts
#define ADD_PARAMS const char *name, int af
+#define EXTRA_PARAMS , int32_t *ttlp, char **canonp
#define ADD_VARIABLES name, af
+#define EXTRA_VARIABLES , ttlp, canonp
#define NEED_H_ERRNO 1
#define NEED__RES_HCONF 1
@@ -39,3 +42,12 @@
#define __inet_aton inet_aton
#include "../nss/getXXbyYY_r.c"
+
+
+int
+__gethostbyname2_r (const char *name, int af, struct hostent *ret, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop)
+{
+ return __gethostbyname3_r (name, af, ret, buf, buflen, result, h_errnop,
+ NULL, NULL);
+}
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 9cb6105f3c..002f04fb3e 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -285,6 +285,8 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
dataset = memcpy (newp, dataset, total + n);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index 54222a3408..cc041581e1 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -80,7 +80,8 @@ static const hst_response_header notfound =
static void
cache_addhst (struct database_dyn *db, int fd, request_header *req,
const void *key, struct hostent *hst, uid_t owner,
- struct hashentry *he, struct datahead *dh, int errval)
+ struct hashentry *he, struct datahead *dh, int errval,
+ int32_t ttl)
{
ssize_t total;
ssize_t written;
@@ -131,7 +132,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = true;
/* Compute the timeout time. */
- dataset->head.timeout = t + db->negtimeout;
+ dataset->head.timeout = t + (ttl == INT32_MAX
+ ? db->negtimeout : ttl);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -247,7 +249,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = true;
/* Compute the timeout time. */
- dataset->head.timeout = t + db->postimeout;
+ dataset->head.timeout = t + (ttl == INT32_MAX ? db->postimeout : ttl);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -323,6 +325,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
dataset = memcpy (newp, dataset, total + req->key_len);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
}
/* Mark the old record as obsolete. */
@@ -423,19 +427,19 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
static int
lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
- size_t buflen, struct hostent **hst)
+ size_t buflen, struct hostent **hst, int32_t *ttlp)
{
if (type == GETHOSTBYNAME)
- return __gethostbyname2_r (key, AF_INET, resultbufp, buffer, buflen, hst,
- &h_errno);
+ return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
+ &h_errno, ttlp, NULL);
if (type == GETHOSTBYNAMEv6)
- return __gethostbyname2_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
- &h_errno);
+ return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
+ &h_errno, ttlp, NULL);
if (type == GETHOSTBYADDR)
- return __gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
- buflen, hst, &h_errno);
- return __gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
- buflen, hst, &h_errno);
+ return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
+ buflen, hst, &h_errno, ttlp);
+ return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
+ buflen, hst, &h_errno, ttlp);
}
@@ -453,6 +457,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
struct hostent *hst;
bool use_malloc = false;
int errval = 0;
+ int32_t ttl = INT32_MAX;
if (__builtin_expect (debug_level > 0, 0))
{
@@ -470,7 +475,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
}
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst) != 0
+ while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
&& h_errno == NETDB_INTERNAL
&& (errval = errno) == ERANGE)
{
@@ -504,7 +509,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
}
cache_addhst (db, fd, req, key, hst, uid, he, dh,
- h_errno == TRY_AGAIN ? errval : 0);
+ h_errno == TRY_AGAIN ? errval : 0, ttl);
if (use_malloc)
free (buffer);
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
index bb4ac37efc..157cd7860c 100644
--- a/nscd/initgrcache.c
+++ b/nscd/initgrcache.c
@@ -110,7 +110,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
bool all_tryagain = true;
bool any_success = false;
- /* This is temporary memory, we need not (ad must not) call
+ /* This is temporary memory, we need not (and must not) call
mempool_alloc. */
// XXX This really should use alloca. need to change the backends.
gid_t *groups = (gid_t *) malloc (size * sizeof (gid_t));
@@ -338,6 +338,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
dataset = memcpy (newp, dataset, total + req->key_len);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
diff --git a/nscd/mem.c b/nscd/mem.c
index d7c59244aa..048e3ddd32 100644
--- a/nscd/mem.c
+++ b/nscd/mem.c
@@ -34,6 +34,11 @@
#include "nscd.h"
+/* Wrapper functions with error checking for standard functions. */
+extern void *xmalloc (size_t n);
+extern void *xcalloc (size_t n, size_t s);
+
+
static int
sort_he (const void *p1, const void *p2)
{
@@ -117,13 +122,47 @@ gc (struct database_dyn *db)
we have to look at the memory. We use a mark and sweep algorithm
where the marks are placed in this array. */
assert (db->head->first_free % BLOCK_ALIGN == 0);
- BITMAP_T mark[(db->head->first_free / BLOCK_ALIGN + BITS - 1) / BITS];
- memset (mark, '\0', sizeof (mark));
+
+ BITMAP_T *mark;
+ bool mark_use_malloc;
+ /* In prune_cache we are also using a dynamically allocated array.
+ If the array in the caller is too large we have malloc'ed it. */
+ size_t stack_used = sizeof (bool) * db->head->module;
+ if (__builtin_expect (stack_used > MAX_STACK_USE, 0))
+ stack_used = 0;
+ size_t memory_needed = ((db->head->first_free / BLOCK_ALIGN + BITS - 1)
+ / BITS) * sizeof (BITMAP_T);
+ if (memory_needed <= MAX_STACK_USE)
+ {
+ mark = (BITMAP_T *) alloca (memory_needed);
+ mark_use_malloc = false;
+ memset (mark, '\0', memory_needed);
+ stack_used = memory_needed;
+ }
+ else
+ {
+ mark = (BITMAP_T *) xcalloc (1, memory_needed);
+ mark_use_malloc = true;
+ }
/* Create an array which can hold pointer to all the entries in hash
entries. */
- struct hashentry *he[db->head->nentries];
- struct hashentry *he_data[db->head->nentries];
+ memory_needed = 2 * db->head->nentries * sizeof (struct hashentry *);
+ struct hashentry **he;
+ struct hashentry **he_data;
+ bool he_use_malloc;
+ if (stack_used + memory_needed <= MAX_STACK_USE)
+ {
+ he = alloca (db->head->nentries * sizeof (struct hashentry *));
+ he_data = alloca (db->head->nentries * sizeof (struct hashentry *));
+ he_use_malloc = false;
+ }
+ else
+ {
+ he = xmalloc (memory_needed);
+ he_data = &he[db->head->nentries * sizeof (struct hashentry *)];
+ he_use_malloc = true;
+ }
size_t cnt = 0;
for (size_t idx = 0; idx < db->head->module; ++idx)
@@ -455,6 +494,11 @@ gc (struct database_dyn *db)
out:
pthread_mutex_unlock (&db->memlock);
pthread_rwlock_unlock (&db->lock);
+
+ if (he_use_malloc)
+ free (he);
+ if (mark_use_malloc)
+ free (mark);
}
@@ -481,7 +525,8 @@ mempool_alloc (struct database_dyn *db, size_t len)
{
/* Try to resize the database. Grow size of 1/8th. */
size_t oldtotal = (sizeof (struct database_pers_head)
- + roundup (db->head->module * sizeof (ref_t), ALIGN)
+ + roundup (db->head->module * sizeof (ref_t),
+ ALIGN)
+ db->head->data_size);
size_t new_data_size = (db->head->data_size
+ MAX (2 * len, db->head->data_size / 8));
diff --git a/nscd/nscd.c b/nscd/nscd.c
index cd4dabfdb1..e007694218 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -120,9 +120,6 @@ static struct argp argp =
options, parse_opt, NULL, doc,
};
-/* The SIGHUP handler is extern to this file */
-extern void sighup_handler(int signum);
-
/* True if only statistics are requested. */
static bool get_stats;
@@ -267,7 +264,6 @@ main (int argc, char **argv)
signal (SIGINT, termination_handler);
signal (SIGQUIT, termination_handler);
signal (SIGTERM, termination_handler);
- signal (SIGHUP, sighup_handler);
signal (SIGPIPE, SIG_IGN);
/* Cleanup files created by a previous 'bind'. */
diff --git a/nscd/nscd.conf b/nscd/nscd.conf
index b0762fbb53..5e8b3f45b8 100644
--- a/nscd/nscd.conf
+++ b/nscd/nscd.conf
@@ -31,10 +31,10 @@
# logfile /var/log/nscd.log
-# threads 6
-# max-threads 128
+# threads 4
+# max-threads 32
server-user nscd
-# stat-user nocpulse
+# stat-user somebody
debug-level 0
# reload-count 5
paranoia no
diff --git a/nscd/nscd.h b/nscd/nscd.h
index e8199b8009..cd6fe15c30 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -55,11 +55,21 @@ typedef enum
#define RESTART_INTERVAL (60 * 60)
+/* Stack size for worker threads. */
+#define NSCD_THREAD_STACKSIZE 1024 * 1024 * (sizeof (void *) / 4)
+
+/* Maximum size of stack frames we allow the thread to use. We use
+ 80% of the thread stack size. */
+#define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
+
+
/* Structure describing dynamic part of one database. */
struct database_dyn
{
pthread_rwlock_t lock;
- pthread_mutex_t prunelock;
+ pthread_cond_t prune_cond;
+ pthread_mutex_t prune_lock;
+ time_t wakeup_time;
int enabled;
int check_file;
@@ -111,6 +121,11 @@ struct database_dyn
#define DEFAULT_DATASIZE_PER_BUCKET 1024
+/* Number of seconds between two cache pruning runs if we do not have
+ better information when it is really needed. */
+#define CACHE_PRUNE_INTERVAL 15
+
+
/* Global variables. */
extern struct database_dyn dbs[lastdb];
extern const char *const dbnames[lastdb];
@@ -189,7 +204,7 @@ extern struct datahead *cache_search (request_type, void *key, size_t len,
extern int cache_add (int type, const void *key, size_t len,
struct datahead *packet, bool first,
struct database_dyn *table, uid_t owner);
-extern void prune_cache (struct database_dyn *table, time_t now, int fd);
+extern time_t prune_cache (struct database_dyn *table, time_t now, int fd);
/* pwdcache.c */
extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
@@ -258,7 +273,7 @@ extern void gc (struct database_dyn *db);
/* nscd_setup_thread.c */
-extern void setup_thread (struct database_dyn *db);
+extern int setup_thread (struct database_dyn *db);
/* Special version of TEMP_FAILURE_RETRY for functions returning error
diff --git a/nscd/nscd.init b/nscd/nscd.init
index dcf92df3da..8ab3fbf731 100644
--- a/nscd/nscd.init
+++ b/nscd/nscd.init
@@ -93,9 +93,12 @@ case "$1" in
;;
force-reload | reload)
echo -n $"Reloading $prog: "
- killproc /usr/sbin/nscd -HUP
- RETVAL=$?
- echo
+ RETVAL=0
+ /usr/sbin/nscd -i passwd || RETVAL=$?
+ /usr/sbin/nscd -i group || RETVAL=$?
+ /usr/sbin/nscd -i hosts || RETVAL=$?
+ /usr/sbin/nscd -i services || RETVAL=$?
+ echo
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
diff --git a/nscd/nscd_setup_thread.c b/nscd/nscd_setup_thread.c
index c17fbd5638..4b6671e300 100644
--- a/nscd/nscd_setup_thread.c
+++ b/nscd/nscd_setup_thread.c
@@ -20,8 +20,9 @@
#include <nscd.h>
-void
+int
setup_thread (struct database_dyn *db)
{
/* Nothing. */
+ return 0;
}
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index 51ea113476..bc1b6bab2f 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -280,6 +280,8 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
dataset = memcpy (newp, dataset, total + n);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
diff --git a/nscd/selinux.c b/nscd/selinux.c
index 6cbcbea19c..9a167ec14d 100644
--- a/nscd/selinux.c
+++ b/nscd/selinux.c
@@ -368,6 +368,14 @@ nscd_request_avc_has_perm (int fd, request_type req)
goto out;
}
+#ifndef NSCD__GETSERV
+ if (perms[req] == 0)
+ {
+ dbg_log (_("compile-time support for database policy missing"));
+ goto out;
+ }
+#endif
+
rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
out:
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
index d6bf51d29f..e122cb3f16 100644
--- a/nscd/servicescache.c
+++ b/nscd/servicescache.c
@@ -272,6 +272,8 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
dataset = memcpy (newp, dataset, total + req->key_len);
alloca_used = false;
}
+ else
+ ++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;