diff options
Diffstat (limited to 'nscd')
-rw-r--r-- | nscd/cache.c | 37 | ||||
-rw-r--r-- | nscd/connections.c | 29 | ||||
-rw-r--r-- | nscd/nscd.c | 30 | ||||
-rw-r--r-- | nscd/nscd.h | 3 |
4 files changed, 81 insertions, 18 deletions
diff --git a/nscd/cache.c b/nscd/cache.c index 787f8b46f5..be9be2aa4f 100644 --- a/nscd/cache.c +++ b/nscd/cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1998, 1999, 2003, 2004, 2005 Free Software Foundation, Inc. +/* Copyright (c) 1998, 1999, 2003-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. @@ -190,13 +190,34 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet, free the data structures since some hash table entries share the same data. */ void -prune_cache (struct database_dyn *table, time_t now) +prune_cache (struct database_dyn *table, time_t now, int fd) { size_t cnt = table->head->module; /* If this table is not actually used don't do anything. */ if (cnt == 0) - return; + { + if (fd != -1) + { + /* Reply to the INVALIDATE initiator. */ + 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; + } + else + pthread_mutex_lock (&table->prunelock); /* If we check for the modification of the underlying file we invalidate the entries also in this case. */ @@ -367,6 +388,14 @@ prune_cache (struct database_dyn *table, time_t now) } while (cnt > 0); + if (fd != -1) + { + /* Reply to the INVALIDATE initiator that the cache has been + invalidated. */ + int32_t resp = 0; + writeall (fd, &resp, sizeof (resp)); + } + if (first <= last) { struct hashentry *head = NULL; @@ -455,4 +484,6 @@ prune_cache (struct database_dyn *table, time_t now) /* Run garbage collection if any entry has been removed or replaced. */ if (any) gc (table); + + pthread_mutex_unlock (&table->prunelock); } diff --git a/nscd/connections.c b/nscd/connections.c index 8bd9a66be8..307337bffe 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -100,6 +100,7 @@ struct database_dyn dbs[lastdb] = { [pwddb] = { .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, + .prunelock = PTHREAD_MUTEX_INITIALIZER, .enabled = 0, .check_file = 1, .persistent = 0, @@ -117,6 +118,7 @@ struct database_dyn dbs[lastdb] = }, [grpdb] = { .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, + .prunelock = PTHREAD_MUTEX_INITIALIZER, .enabled = 0, .check_file = 1, .persistent = 0, @@ -134,6 +136,7 @@ struct database_dyn dbs[lastdb] = }, [hstdb] = { .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, + .prunelock = PTHREAD_MUTEX_INITIALIZER, .enabled = 0, .check_file = 1, .persistent = 0, @@ -813,9 +816,10 @@ close_sockets (void) static void -invalidate_cache (char *key) +invalidate_cache (char *key, int fd) { dbtype number; + int32_t resp; if (strcmp (key, "passwd") == 0) number = pwddb; @@ -829,10 +833,19 @@ invalidate_cache (char *key) res_init (); } else - return; + { + resp = EINVAL; + writeall (fd, &resp, sizeof (resp)); + return; + } if (dbs[number].enabled) - prune_cache (&dbs[number], LONG_MAX); + prune_cache (&dbs[number], LONG_MAX, fd); + else + { + resp = 0; + writeall (fd, &resp, sizeof (resp)); + } } @@ -1089,7 +1102,7 @@ cannot handle old request version %d; current version is %d"), else if (uid == 0) { if (req->type == INVALIDATE) - invalidate_cache (key); + invalidate_cache (key, fd); else termination_handler (0); } @@ -1435,7 +1448,7 @@ handle_request: request received (Version = %d)"), req.version); /* 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)); + prune_cache (&dbs[my_number], time (NULL), -1); if (clock_gettime (timeout_clock, &prune_ts) == -1) /* Should never happen. */ @@ -1908,14 +1921,14 @@ sighup_handler (int signum) { /* Prune the password database. */ if (dbs[pwddb].enabled) - prune_cache (&dbs[pwddb], LONG_MAX); + prune_cache (&dbs[pwddb], LONG_MAX, -1); /* Prune the group database. */ if (dbs[grpdb].enabled) - prune_cache (&dbs[grpdb], LONG_MAX); + prune_cache (&dbs[grpdb], LONG_MAX, -1); /* Prune the host database. */ if (dbs[hstdb].enabled) - prune_cache (&dbs[hstdb], LONG_MAX); + prune_cache (&dbs[hstdb], LONG_MAX, -1); } diff --git a/nscd/nscd.c b/nscd/nscd.c index 917163af78..03359f3c05 100644 --- a/nscd/nscd.c +++ b/nscd/nscd.c @@ -336,9 +336,6 @@ parse_opt (int key, char *arg, struct argp_state *state) exit (EXIT_FAILURE); request_header req; - ssize_t nbytes; - struct iovec iov[2]; - if (strcmp (arg, "passwd") == 0) req.key_len = sizeof "passwd"; else if (strcmp (arg, "group") == 0) @@ -351,17 +348,38 @@ parse_opt (int key, char *arg, struct argp_state *state) req.version = NSCD_VERSION; req.type = INVALIDATE; + struct iovec iov[2]; iov[0].iov_base = &req; iov[0].iov_len = sizeof (req); iov[1].iov_base = arg; iov[1].iov_len = req.key_len; - nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2)); + ssize_t nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2)); + + if (nbytes != iov[0].iov_len + iov[1].iov_len) + { + int err = errno; + close (sock); + error (EXIT_FAILURE, err, _("write incomplete")); + } + + /* Wait for ack. Older nscd just closed the socket when + prune_cache finished, silently ignore that. */ + int32_t resp = 0; + nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp))); + if (nbytes != 0 && nbytes != sizeof (resp)) + { + int err = errno; + close (sock); + error (EXIT_FAILURE, err, _("cannot read invalidate ACK")); + } close (sock); - exit (nbytes != iov[0].iov_len + iov[1].iov_len - ? EXIT_FAILURE : EXIT_SUCCESS); + if (resp != 0) + error (EXIT_FAILURE, resp, _("invalidation failed")); + + exit (0); } case 't': diff --git a/nscd/nscd.h b/nscd/nscd.h index 8b95630807..5c2ff3a95b 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -58,6 +58,7 @@ typedef enum struct database_dyn { pthread_rwlock_t lock; + pthread_mutex_t prunelock; int enabled; int check_file; @@ -184,7 +185,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); +extern void 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, |