autofs-5.0.8 - dont clobber mapent for negative cache From: Ian Kent When negative caching a map entry on mount fail don't save the mapent and restore it when the negative cache timeout expires. Deleting the mapent, as is done now, can be expensive especially when it causes a file read for a large file map. --- CHANGELOG | 1 + daemon/lookup.c | 6 +++ include/automount.h | 9 +++++ lib/cache.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- modules/lookup_file.c | 6 ++- modules/lookup_hosts.c | 10 ++++- modules/lookup_ldap.c | 6 ++- modules/lookup_nisplus.c | 10 ++++- modules/lookup_program.c | 10 ++++- modules/lookup_sss.c | 6 ++- modules/lookup_yp.c | 6 ++- 11 files changed, 136 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d419737..d966260 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ - pass map_source as function paramter where possible. - check for bind onto self in mount_bind.c. - fix symlink expire. +- dont clobber mapent for negative cache. 17/10/2013 autofs-5.0.8 ======================= diff --git a/daemon/lookup.c b/daemon/lookup.c index fb6370c..d7d6403 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -852,7 +852,11 @@ static void update_negative_cache(struct autofs_point *ap, struct map_source *so int rv = CHE_FAIL; cache_writelock(map->mc); - rv = cache_update(map->mc, map, name, NULL, now); + me = cache_lookup_distinct(map->mc, name); + if (me) + rv = cache_push_mapent(me, NULL); + else + 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; diff --git a/include/automount.h b/include/automount.h index 396391c..94baab8 100644 --- a/include/automount.h +++ b/include/automount.h @@ -146,6 +146,12 @@ struct mapent_cache { struct mapent **hash; }; +struct stack { + char *mapent; + time_t age; + struct stack *next; +}; + struct mapent { struct mapent *next; struct list_head ino_index; @@ -159,6 +165,7 @@ struct mapent { struct mapent *parent; char *key; char *mapent; + struct stack *stack; time_t age; /* Time of last mount fail */ time_t status; @@ -175,6 +182,8 @@ void cache_readlock(struct mapent_cache *mc); void cache_writelock(struct mapent_cache *mc); int cache_try_writelock(struct mapent_cache *mc); void cache_unlock(struct mapent_cache *mc); +int cache_push_mapent(struct mapent *me, char *mapent); +int cache_pop_mapent(struct mapent *me); struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map); struct mapent_cache *cache_init_null_cache(struct master *master); int cache_set_ino_index(struct mapent_cache *mc, const char *key, dev_t dev, ino_t ino); diff --git a/lib/cache.c b/lib/cache.c index be4917b..f2efcd3 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -177,6 +177,69 @@ static inline void ino_index_unlock(struct mapent_cache *mc) return; } +/* Save the cache entry mapent field onto a stack and set a new mapent */ +int cache_push_mapent(struct mapent *me, char *mapent) +{ + struct stack *s; + char *new; + + if (!me->mapent) + return CHE_FAIL; + + if (!mapent) + new = NULL; + else { + new = strdup(mapent); + if (!new) + return CHE_FAIL; + } + + s = malloc(sizeof(struct stack)); + if (!s) { + if (new) + free(new); + return CHE_FAIL; + } + memset(s, 0, sizeof(*s)); + + s->mapent = me->mapent; + s->age = me->age; + me->mapent = mapent; + + if (me->stack) + s->next = me->stack; + me->stack = s; + + return CHE_OK; +} + +/* Restore cache entry mapent to a previously saved mapent, discard current */ +int cache_pop_mapent(struct mapent *me) +{ + struct stack *s = me->stack; + char *mapent; + time_t age; + + if (!s || !s->mapent) + return CHE_FAIL; + + mapent = s->mapent; + age = s->age; + me->stack = s->next; + free(s); + + if (age < me->age) { + free(mapent); + return CHE_OK; + } + + if (me->mapent) + free(me->mapent); + me->mapent = mapent; + + return CHE_OK; +} + struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map) { struct mapent_cache *mc; @@ -578,6 +641,8 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c } else me->mapent = NULL; + me->stack = NULL; + me->age = age; me->status = 0; me->mc = mc; @@ -689,7 +754,9 @@ void cache_update_negative(struct mapent_cache *mc, int rv = CHE_OK; me = cache_lookup_distinct(mc, key); - if (!me) + if (me) + rv = cache_push_mapent(me, NULL); + else rv = cache_update(mc, ms, key, NULL, now); if (rv != CHE_FAIL) { me = cache_lookup_distinct(mc, key); @@ -858,6 +925,7 @@ int cache_delete(struct mapent_cache *mc, const char *key) pred = me; me = me->next; if (strcmp(this, me->key) == 0) { + struct stack *s = me->stack; if (me->multi && !list_empty(&me->multi_list)) { ret = CHE_FAIL; goto done; @@ -872,6 +940,13 @@ int cache_delete(struct mapent_cache *mc, const char *key) free(me->key); if (me->mapent) free(me->mapent); + while (s) { + struct stack *next = s->next; + if (s->mapent) + free(s->mapent); + free(s); + s = next; + } free(me); me = pred; } @@ -882,6 +957,7 @@ int cache_delete(struct mapent_cache *mc, const char *key) goto done; if (strcmp(this, me->key) == 0) { + struct stack *s = me->stack; if (me->multi && !list_empty(&me->multi_list)) { ret = CHE_FAIL; goto done; @@ -896,6 +972,13 @@ int cache_delete(struct mapent_cache *mc, const char *key) free(me->key); if (me->mapent) free(me->mapent); + while (s) { + struct stack *next = s->next; + if (s->mapent) + free(s->mapent); + free(s); + s = next; + } free(me); } done: diff --git a/modules/lookup_file.c b/modules/lookup_file.c index 2268059..512e3ef 100644 --- a/modules/lookup_file.c +++ b/modules/lookup_file.c @@ -988,8 +988,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, key); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, key); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, key); + } cache_unlock(smc); } } diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c index 8a8a34d..60c01ad 100644 --- a/modules/lookup_hosts.c +++ b/modules/lookup_hosts.c @@ -155,7 +155,9 @@ static int do_parse_mount(struct autofs_point *ap, struct map_source *source, cache_writelock(mc); me = cache_lookup_distinct(mc, name); - if (!me) + if (me) + rv = cache_push_mapent(me, NULL); + else rv = cache_update(mc, source, name, NULL, now); if (rv != CHE_FAIL) { me = cache_lookup_distinct(mc, name); @@ -315,8 +317,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, name); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, name); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, name); + } cache_unlock(smc); } } diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index 598b077..c22d100 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -2982,8 +2982,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, key); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, key); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, key); + } cache_unlock(smc); } } diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c index 1aedb3d..42c9ccc 100644 --- a/modules/lookup_nisplus.c +++ b/modules/lookup_nisplus.c @@ -509,8 +509,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, key); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, key); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, key); + } cache_unlock(smc); } } @@ -602,7 +604,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * return NSS_STATUS_TRYAGAIN; cache_writelock(mc); me = cache_lookup_distinct(mc, key); - if (!me) + if (me) + rv = cache_push_mapent(me, NULL); + else rv = cache_update(mc, source, key, NULL, now); if (rv != CHE_FAIL) { me = cache_lookup_distinct(mc, key); diff --git a/modules/lookup_program.c b/modules/lookup_program.c index 5b87b9c..326561f 100644 --- a/modules/lookup_program.c +++ b/modules/lookup_program.c @@ -156,8 +156,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, name); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, name); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, name); + } cache_unlock(smc); } } @@ -451,7 +453,9 @@ out_free: cache_writelock(mc); me = cache_lookup_distinct(mc, name); - if (!me) + if (me) + rv = cache_push_mapent(me, NULL); + else rv = cache_update(mc, source, name, NULL, now); if (rv != CHE_FAIL) { me = cache_lookup_distinct(mc, name); diff --git a/modules/lookup_sss.c b/modules/lookup_sss.c index 4a9cfd2..528ab41 100644 --- a/modules/lookup_sss.c +++ b/modules/lookup_sss.c @@ -599,8 +599,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, key); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, key); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, key); + } cache_unlock(smc); } } diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c index 9c3aba9..ba97ccc 100644 --- a/modules/lookup_yp.c +++ b/modules/lookup_yp.c @@ -613,8 +613,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * cache_writelock(smc); sme = cache_lookup_distinct(smc, key); /* Negative timeout expired for non-existent entry. */ - if (sme && !sme->mapent) - cache_delete(smc, key); + if (sme && !sme->mapent) { + if (cache_pop_mapent(sme) == CHE_FAIL) + cache_delete(smc, key); + } cache_unlock(smc); } }