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. --- daemon/lookup.c | 48 +++++++++++++++++++++++++++++++++++++++++++++-- modules/lookup_file.c | 20 ++++++++++++------- modules/lookup_hosts.c | 23 ++++++++++++++++++---- modules/lookup_ldap.c | 20 ++++++++++++------- modules/lookup_nisplus.c | 19 ++++++++++++------ modules/lookup_program.c | 35 ++++++++++++++++++++++++++-------- modules/lookup_yp.c | 19 ++++++++++++------ 7 files changed, 144 insertions(+), 40 deletions(-) --- autofs-5.0.1.orig/daemon/lookup.c +++ autofs-5.0.1/daemon/lookup.c @@ -805,6 +805,45 @@ static enum nsswitch_status lookup_map_n return result; } +static void update_negative_cache(struct autofs_point *ap, struct map_source *source, 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; @@ -909,8 +948,13 @@ int lookup_nss_mount(struct autofs_point 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; } --- autofs-5.0.1.orig/modules/lookup_file.c +++ autofs-5.0.1/modules/lookup_file.c @@ -1073,14 +1073,20 @@ int lookup_mount(struct autofs_point *ap 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 --- autofs-5.0.1.orig/modules/lookup_hosts.c +++ autofs-5.0.1/modules/lookup_hosts.c @@ -130,12 +130,27 @@ int lookup_mount(struct autofs_point *ap mc = source->mc; + /* Check if we recorded a mount fail for this key anywhere */ + me = lookup_source_mapent(ap, name, LKP_DISTINCT); + if (me) { + struct mapent_cache *fmc = me->mc; + + if (me->status >= time(NULL)) { + cache_unlock(fmc); + return NSS_STATUS_NOTFOUND; + } + + if (!me->mapent) { + cache_delete(fmc, name); + me = NULL; + } + + cache_unlock(fmc); + } + 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 --- autofs-5.0.1.orig/modules/lookup_ldap.c +++ autofs-5.0.1/modules/lookup_ldap.c @@ -2502,14 +2502,20 @@ int lookup_mount(struct autofs_point *ap 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 --- autofs-5.0.1.orig/modules/lookup_nisplus.c +++ autofs-5.0.1/modules/lookup_nisplus.c @@ -493,13 +493,20 @@ int lookup_mount(struct autofs_point *ap 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 --- autofs-5.0.1.orig/modules/lookup_program.c +++ autofs-5.0.1/modules/lookup_program.c @@ -131,13 +131,25 @@ int lookup_mount(struct autofs_point *ap 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 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 */ 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); } } --- autofs-5.0.1.orig/modules/lookup_yp.c +++ autofs-5.0.1/modules/lookup_yp.c @@ -602,13 +602,20 @@ int lookup_mount(struct autofs_point *ap 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