diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-02-02 09:48:26 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-02-02 09:48:26 +0000 |
commit | ce28a8ab09cdd49890261d37b5b9280131d18014 (patch) | |
tree | c8ba4212f852ffa7ae3aaf87b3a316612e2c401b /nscd/nscd_helper.c | |
parent | a544f6724f8a668e4e2c4e47b5d8b87a47c67db7 (diff) | |
download | glibc-ce28a8ab09cdd49890261d37b5b9280131d18014.tar glibc-ce28a8ab09cdd49890261d37b5b9280131d18014.tar.gz glibc-ce28a8ab09cdd49890261d37b5b9280131d18014.tar.bz2 glibc-ce28a8ab09cdd49890261d37b5b9280131d18014.zip |
Updated to fedora-glibc-20070202T0923cvs/fedora-glibc-2_5_90-16
Diffstat (limited to 'nscd/nscd_helper.c')
-rw-r--r-- | nscd/nscd_helper.c | 153 |
1 files changed, 97 insertions, 56 deletions
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index 7c45981586..394b2f86e6 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1998-2002,2003,2004,2005,2006 Free Software Foundation, Inc. +/* Copyright (C) 1998-2002,2003,2004,2005,2006,2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. @@ -21,6 +22,7 @@ #include <errno.h> #include <fcntl.h> #include <stdbool.h> +#include <string.h> #include <time.h> #include <unistd.h> #include <sys/mman.h> @@ -95,16 +97,20 @@ __readvall (int fd, const struct iovec *iov, int iovcnt) static int -open_socket (void) +open_socket (request_type type, const char *key, size_t keylen) { int sock = __socket (PF_UNIX, SOCK_STREAM, 0); if (sock < 0) return -1; + struct + { + request_header req; + char key[keylen]; + } reqdata; + /* Make socket non-blocking. */ - int fl = __fcntl (sock, F_GETFL); - if (fl != -1) - __fcntl (sock, F_SETFL, fl | O_NONBLOCK); + __fcntl (sock, F_SETFL, O_RDWR | O_NONBLOCK); struct sockaddr_un sun; sun.sun_family = AF_UNIX; @@ -113,13 +119,56 @@ open_socket (void) && errno != EINPROGRESS) goto out; - struct pollfd fds[1]; - fds[0].fd = sock; - fds[0].events = POLLOUT | POLLERR | POLLHUP; - if (__poll (fds, 1, 5 * 1000) > 0) - /* Success. We do not check for success of the connect call here. - If it failed, the following operations will fail. */ - return sock; + reqdata.req.version = NSCD_VERSION; + reqdata.req.type = type; + reqdata.req.key_len = keylen; + + memcpy (reqdata.key, key, keylen); + + bool first_try = true; + struct timeval tvend; + while (1) + { +#ifndef MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +#endif + ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata, + sizeof (reqdata), + MSG_NOSIGNAL)); + if (__builtin_expect (wres == (ssize_t) sizeof (reqdata), 1)) + /* We managed to send the request. */ + return sock; + + if (wres != -1 || errno != EAGAIN) + /* Something is really wrong, no chance to continue. */ + break; + + /* The daemon is busy wait for it. */ + int to; + if (first_try) + { + gettimeofday (&tvend, NULL); + tvend.tv_sec += 5; + to = 5 * 1000; + first_try = false; + } + else + { + struct timeval now; + gettimeofday (&now, NULL); + to = ((tvend.tv_sec - now.tv_sec) * 1000 + + (tvend.tv_usec - now.tv_usec) / 1000); + } + + struct pollfd fds[1]; + fds[0].fd = sock; + fds[0].events = POLLOUT | POLLERR | POLLHUP; + if (__poll (fds, 1, to) <= 0) + /* The connection timed out or broke down. */ + break; + + /* We try to write again. */ + } out: close_not_cancel_no_status (sock); @@ -179,36 +228,15 @@ get_mapping (request_type type, const char *key, int saved_errno = errno; int mapfd = -1; + char resdata[keylen]; - /* Send the request. */ - struct - { - request_header req; - char key[keylen]; - } reqdata; - - int sock = open_socket (); + /* Open a socket and send the request. */ + int sock = open_socket (type, key, keylen); if (sock < 0) goto out; - reqdata.req.version = NSCD_VERSION; - reqdata.req.type = type; - reqdata.req.key_len = keylen; - memcpy (reqdata.key, key, keylen); - -# ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL 0 -# endif - if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata, - sizeof (reqdata), - MSG_NOSIGNAL)) - != sizeof (reqdata), 0)) - /* We cannot even write the request. */ - goto out_close2; - /* Room for the data sent along with the file descriptor. We expect the key name back. */ -# define resdata reqdata.key struct iovec iov[1]; iov[0].iov_base = resdata; iov[0].iov_len = keylen; @@ -362,7 +390,10 @@ __nscd_get_map_ref (request_type type, const char *name, } -const struct datahead * +/* Don't return const struct datahead *, as eventhough the record + is normally constant, it can change arbitrarily during nscd + garbage collection. */ +struct datahead * __nscd_cache_search (request_type type, const char *key, size_t keylen, const struct mapped_database *mapped) { @@ -374,16 +405,32 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen, { struct hashentry *here = (struct hashentry *) (mapped->data + work); +#ifndef _STRING_ARCH_unaligned + /* Although during garbage collection when moving struct hashentry + records around we first copy from old to new location and then + adjust pointer from previous hashentry to it, there is no barrier + between those memory writes. It is very unlikely to hit it, + so check alignment only if a misaligned load can crash the + application. */ + if ((uintptr_t) here & (__alignof__ (*here) - 1)) + return NULL; +#endif + if (type == here->type && keylen == here->len - && here->key + here->len <= datasize + && here->key + keylen <= datasize && memcmp (key, mapped->data + here->key, keylen) == 0 && here->packet + sizeof (struct datahead) <= datasize) { /* We found the entry. Increment the appropriate counter. */ - const struct datahead *dh + struct datahead *dh = (struct datahead *) (mapped->data + here->packet); +#ifndef _STRING_ARCH_unaligned + if ((uintptr_t) dh & (__alignof__ (*dh) - 1)) + return NULL; +#endif + /* See whether we must ignore the entry or whether something is wrong because garbage collection is in progress. */ if (dh->usable && here->packet + dh->allocsize <= datasize) @@ -402,28 +449,22 @@ int __nscd_open_socket (const char *key, size_t keylen, request_type type, void *response, size_t responselen) { + /* This should never happen and it is something the nscd daemon + enforces, too. He it helps to limit the amount of stack + used. */ + if (keylen > MAXKEYLEN) + return -1; + int saved_errno = errno; - int sock = open_socket (); + int sock = open_socket (type, key, keylen); if (sock >= 0) { - request_header req; - req.version = NSCD_VERSION; - req.type = type; - req.key_len = keylen; - - struct iovec vec[2]; - vec[0].iov_base = &req; - vec[0].iov_len = sizeof (request_header); - vec[1].iov_base = (void *) key; - vec[1].iov_len = keylen; - - ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2)); - if (nbytes == (ssize_t) (sizeof (request_header) + keylen) - /* Wait for data. */ - && wait_on_socket (sock) > 0) + /* Wait for data. */ + if (wait_on_socket (sock) > 0) { - nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen)); + ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response, + responselen)); if (nbytes == (ssize_t) responselen) return sock; } |