- fix negative caching of non-existent keys.

- fix ldap library detection in configure.
- use CLOEXEC flag functionality if present.
- fix select(2) fd limit.
- make hash table scale to thousands of entries.
This commit is contained in:
Ian Kent 2009-01-15 03:47:47 +00:00
parent c267c68a0b
commit b04561f205
6 changed files with 2224 additions and 1 deletions

View File

@ -0,0 +1,115 @@
autofs-5.0.4 - fix ldap detection
From: Guillaume Rousse <Guillaume.Rousse@inria.fr>
The test for LDAP library wrongly use LDFLAGS to add -lldap to the gcc
call. However, when strict linker ordering is in effect, it doesn't work
correctly. As described in autoconf documentation, additional libs
should be added through LIBS variable instead.
---
aclocal.m4 | 20 ++++++++++----------
configure | 20 ++++++++++----------
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/aclocal.m4 b/aclocal.m4
index bb0ab21..ab11112 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -246,9 +246,9 @@ dnl --------------------------------------------------------------------------
AC_DEFUN([AF_CHECK_FUNC_LDAP_CREATE_PAGE_CONTROL],
[AC_MSG_CHECKING(for ldap_create_page_control in -lldap)
-# save current ldflags
-af_check_ldap_create_page_control_save_ldflags="$LDFLAGS"
-LDFLAGS="$LDFLAGS -lldap"
+# save current libs
+af_check_ldap_create_page_control_save_libs="$LIBS"
+LIBS="$LIBS -lldap"
AC_TRY_LINK(
[ #include <ldap.h> ],
@@ -267,8 +267,8 @@ if test "$af_have_ldap_create_page_control" = "yes"; then
[Define to 1 if you have the `ldap_create_page_control' function.])
fi
-# restore ldflags
-LDFLAGS="$af_check_ldap_create_page_control_save_ldflags"
+# restore libs
+LIBS="$af_check_ldap_create_page_control_save_libs"
])
dnl --------------------------------------------------------------------------
@@ -279,9 +279,9 @@ dnl --------------------------------------------------------------------------
AC_DEFUN([AF_CHECK_FUNC_LDAP_PARSE_PAGE_CONTROL],
[AC_MSG_CHECKING(for ldap_parse_page_control in -lldap)
-# save current ldflags
-af_check_ldap_parse_page_control_save_ldflags="$LDFLAGS"
-LDFLAGS="$LDFLAGS -lldap"
+# save current libs
+af_check_ldap_parse_page_control_save_libs="$LIBS"
+LIBS="$LIBS -lldap"
AC_TRY_LINK(
[ #include <ldap.h> ],
@@ -300,7 +300,7 @@ if test "$af_have_ldap_create_page_control" = "yes"; then
[Define to 1 if you have the `ldap_parse_page_control' function.])
fi
-# restore ldflags
-LDFLAGS="$af_check_ldap_parse_page_control_save_ldflags"
+# restore libs
+LIBS="$af_check_ldap_parse_page_control_save_libs"
])
diff --git a/configure b/configure
index ed17660..afa692c 100755
--- a/configure
+++ b/configure
@@ -4608,9 +4608,9 @@ _ACEOF
{ echo "$as_me:$LINENO: checking for ldap_create_page_control in -lldap" >&5
echo $ECHO_N "checking for ldap_create_page_control in -lldap... $ECHO_C" >&6; }
-# save current ldflags
-af_check_ldap_create_page_control_save_ldflags="$LDFLAGS"
-LDFLAGS="$LDFLAGS -lldap"
+# save current libs
+af_check_ldap_create_page_control_save_libs="$LIBS"
+LIBS="$LIBS -lldap"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -4672,15 +4672,15 @@ _ACEOF
fi
-# restore ldflags
-LDFLAGS="$af_check_ldap_create_page_control_save_ldflags"
+# restore libs
+LIBS="$af_check_ldap_create_page_control_save_libs"
{ echo "$as_me:$LINENO: checking for ldap_parse_page_control in -lldap" >&5
echo $ECHO_N "checking for ldap_parse_page_control in -lldap... $ECHO_C" >&6; }
-# save current ldflags
-af_check_ldap_parse_page_control_save_ldflags="$LDFLAGS"
-LDFLAGS="$LDFLAGS -lldap"
+# save current libs
+af_check_ldap_parse_page_control_save_libs="$LIBS"
+LIBS="$LIBS -lldap"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -4742,8 +4742,8 @@ _ACEOF
fi
-# restore ldflags
-LDFLAGS="$af_check_ldap_parse_page_control_save_ldflags"
+# restore libs
+LIBS="$af_check_ldap_parse_page_control_save_libs"
fi

View File

@ -0,0 +1,331 @@
autofs-5.0.4 - fix negative cache non-existent key
From: Ian Kent <raven@themaw.net>
autofs was not recording map entries that don't exist for negative
caching. This was causing unwanted network map lookups.
---
CHANGELOG | 1 +
daemon/lookup.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
modules/lookup_file.c | 20 ++++++++++++-------
modules/lookup_hosts.c | 21 ++++++++++++++++----
modules/lookup_ldap.c | 20 ++++++++++++-------
modules/lookup_nisplus.c | 19 ++++++++++++------
modules/lookup_program.c | 35 ++++++++++++++++++++++++++--------
modules/lookup_yp.c | 19 ++++++++++++------
8 files changed, 143 insertions(+), 40 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 88ca579..bd35b00 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@
-----------------------
- fix dumb libxml2 check
- fix nested submount expire deadlock.
+- fix negative caching for non-existent map keys.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/daemon/lookup.c b/daemon/lookup.c
index 803df4f..0cf6e3f 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -804,6 +804,45 @@ static enum nsswitch_status lookup_map_name(struct nss_source *this,
return result;
}
+static void update_negative_cache(struct autofs_point *ap, struct map_source *source, const char *name)
+{
+ struct master_mapent *entry = ap->entry;
+ struct map_source *map;
+ struct mapent *me;
+
+ /* Have we recorded the lookup fail for negative caching? */
+ me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+ if (me)
+ /*
+ * Already exists in the cache, the mount fail updates
+ * will update negative timeout status.
+ */
+ cache_unlock(me->mc);
+ else {
+ /* Notify only once after fail */
+ error(ap->logopt, "key \"%s\" not found in map.", name);
+
+ /* Doesn't exist in any source, just add it somewhere */
+ if (source)
+ map = source;
+ else
+ map = entry->maps;
+ if (map) {
+ time_t now = time(NULL);
+ int rv = CHE_FAIL;
+
+ cache_writelock(map->mc);
+ rv = cache_update(map->mc, map, name, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(map->mc, name);
+ me->status = now + ap->negative_timeout;
+ }
+ cache_unlock(map->mc);
+ }
+ }
+ return;
+}
+
int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len)
{
struct master_mapent *entry = ap->entry;
@@ -907,8 +946,13 @@ int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const c
send_map_update_request(ap);
pthread_cleanup_pop(1);
- if (result == NSS_STATUS_NOTFOUND)
- error(ap->logopt, "key \"%s\" not found in map.", name);
+ /*
+ * The last source lookup will return NSS_STATUS_NOTFOUND if the
+ * map exits and the key has not been found but the map may also
+ * not exist in which case the key is also not found.
+ */
+ if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL)
+ update_negative_cache(ap, source, name);
return !result;
}
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 807ceab..9e34b72 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -1069,14 +1069,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
if (key_len > KEY_MAX_LEN)
return NSS_STATUS_NOTFOUND;
- /* Check if we recorded a mount fail for this key */
- cache_readlock(mc);
- me = cache_lookup_distinct(mc, key);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_UNAVAIL;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Negative timeout expired for non-existent entry. */
+ if (!me->mapent)
+ cache_delete(me->mc, key);
+
+ cache_unlock(me->mc);
}
- cache_unlock(mc);
/*
* We can't check the direct mount map as if it's not in
diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
index bf24d7f..f8d4269 100644
--- a/modules/lookup_hosts.c
+++ b/modules/lookup_hosts.c
@@ -136,12 +136,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
mc = source->mc;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (!me->mapent) {
+ cache_delete(me->mc, name);
+ me = NULL;
+ }
+
+ cache_unlock(me->mc);
+ }
+
cache_readlock(mc);
me = cache_lookup_distinct(mc, name);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_NOTFOUND;
- } else if (!me) {
+ if (!me) {
cache_unlock(mc);
/*
* We haven't read the list of hosts into the
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 31c2c13..42c3235 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -2709,14 +2709,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
if (key_len > KEY_MAX_LEN)
return NSS_STATUS_NOTFOUND;
- /* Check if we recorded a mount fail for this key */
- cache_readlock(mc);
- me = cache_lookup_distinct(mc, key);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_NOTFOUND;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Negative timeout expired for non-existent entry. */
+ if (!me->mapent)
+ cache_delete(me->mc, key);
+
+ cache_unlock(me->mc);
}
- cache_unlock(mc);
/*
* We can't check the direct mount map as if it's not in
diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
index 755556d..f15465f 100644
--- a/modules/lookup_nisplus.c
+++ b/modules/lookup_nisplus.c
@@ -493,13 +493,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
if (key_len > KEY_MAX_LEN)
return NSS_STATUS_NOTFOUND;
- cache_readlock(mc);
- me = cache_lookup_distinct(mc, key);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_NOTFOUND;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Negative timeout expired for non-existent entry. */
+ if (!me->mapent)
+ cache_delete(me->mc, key);
+
+ cache_unlock(me->mc);
}
- cache_unlock(mc);
/*
* We can't check the direct mount map as if it's not in
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
index daf874d..bf32d3b 100644
--- a/modules/lookup_program.c
+++ b/modules/lookup_program.c
@@ -131,13 +131,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
mc = source->mc;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Negative timeout expired for non-existent entry. */
+ if (!me->mapent)
+ cache_delete(me->mc, name);
+
+ cache_unlock(me->mc);
+ }
+
/* Catch installed direct offset triggers */
- cache_readlock(mc);
+ cache_writelock(mc);
me = cache_lookup_distinct(mc, name);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_NOTFOUND;
- } else if (!me) {
+ if (!me) {
cache_unlock(mc);
/*
* If there's a '/' in the name and the offset is not in
@@ -149,8 +161,6 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
return NSS_STATUS_NOTFOUND;
}
} else {
- cache_unlock(mc);
-
/* Otherwise we found a valid offset so try mount it */
debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
@@ -163,19 +173,28 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
*/
if (strchr(name, '/') ||
me->age + ap->negative_timeout > time(NULL)) {
+ char *ent = NULL;
+
+ if (me->mapent) {
+ ent = alloca(strlen(me->mapent) + 1);
+ strcpy(ent, me->mapent);
+ }
+ cache_unlock(mc);
master_source_current_wait(ap->entry);
ap->entry->current = source;
ret = ctxt->parse->parse_mount(ap, name,
- name_len, me->mapent, ctxt->parse->context);
+ name_len, ent, ctxt->parse->context);
goto out_free;
} else {
if (me->multi) {
+ cache_unlock(mc);
warn(ap->logopt, MODPREFIX
"unexpected lookup for active multi-mount"
" key %s, returning fail", name);
return NSS_STATUS_UNAVAIL;
}
cache_delete(mc, name);
+ cache_unlock(mc);
}
}
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index 8b6408b..1b62f57 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -603,13 +603,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
if (key_len > KEY_MAX_LEN)
return NSS_STATUS_NOTFOUND;
- cache_readlock(mc);
- me = cache_lookup_distinct(mc, key);
- if (me && me->status >= time(NULL)) {
- cache_unlock(mc);
- return NSS_STATUS_NOTFOUND;
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Negative timeout expired for non-existent entry. */
+ if (!me->mapent)
+ cache_delete(me->mc, key);
+
+ cache_unlock(me->mc);
}
- cache_unlock(mc);
/*
* We can't check the direct mount map as if it's not in

View File

@ -0,0 +1,275 @@
autofs-5.0.4 - fix select fd limit
From: Ian Kent <raven@themaw.net>
Using a large number of direct mounts causes autofs to hang. This is
because select(2) is limited to 1024 file handles (usually). To resolve
this we need to convert calls to select(2) to use poll(2).
---
CHANGELOG | 1 +
daemon/spawn.c | 19 ++++++------
lib/rpc_subs.c | 32 ++++++++++++++------
modules/lookup_program.c | 74 +++++++++++++++++++++++++++-------------------
4 files changed, 78 insertions(+), 48 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 43f3205..0fb7db5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@
- fix nested submount expire deadlock.
- fix negative caching for non-existent map keys.
- use CLOEXEC flag.
+- fix select(2) fd limit.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/daemon/spawn.c b/daemon/spawn.c
index 4ddf46f..e02d926 100644
--- a/daemon/spawn.c
+++ b/daemon/spawn.c
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
+#include <poll.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
@@ -89,21 +90,21 @@ void reset_signals(void)
static int timed_read(int pipe, char *buf, size_t len, int time)
{
- struct timeval timeout = { 0, 0 };
- struct timeval *tout = NULL;
- fd_set wset, rset;
+ struct pollfd pfd[1];
+ int timeout = time;
int ret;
- FD_ZERO(&rset);
- FD_SET(pipe, &rset);
- wset = rset;
+ pfd[0].fd = pipe;
+ pfd[0].events = POLLIN;
if (time != -1) {
- timeout.tv_sec = time;
- tout = &timeout;
+ if (time >= (INT_MAX - 1)/1000)
+ timeout = INT_MAX - 1;
+ else
+ timeout = time * 1000;
}
- ret = select(pipe + 1, &rset, &wset, NULL, tout);
+ ret = poll(pfd, 1, timeout);
if (ret <= 0) {
if (ret == 0)
ret = -ETIMEDOUT;
diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
index 9ac3657..7b347a7 100644
--- a/lib/rpc_subs.c
+++ b/lib/rpc_subs.c
@@ -31,6 +31,7 @@
#include <sys/ioctl.h>
#include <ctype.h>
#include <pthread.h>
+#include <poll.h>
#include "mount.h"
#include "rpc_subs.h"
@@ -197,14 +198,15 @@ void rpc_destroy_udp_client(struct conn_info *info)
/*
* Perform a non-blocking connect on the socket fd.
*
- * tout contains the timeout. It will be modified to contain the time
- * remaining (i.e. time provided - time elasped).
+ * The input struct timeval always has tv_nsec set to zero,
+ * we only ever use tv_sec for timeouts.
*/
static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
{
+ struct pollfd pfd[1];
+ int timeout = tout->tv_sec;
int flags, ret;
socklen_t len;
- fd_set wset, rset;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
@@ -229,12 +231,10 @@ static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
if (ret == 0)
goto done;
- /* now wait */
- FD_ZERO(&rset);
- FD_SET(fd, &rset);
- wset = rset;
+ pfd[0].fd = fd;
+ pfd[0].events = POLLOUT;
- ret = select(fd + 1, &rset, &wset, NULL, tout);
+ ret = poll(pfd, 1, timeout);
if (ret <= 0) {
if (ret == 0)
ret = -ETIMEDOUT;
@@ -243,13 +243,27 @@ static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
goto done;
}
- if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
+ if (pfd[0].revents) {
int status;
len = sizeof(ret);
status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
if (status < 0) {
+ char buf[MAX_ERR_BUF + 1];
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+
+ /*
+ * We assume getsockopt amounts to a read on the
+ * descriptor and gives us the errno we need for
+ * the POLLERR revent case.
+ */
ret = -errno;
+
+ /* Unexpected case, log it so we know we got caught */
+ if (pfd[0].revents & POLLNVAL)
+ logerr("unexpected poll(2) error on connect:"
+ " %s", estr);
+
goto done;
}
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
index 6f4e2a3..f62d3ef 100644
--- a/modules/lookup_program.c
+++ b/modules/lookup_program.c
@@ -24,6 +24,7 @@
#include <sys/times.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <poll.h>
#define MODULE_LOOKUP
#include "automount.h"
@@ -113,14 +114,12 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
char errbuf[1024], *errp;
char ch;
int pipefd[2], epipefd[2];
+ struct pollfd pfd[2];
pid_t f;
- int files_left;
int status;
- fd_set readfds, ourfds;
enum state { st_space, st_map, st_done } state;
int quoted = 0;
int ret = 1;
- int max_fd;
int distance;
int alloci = 1;
@@ -253,30 +252,39 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
errp = errbuf;
state = st_space;
- FD_ZERO(&ourfds);
- FD_SET(pipefd[0], &ourfds);
- FD_SET(epipefd[0], &ourfds);
+ pfd[0].fd = pipefd[0];
+ pfd[0].events = POLLIN;
+ pfd[1].fd = epipefd[0];
+ pfd[1].events = POLLIN;
- max_fd = pipefd[0] > epipefd[0] ? pipefd[0] : epipefd[0];
+ while (1) {
+ int bytes;
- files_left = 2;
+ if (poll(pfd, 2, -1) < 0 && errno != EINTR)
+ break;
+
+ if (pfd[0].fd == -1 && pfd[1].fd == -1)
+ break;
- while (files_left != 0) {
- readfds = ourfds;
- if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0 && errno != EINTR)
+ if ((pfd[0].revents & (POLLIN|POLLHUP)) == POLLHUP &&
+ (pfd[1].revents & (POLLIN|POLLHUP)) == POLLHUP)
break;
/* Parse maps from stdout */
- if (FD_ISSET(pipefd[0], &readfds)) {
- if (read(pipefd[0], &ch, 1) < 1) {
- FD_CLR(pipefd[0], &ourfds);
- files_left--;
+ if (pfd[0].revents) {
+cont:
+ bytes = read(pipefd[0], &ch, 1);
+ if (bytes == 0)
+ goto next;
+ else if (bytes < 0) {
+ pfd[0].fd = -1;
state = st_done;
+ goto next;
}
if (!quoted && ch == '\\') {
quoted = 1;
- continue;
+ goto cont;
}
switch (state) {
@@ -333,26 +341,32 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
/* Eat characters till there's no more output */
break;
}
+ goto cont;
}
quoted = 0;
-
+next:
/* Deal with stderr */
- if (FD_ISSET(epipefd[0], &readfds)) {
- if (read(epipefd[0], &ch, 1) < 1) {
- FD_CLR(epipefd[0], &ourfds);
- files_left--;
- } else if (ch == '\n') {
- *errp = '\0';
- if (errbuf[0])
- logmsg(">> %s", errbuf);
- errp = errbuf;
- } else {
- if (errp >= &errbuf[1023]) {
+ if (pfd[1].revents) {
+ while (1) {
+ bytes = read(epipefd[0], &ch, 1);
+ if (bytes == 0)
+ break;
+ else if (bytes < 0) {
+ pfd[1].fd = -1;
+ break;
+ } else if (ch == '\n') {
*errp = '\0';
- logmsg(">> %s", errbuf);
+ if (errbuf[0])
+ logmsg(">> %s", errbuf);
errp = errbuf;
+ } else {
+ if (errp >= &errbuf[1023]) {
+ *errp = '\0';
+ logmsg(">> %s", errbuf);
+ errp = errbuf;
+ }
+ *(errp++) = ch;
}
- *(errp++) = ch;
}
}
}

View File

@ -0,0 +1,294 @@
autofs-5.0.4 - make hash table scale to thousands of entries
From: Valerie Aurora Henson <vaurora@redhat.com>
Originally written by Paul Wankadia <junyer@google.com>.
The autofs cache lookup performs poorly for large maps.
The additive hashing algorithm used by autofs results in a clustering
of hash values around the average hash chain size. It is biased toward
a small range of hash indexes which becomes worse as the hash table size
increases.
Simple testing shows that the "One-at-a-time" hash function (implemented
by this patch) gives a much better distribution of hash indexes as table
size increases.
The only change made to the original patch is to make the hash table size
configurable with a default somewhat larger than it is currently.
---
CHANGELOG | 2 ++
include/automount.h | 2 +-
include/defaults.h | 3 +++
lib/cache.c | 47 +++++++++++++++++++++++-----------------
lib/defaults.c | 16 +++++++++++++-
redhat/autofs.sysconfig.in | 6 +++++
samples/autofs.conf.default.in | 6 +++++
7 files changed, 60 insertions(+), 22 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 0fb7db5..912c088 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,8 @@
- fix negative caching for non-existent map keys.
- use CLOEXEC flag.
- fix select(2) fd limit.
+- make hash table scale to thousands of entries (Paul Wankadia,
+ Valerie Aurora Henson).
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/include/automount.h b/include/automount.h
index a55ddbc..fa24885 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -128,7 +128,7 @@ struct autofs_point;
#define CHE_DUPLICATE 0x0020
#define CHE_UNAVAIL 0x0040
-#define HASHSIZE 77
+#define NULL_MAP_HASHSIZE 64
#define NEGATIVE_TIMEOUT 10
#define UMOUNT_RETRIES 8
#define EXPIRE_RETRIES 3
diff --git a/include/defaults.h b/include/defaults.h
index 12534ec..9a2430f 100644
--- a/include/defaults.h
+++ b/include/defaults.h
@@ -40,6 +40,8 @@
#define DEFAULT_APPEND_OPTIONS 1
#define DEFAULT_AUTH_CONF_FILE AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
+#define DEFAULT_MAP_HASH_TABLE_SIZE 1024
+
struct ldap_schema;
struct ldap_searchdn;
@@ -62,6 +64,7 @@ void defaults_free_searchdns(struct ldap_searchdn *);
unsigned int defaults_get_append_options(void);
unsigned int defaults_get_umount_wait(void);
const char *defaults_get_auth_conf_file(void);
+unsigned int defaults_get_map_hash_table_size(void);
#endif
diff --git a/lib/cache.c b/lib/cache.c
index 4a00367..edb3192 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -190,7 +190,7 @@ struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map)
if (!mc)
return NULL;
- mc->size = HASHSIZE;
+ mc->size = defaults_get_map_hash_table_size();
mc->hash = malloc(mc->size * sizeof(struct entry *));
if (!mc->hash) {
@@ -241,7 +241,7 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
if (!mc)
return NULL;
- mc->size = HASHSIZE;
+ mc->size = NULL_MAP_HASHSIZE;
mc->hash = malloc(mc->size * sizeof(struct entry *));
if (!mc->hash) {
@@ -279,29 +279,36 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
return mc;
}
-static unsigned int hash(const char *key)
+static u_int32_t hash(const char *key, unsigned int size)
{
- unsigned long hashval;
+ u_int32_t hashval;
char *s = (char *) key;
- for (hashval = 0; *s != '\0';)
- hashval += *s++;
+ for (hashval = 0; *s != '\0';) {
+ hashval += (unsigned char) *s++;
+ hashval += (hashval << 10);
+ hashval ^= (hashval >> 6);
+ }
+
+ hashval += (hashval << 3);
+ hashval ^= (hashval >> 11);
+ hashval += (hashval << 15);
- return hashval % HASHSIZE;
+ return hashval % size;
}
-static unsigned int ino_hash(dev_t dev, ino_t ino)
+static u_int32_t ino_hash(dev_t dev, ino_t ino, unsigned int size)
{
- unsigned long hashval;
+ u_int32_t hashval;
hashval = dev + ino;
- return hashval % HASHSIZE;
+ return hashval % size;
}
int cache_set_ino_index(struct mapent_cache *mc, const char *key, dev_t dev, ino_t ino)
{
- unsigned int ino_index = ino_hash(dev, ino);
+ u_int32_t ino_index = ino_hash(dev, ino, mc->size);
struct mapent *me;
me = cache_lookup_distinct(mc, key);
@@ -323,10 +330,10 @@ struct mapent *cache_lookup_ino(struct mapent_cache *mc, dev_t dev, ino_t ino)
{
struct mapent *me = NULL;
struct list_head *head, *p;
- unsigned int ino_index;
+ u_int32_t ino_index;
ino_index_lock(mc);
- ino_index = ino_hash(dev, ino);
+ ino_index = ino_hash(dev, ino, mc->size);
head = &mc->ino_index[ino_index];
list_for_each(p, head) {
@@ -369,7 +376,7 @@ struct mapent *cache_lookup_first(struct mapent_cache *mc)
struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
{
struct mapent *this;
- unsigned long hashval;
+ u_int32_t hashval;
unsigned int i;
if (!me)
@@ -385,7 +392,7 @@ struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
return this;
}
- hashval = hash(me->key) + 1;
+ hashval = hash(me->key, mc->size) + 1;
if (hashval < mc->size) {
for (i = (unsigned int) hashval; i < mc->size; i++) {
this = mc->hash[i];
@@ -433,7 +440,7 @@ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key)
if (!key)
return NULL;
- for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
+ for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
if (strcmp(key, me->key) == 0)
goto done;
}
@@ -446,7 +453,7 @@ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key)
goto done;
}
- for (me = mc->hash[hash("*")]; me != NULL; me = me->next)
+ for (me = mc->hash[hash("*", mc->size)]; me != NULL; me = me->next)
if (strcmp("*", me->key) == 0)
goto done;
}
@@ -462,7 +469,7 @@ struct mapent *cache_lookup_distinct(struct mapent_cache *mc, const char *key)
if (!key)
return NULL;
- for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
+ for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
if (strcmp(key, me->key) == 0)
return me;
}
@@ -530,7 +537,7 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
{
struct mapent *me, *existing = NULL;
char *pkey, *pent;
- unsigned int hashval = hash(key);
+ u_int32_t hashval = hash(key, mc->size);
int status;
me = (struct mapent *) malloc(sizeof(struct mapent));
@@ -750,7 +757,7 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key
int cache_delete(struct mapent_cache *mc, const char *key)
{
struct mapent *me = NULL, *pred;
- unsigned int hashval = hash(key);
+ u_int32_t hashval = hash(key, mc->size);
int status, ret = CHE_OK;
char *this;
diff --git a/lib/defaults.c b/lib/defaults.c
index ff653e3..0d39716 100644
--- a/lib/defaults.c
+++ b/lib/defaults.c
@@ -49,6 +49,8 @@
#define ENV_UMOUNT_WAIT "UMOUNT_WAIT"
#define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE"
+#define ENV_MAP_HASH_TABLE_SIZE "MAP_HASH_TABLE_SIZE"
+
static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
@@ -323,7 +325,8 @@ unsigned int defaults_read_config(unsigned int to_syslog)
check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) ||
check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) ||
check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) ||
- check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog))
+ check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog) ||
+ check_set_config_value(key, ENV_MAP_HASH_TABLE_SIZE, value, to_syslog))
;
}
@@ -672,3 +675,14 @@ const char *defaults_get_auth_conf_file(void)
return (const char *) cf;
}
+unsigned int defaults_get_map_hash_table_size(void)
+{
+ long size;
+
+ size = get_env_number(ENV_MAP_HASH_TABLE_SIZE);
+ if (size < 0)
+ size = DEFAULT_MAP_HASH_TABLE_SIZE;
+
+ return (unsigned int) size;
+}
+
diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
index 8256888..fe36f45 100644
--- a/redhat/autofs.sysconfig.in
+++ b/redhat/autofs.sysconfig.in
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
#
#AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
#
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
+# Should be a power of 2 with a ratio roughly
+# between 1:10 and 1:20 for each map.
+#
+#MAP_HASH_TABLE_SIZE=1024
+#
# General global options
#
# If the kernel supports using the autofs miscellanous device
diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
index 844a6f3..4496738 100644
--- a/samples/autofs.conf.default.in
+++ b/samples/autofs.conf.default.in
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
#
#AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
#
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
+# Should be a power of 2 with a ratio roughly
+# between 1:10 and 1:20 for each map.
+#
+#MAP_HASH_TABLE_SIZE=1024
+#
# General global options
#
# If the kernel supports using the autofs miscellanous device

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
Summary: A tool for automatically mounting and unmounting filesystems
Name: autofs
Version: 5.0.4
Release: 4
Release: 5
Epoch: 1
License: GPLv2+
Group: System Environment/Daemons
@ -12,6 +12,11 @@ URL: http://wiki.autofs.net/
Source: ftp://ftp.kernel.org/pub/linux/daemons/autofs/v5/autofs-%{version}.tar.bz2
Patch1: autofs-5.0.4-fix-dumb-libxml2-check.patch
Patch2: autofs-5.0.4-expire-specific-submount-only.patch
Patch3: autofs-5.0.4-fix-negative-cache-non-existent-key.patch
Patch4: autofs-5.0.4-fix-ldap-detection.patch
Patch5: autofs-5.0.4-use-CLOEXEC-flag.patch
Patch6: autofs-5.0.4-fix-select-fd-limit.patch
Patch7: autofs-5.0.4-make-hash-table-scale-to-thousands-of-entries.patch
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs
Requires: kernel >= 2.6.17
@ -55,6 +60,11 @@ inkludera nätfilsystem, CD-ROM, floppydiskar, och så vidare.
echo %{version}-%{release} > .version
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%build
#CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir}
@ -107,6 +117,13 @@ fi
%{_libdir}/autofs/
%changelog
* Thu Jan 15 2009 Ian Kent <kent@redhat.com> - 5.0.4-5
- fix negative caching of non-existent keys.
- fix ldap library detection in configure.
- use CLOEXEC flag functionality if present.
- fix select(2) fd limit.
- make hash table scale to thousands of entries.
* Wed Dec 3 2008 Ian Kent <kent@redhat.com> - 5.0.4-4
- fix nested submount expire deadlock.