From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6960 invoked by alias); 30 May 2006 16:46:00 -0000 Received: (qmail 6940 invoked by uid 22791); 30 May 2006 16:45:59 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 30 May 2006 16:45:51 +0000 Received: from sunsite.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.1/8.13.1) with ESMTP id k4UGjkuE022081; Tue, 30 May 2006 18:45:46 +0200 Received: (from jj@localhost) by sunsite.mff.cuni.cz (8.13.1/8.13.1/Submit) id k4UGjkHL022078; Tue, 30 May 2006 18:45:46 +0200 Date: Tue, 30 May 2006 16:46:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] Fix nscd -i Message-ID: <20060530164545.GC3823@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2006-05/txt/msg00023.txt.bz2 Hi! nscd -i group (etc.) doesn't currently wait till the cache is invalidated, so if whomever spawned nscd -i group shortly after that uses getgrnam etc. on the group added (resp. removed) shortly before the invalidation, the old response might still be in the cache. The following patch changes nscd -i to wait for response (it will actually work even when new nscd is executed against older (before this patch) nscd already running on the system - in that case the old nscd will invoke prune_cache and when done with it, will close the socket, which means the read of the response will return 0 and be silently ignored). 2006-05-30 Jakub Jelinek * nscd/nscd.h (prune_cache): Add fd argument to prototype. * nscd/nscd.c (parse_opt): Read response from INVALIDATE request to make sure the database has been already invalidated. * nscd/cache.c (prune_cache): Add fd argument. Write response to fd after the cache has been invalidated. Use pthread_mutex_lock rather than pthread_mutex_trylock if fd != -1. * nscd/connections.c (invalidate_cache): Add fd argument, write response to fd if not calling prune_cache, pass fd to prune_cache. (handle_request): Adjust invalidate_cache caller. (nscd_run): Pass -1 as fd to prune_cache. --- libc/nscd/nscd.h.jj 2006-05-29 16:28:07.000000000 +0200 +++ libc/nscd/nscd.h 2006-05-30 17:42:49.000000000 +0200 @@ -185,7 +185,7 @@ extern struct datahead *cache_search (re 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, --- libc/nscd/nscd.c.jj 2006-04-07 12:51:00.000000000 +0200 +++ libc/nscd/nscd.c 2006-05-30 18:32:45.000000000 +0200 @@ -332,9 +332,6 @@ parse_opt (int key, char *arg, struct ar 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) @@ -347,17 +344,38 @@ parse_opt (int key, char *arg, struct ar 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': --- libc/nscd/cache.c.jj 2006-05-29 16:28:07.000000000 +0200 +++ libc/nscd/cache.c 2006-05-30 17:40:51.000000000 +0200 @@ -190,20 +190,34 @@ cache_add (int type, const void *key, si 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. No need for the second to wait around. */ - if (pthread_mutex_trylock (&table->prunelock) != 0) - /* Te work is already being done. */ - return ; + 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. */ @@ -374,6 +388,14 @@ prune_cache (struct database_dyn *table, } 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; --- libc/nscd/connections.c.jj 2006-05-30 16:56:43.000000000 +0200 +++ libc/nscd/connections.c 2006-05-30 17:42:12.000000000 +0200 @@ -816,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; @@ -832,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)); + } } @@ -1092,7 +1102,7 @@ cannot handle old request version %d; cu else if (uid == 0) { if (req->type == INVALIDATE) - invalidate_cache (key); + invalidate_cache (key, fd); else termination_handler (0); } @@ -1438,7 +1448,7 @@ handle_request: request received (Versio /* 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. */ Jakub