From f5c86b60af409a1579e3371572de1ff5b7da0040 Mon Sep 17 00:00:00 2001 From: ikent Date: Thu, 29 Mar 2007 07:31:59 +0000 Subject: [PATCH] - fix directory creation for browse mounts. - fix wildcard map handling and improve nsswitch source map update. --- autofs-5.0.1-fix-browse-dir-create.patch | 52 + autofs-5.0.1-map-update-source-only.patch | 1506 +++++++++++++++++++++ autofs.spec | 10 +- 3 files changed, 1567 insertions(+), 1 deletion(-) create mode 100644 autofs-5.0.1-fix-browse-dir-create.patch create mode 100644 autofs-5.0.1-map-update-source-only.patch diff --git a/autofs-5.0.1-fix-browse-dir-create.patch b/autofs-5.0.1-fix-browse-dir-create.patch new file mode 100644 index 0000000..b893e95 --- /dev/null +++ b/autofs-5.0.1-fix-browse-dir-create.patch @@ -0,0 +1,52 @@ +diff --git a/daemon/lookup.c b/daemon/lookup.c +index aded82b..4429edb 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -423,6 +423,7 @@ int lookup_nss_read_map(struct autofs_point *ap, time_t age) + struct nss_source *this; + struct map_source *map; + enum nsswitch_status status; ++ unsigned int at_least_one = 0; + int result = 0; + + /* +@@ -493,9 +494,13 @@ int lookup_nss_read_map(struct autofs_point *ap, time_t age) + if (result == NSS_STATUS_UNKNOWN) + continue; + ++ if (result == NSS_STATUS_SUCCESS) { ++ at_least_one = 1; ++ result = NSS_STATUS_TRYAGAIN; ++ } ++ + status = check_nss_result(this, result); + if (status >= 0) { +- result = !status; + map = NULL; + break; + } +@@ -509,7 +514,10 @@ int lookup_nss_read_map(struct autofs_point *ap, time_t age) + } + pthread_cleanup_pop(1); + +- return !result; ++ if (!result || at_least_one) ++ return 1; ++ ++ return 0; + } + + int lookup_ghost(struct autofs_point *ap) +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index bc75be0..5f03b2f 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -305,7 +305,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + + mapname = alloca(strlen(ctxt->mapname) + 1); + if (!mapname) +- return 0; ++ return NSS_STATUS_UNKNOWN; + + strcpy(mapname, ctxt->mapname); + diff --git a/autofs-5.0.1-map-update-source-only.patch b/autofs-5.0.1-map-update-source-only.patch new file mode 100644 index 0000000..91441a2 --- /dev/null +++ b/autofs-5.0.1-map-update-source-only.patch @@ -0,0 +1,1506 @@ +diff --git a/daemon/direct.c b/daemon/direct.c +index 38baabd..179e74b 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -526,7 +526,7 @@ int mount_autofs_direct(struct autofs_point *ap) + return -1; + + /* TODO: check map type */ +- if (lookup_nss_read_map(ap, now)) ++ if (lookup_nss_read_map(ap, NULL, now)) + lookup_prune_cache(ap, now); + else { + error(ap->logopt, "failed to read direct map"); +@@ -1413,7 +1413,7 @@ static void *do_mount_direct(void *arg) + } + + cont: +- status = lookup_nss_mount(ap, mt->name, strlen(mt->name)); ++ status = lookup_nss_mount(ap, NULL, mt->name, strlen(mt->name)); + /* + * Direct mounts are always a single mount. If it fails there's + * nothing to undo so just complain +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 2068c16..02e7045 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -261,7 +261,7 @@ int mount_autofs_indirect(struct autofs_point *ap) + return -1; + + /* TODO: read map, determine map type is OK */ +- if (lookup_nss_read_map(ap, now)) ++ if (lookup_nss_read_map(ap, NULL, now)) + lookup_prune_cache(ap, now); + else { + error(ap->logopt, "failed to read map for %s", ap->path); +@@ -884,7 +884,7 @@ static void *do_mount_indirect(void *arg) + free(tsv); + } + cont: +- status = lookup_nss_mount(ap, mt->name, mt->len); ++ status = lookup_nss_mount(ap, NULL, mt->name, mt->len); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) { + send_ready(ap->ioctlfd, mt->wait_queue_token); +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 4429edb..acf2e98 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -261,11 +261,16 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a + if (!ap->ghost && ap->type != LKP_DIRECT) + return NSS_STATUS_SUCCESS; + ++ if (!map->stale) ++ return NSS_STATUS_SUCCESS; ++ + master_source_current_wait(ap->entry); + ap->entry->current = map; + + status = lookup->lookup_read_map(ap, age, lookup->context); + ++ map->stale = 0; ++ + /* + * For maps that don't support enumeration return success + * and do whatever we must to have autofs function with an +@@ -302,7 +307,9 @@ static int read_file_source_instance(struct autofs_point *ap, struct map_source + + instance = master_find_source_instance(map, type, format, 0, NULL); + if (!instance) { +- instance = master_add_source_instance(map, type, format, age); ++ int argc = map->argc; ++ const char **argv = map->argv; ++ instance = master_add_source_instance(map, type, format, age, argc, argv); + if (!instance) + return NSS_STATUS_UNAVAIL; + instance->recurse = map->recurse; +@@ -321,7 +328,9 @@ static int read_source_instance(struct autofs_point *ap, struct map_source *map, + + instance = master_find_source_instance(map, type, format, 0, NULL); + if (!instance) { +- instance = master_add_source_instance(map, type, format, age); ++ int argc = map->argc; ++ const char **argv = map->argv; ++ instance = master_add_source_instance(map, type, format, age, argc, argv); + if (!instance) + return NSS_STATUS_UNAVAIL; + instance->recurse = map->recurse; +@@ -343,7 +352,6 @@ static enum nsswitch_status read_map_source(struct nss_source *this, + struct autofs_point *ap, struct map_source *map, time_t age) + { + enum nsswitch_status result; +- struct map_source *instance; + struct map_source tmap; + char *path; + +@@ -363,15 +371,6 @@ static enum nsswitch_status read_map_source(struct nss_source *this, + return NSS_STATUS_NOTFOUND; + } + +- instance = master_find_source_instance(map, +- "file", map->format, map->argc, map->argv); +- if (!instance) +- instance = master_find_source_instance(map, +- "program", map->format, map->argc, map->argv); +- +- if (instance) +- return read_file_source_instance(ap, map, age); +- + this->source[4] = '\0'; + tmap.type = this->source; + tmap.format = map->format; +@@ -412,10 +411,12 @@ static enum nsswitch_status read_map_source(struct nss_source *this, + result = read_file_source_instance(ap, &tmap, age); + pthread_cleanup_pop(1); + ++ map->instance = tmap.instance; ++ + return result; + } + +-int lookup_nss_read_map(struct autofs_point *ap, time_t age) ++int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age) + { + struct master_mapent *entry = ap->entry; + struct list_head nsslist; +@@ -433,7 +434,10 @@ int lookup_nss_read_map(struct autofs_point *ap, time_t age) + */ + pthread_cleanup_push(master_source_lock_cleanup, entry); + master_source_readlock(entry); +- map = entry->maps; ++ if (source) ++ map = source; ++ else ++ map = entry->maps; + while (map) { + /* Is map source up to date or no longer valid */ + if (!map->stale || entry->age > map->age) { +@@ -655,7 +659,9 @@ static int lookup_name_file_source_instance(struct autofs_point *ap, struct map_ + + instance = master_find_source_instance(map, type, format, 0, NULL); + if (!instance) { +- instance = master_add_source_instance(map, type, format, age); ++ int argc = map->argc; ++ const char **argv = map->argv; ++ instance = master_add_source_instance(map, type, format, age, argc, argv); + if (!instance) + return NSS_STATUS_NOTFOUND; + instance->recurse = map->recurse; +@@ -675,7 +681,9 @@ static int lookup_name_source_instance(struct autofs_point *ap, struct map_sourc + + instance = master_find_source_instance(map, type, format, 0, NULL); + if (!instance) { +- instance = master_add_source_instance(map, type, format, age); ++ int argc = map->argc; ++ const char **argv = map->argv; ++ instance = master_add_source_instance(map, type, format, age, argc, argv); + if (!instance) + return NSS_STATUS_NOTFOUND; + instance->recurse = map->recurse; +@@ -690,7 +698,6 @@ static enum nsswitch_status lookup_map_name(struct nss_source *this, + const char *name, int name_len) + { + enum nsswitch_status result; +- struct map_source *instance; + struct map_source tmap; + char *path; + +@@ -710,13 +717,6 @@ static enum nsswitch_status lookup_map_name(struct nss_source *this, + return NSS_STATUS_NOTFOUND; + } + +- instance = master_find_source_instance(map, "file", map->format, 0, NULL); +- if (!instance) +- instance = master_find_source_instance(map, "program", map->format, 0, NULL); +- +- if (instance) +- return lookup_name_file_source_instance(ap, map, name, name_len); +- + this->source[4] = '\0'; + tmap.type = this->source; + tmap.format = map->format; +@@ -754,13 +754,15 @@ static enum nsswitch_status lookup_map_name(struct nss_source *this, + + result = lookup_name_file_source_instance(ap, &tmap, name, name_len); + ++ map->instance = tmap.instance; ++ + /* path is freed in free_argv */ + free_argv(tmap.argc, tmap.argv); + + return result; + } + +-int lookup_nss_mount(struct autofs_point *ap, const char *name, int name_len) ++int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len) + { + struct master_mapent *entry = ap->entry; + struct list_head nsslist; +@@ -777,7 +779,10 @@ int lookup_nss_mount(struct autofs_point *ap, const char *name, int name_len) + */ + pthread_cleanup_push(master_source_lock_cleanup, entry); + master_source_readlock(entry); +- map = entry->maps; ++ if (source) ++ map = source; ++ else ++ map = entry->maps; + while (map) { + /* + * Only consider map sources that have been read since +@@ -856,11 +861,28 @@ int lookup_nss_mount(struct autofs_point *ap, const char *name, int name_len) + + map = map->next; + } ++ send_map_update_request(ap); + pthread_cleanup_pop(1); + + return !result; + } + ++static void lookup_close_lookup_instances(struct map_source *map) ++{ ++ struct map_source *instance; ++ ++ instance = map->instance; ++ while (instance) { ++ lookup_close_lookup_instances(instance); ++ instance = instance->next; ++ } ++ ++ if (map->lookup) { ++ close_lookup(map->lookup); ++ map->lookup = NULL; ++ } ++} ++ + void lookup_close_lookup(struct autofs_point *ap) + { + struct map_source *map; +@@ -870,21 +892,7 @@ void lookup_close_lookup(struct autofs_point *ap) + return; + + while (map) { +- struct map_source *instance; +- +- instance = map->instance; +- while (instance) { +- if (instance->lookup) { +- close_lookup(instance->lookup); +- instance->lookup = NULL; +- } +- instance = instance->next; +- } +- +- if (map->lookup) { +- close_lookup(map->lookup); +- map->lookup = NULL; +- } ++ lookup_close_lookup_instances(map); + map = map->next; + } + return; +@@ -925,6 +933,7 @@ int lookup_prune_cache(struct autofs_point *ap, time_t age) + + map = entry->maps; + while (map) { ++ /* Is the map stale */ + if (!map->stale) { + map = map->next; + continue; +@@ -956,7 +965,7 @@ int lookup_prune_cache(struct autofs_point *ap, time_t age) + + if (is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { + debug(ap->logopt, +- "prune posponed, %s is mounted", path); ++ "prune check posponed, %s mounted", path); + free(key); + free(path); + continue; +diff --git a/daemon/state.c b/daemon/state.c +index 2fa78aa..6c373c8 100644 +--- a/daemon/state.c ++++ b/daemon/state.c +@@ -378,7 +378,7 @@ static void *do_readmap(void *arg) + + pthread_cleanup_push(do_readmap_cleanup, ra); + +- status = lookup_nss_read_map(ap, now); ++ status = lookup_nss_read_map(ap, NULL, now); + if (!status) + pthread_exit(NULL); + +diff --git a/include/automount.h b/include/automount.h +index 01e5301..85e6e9c 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -141,6 +141,7 @@ struct mapent { + pthread_mutex_t multi_mutex; + struct list_head multi_list; + struct mapent_cache *mc; ++ struct map_source *source; + /* Need to know owner if we're a multi-mount */ + struct mapent *multi; + /* Parent nesting point within multi-mount */ +@@ -175,10 +176,10 @@ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key); + struct mapent *cache_lookup_distinct(struct mapent_cache *mc, const char *key); + struct mapent *cache_lookup_offset(const char *prefix, const char *offset, int start, struct list_head *head); + struct mapent *cache_partial_match(struct mapent_cache *mc, const char *prefix); +-int cache_add(struct mapent_cache *mc, const char *key, const char *mapent, time_t age); ++int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age); + int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age); + int cache_set_parents(struct mapent *mm); +-int cache_update(struct mapent_cache *mc, const char *key, const char *mapent, time_t age); ++int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age); + int cache_delete(struct mapent_cache *mc, const char *key); + void cache_multi_lock(struct mapent *me); + void cache_multi_unlock(struct mapent *me); +@@ -221,11 +222,11 @@ int rmdir_path(struct autofs_point *ap, const char *path, dev_t dev); + #define PARSE_MAX_BUF KEY_MAX_LEN + MAPENT_MAX_LEN + 2 + + int lookup_nss_read_master(struct master *master, time_t age); +-int lookup_nss_read_map(struct autofs_point *ap, time_t age); ++int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age); + int lookup_enumerate(struct autofs_point *ap, + int (*fn)(struct autofs_point *,struct mapent *, int), time_t now); + int lookup_ghost(struct autofs_point *ap); +-int lookup_nss_mount(struct autofs_point *ap, const char *name, int name_len); ++int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len); + void lookup_close_lookup(struct autofs_point *ap); + int lookup_prune_cache(struct autofs_point *ap, time_t age); + struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type); +diff --git a/include/master.h b/include/master.h +index 96dfbd2..8470bb1 100644 +--- a/include/master.h ++++ b/include/master.h +@@ -85,7 +85,8 @@ void master_free_map_source(struct map_source *, unsigned int); + struct map_source * + master_find_source_instance(struct map_source *, const char *, const char *, int, const char **); + struct map_source * +-master_add_source_instance(struct map_source *, const char *, const char *, time_t); ++master_add_source_instance(struct map_source *, const char *, const char *, time_t, int, const char **); ++void send_map_update_request(struct autofs_point *); + void master_source_writelock(struct master_mapent *); + void master_source_readlock(struct master_mapent *); + void master_source_unlock(struct master_mapent *); +diff --git a/lib/cache.c b/lib/cache.c +index d27dea9..06bb461 100644 +--- a/lib/cache.c ++++ b/lib/cache.c +@@ -509,7 +509,7 @@ struct mapent *cache_partial_match(struct mapent_cache *mc, const char *prefix) + } + + /* cache must be write locked by caller */ +-int cache_add(struct mapent_cache *mc, const char *key, const char *mapent, time_t age) ++int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age) + { + struct mapent *me, *existing = NULL; + char *pkey, *pent; +@@ -541,6 +541,7 @@ int cache_add(struct mapent_cache *mc, const char *key, const char *mapent, time + me->age = age; + me->status = 0; + me->mc = mc; ++ me->source = ms; + INIT_LIST_HEAD(&me->ino_index); + INIT_LIST_HEAD(&me->multi_list); + me->multi = NULL; +@@ -618,7 +619,7 @@ int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key, + if (me && me != owner) + return CHE_DUPLICATE; + +- ret = cache_add(mc, key, mapent, age); ++ ret = cache_add(mc, owner->source, key, mapent, age); + if (ret == CHE_FAIL) { + warn(LOGOPT_ANY, "failed to add key %s to cache", key); + return CHE_FAIL; +@@ -686,7 +687,7 @@ int cache_set_parents(struct mapent *mm) + } + + /* cache must be write locked by caller */ +-int cache_update(struct mapent_cache *mc, const char *key, const char *mapent, time_t age) ++int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age) + { + struct mapent *me = NULL; + char *pent; +@@ -694,7 +695,7 @@ int cache_update(struct mapent_cache *mc, const char *key, const char *mapent, t + + me = cache_lookup(mc, key); + if (!me || (*me->key == '*' && *key != '*')) { +- ret = cache_add(mc, key, mapent, age); ++ ret = cache_add(mc, ms, key, mapent, age); + if (!ret) { + debug(LOGOPT_NONE, "failed for %s", key); + return CHE_FAIL; +@@ -705,9 +706,11 @@ int cache_update(struct mapent_cache *mc, const char *key, const char *mapent, t + if (me->age == age) + return CHE_OK; + +- if (!mapent) ++ if (!mapent) { ++ if (me->mapent) ++ free(me->mapent); + me->mapent = NULL; +- else if (!me->mapent || strcmp(me->mapent, mapent) != 0) { ++ } else if (!me->mapent || strcmp(me->mapent, mapent) != 0) { + pent = malloc(strlen(mapent) + 1); + if (pent == NULL) + return CHE_FAIL; +diff --git a/lib/master.c b/lib/master.c +index 0066f8b..4d31959 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -292,10 +292,8 @@ struct map_source *master_find_map_source(struct master_mapent *entry, + return source; + } + +-void master_free_map_source(struct map_source *source, unsigned int free_cache) ++static void __master_free_map_source(struct map_source *source, unsigned int free_cache) + { +- int status; +- + if (source->type) + free(source->type); + if (source->format) +@@ -318,20 +316,12 @@ void master_free_map_source(struct map_source *source, unsigned int free_cache) + if (source->instance) { + struct map_source *instance, *next; + +- status = pthread_mutex_lock(&instance_mutex); +- if (status) +- fatal(status); +- + instance = source->instance; + while (instance) { + next = instance->next; +- master_free_map_source(instance, 0); ++ __master_free_map_source(instance, 0); + instance = next; + } +- +- status = pthread_mutex_unlock(&instance_mutex); +- if (status) +- fatal(status); + } + + free(source); +@@ -339,6 +329,21 @@ void master_free_map_source(struct map_source *source, unsigned int free_cache) + return; + } + ++void master_free_map_source(struct map_source *source, unsigned int free_cache) ++{ ++ int status; ++ ++ status = pthread_mutex_lock(&instance_mutex); ++ if (status) ++ fatal(status); ++ ++ __master_free_map_source(source, free_cache); ++ ++ status = pthread_mutex_unlock(&instance_mutex); ++ if (status) ++ fatal(status); ++} ++ + struct map_source *master_find_source_instance(struct map_source *source, const char *type, const char *format, int argc, const char **argv) + { + struct map_source *map; +@@ -378,19 +383,15 @@ next: + } + + struct map_source * +-master_add_source_instance(struct map_source *source, const char *type, const char *format, time_t age) ++master_add_source_instance(struct map_source *source, const char *type, const char *format, time_t age, int argc, const char **argv) + { + struct map_source *instance; + struct map_source *new; + char *ntype, *nformat; +- const char **tmpargv, *name; ++ const char **tmpargv; + int status; + +- if (!type) +- return NULL; +- +- instance = master_find_source_instance(source, +- type, format, source->argc, source->argv); ++ instance = master_find_source_instance(source, type, format, argc, argv); + if (instance) + return instance; + +@@ -399,12 +400,14 @@ master_add_source_instance(struct map_source *source, const char *type, const ch + return NULL; + memset(new, 0, sizeof(struct map_source)); + +- ntype = strdup(type); +- if (!ntype) { +- master_free_map_source(new, 0); +- return NULL; ++ if (type) { ++ ntype = strdup(type); ++ if (!ntype) { ++ master_free_map_source(new, 0); ++ return NULL; ++ } ++ new->type = ntype; + } +- new->type = ntype; + + if (format) { + nformat = strdup(format); +@@ -418,17 +421,16 @@ master_add_source_instance(struct map_source *source, const char *type, const ch + new->age = age; + new->master_line = 0; + new->mc = source->mc; ++ new->stale = 1; + +- tmpargv = copy_argv(source->argc, source->argv); ++ tmpargv = copy_argv(argc, argv); + if (!tmpargv) { + master_free_map_source(new, 0); + return NULL; + } +- new->argc = source->argc; ++ new->argc = argc; + new->argv = tmpargv; + +- name = new->argv[0]; +- + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); +@@ -451,6 +453,71 @@ master_add_source_instance(struct map_source *source, const char *type, const ch + return new; + } + ++static void check_stale_instances(struct map_source *source) ++{ ++ struct map_source *map; ++ ++ if (!source) ++ return; ++ ++ map = source->instance; ++ while (map) { ++ if (map->stale) { ++ source->stale = 1; ++ break; ++ } ++ check_stale_instances(map->instance); ++ map = map->next; ++ } ++ ++ return; ++} ++ ++void send_map_update_request(struct autofs_point *ap) ++{ ++ struct map_source *map; ++ int status, need_update = 0; ++ ++ if (!ap->ghost) ++ return; ++ ++ status = pthread_mutex_lock(&instance_mutex); ++ if (status) ++ fatal(status); ++ ++ map = ap->entry->maps; ++ while (map) { ++ check_stale_instances(map); ++ map = map->next; ++ } ++ ++ map = ap->entry->maps; ++ while (map) { ++ if (map->stale) { ++ need_update = 1; ++ break; ++ } ++ map = map->next; ++ } ++ ++ status = pthread_mutex_unlock(&instance_mutex); ++ if (status) ++ fatal(status); ++ ++ if (!need_update) ++ return; ++ ++ status = pthread_mutex_lock(&ap->state_mutex); ++ if (status) ++ fatal(status); ++ nextstate(ap->state_pipe[1], ST_READMAP); ++ status = pthread_mutex_unlock(&ap->state_mutex); ++ if (status) ++ fatal(status); ++ ++ return; ++} ++ + void master_source_writelock(struct master_mapent *entry) + { + int status; +diff --git a/lib/master_parse.y b/lib/master_parse.y +index e4c9f7d..7e98a4e 100644 +--- a/lib/master_parse.y ++++ b/lib/master_parse.y +@@ -531,7 +531,7 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne + /* Add null map entries to the null map cache */ + if (type && !strcmp(type, "null")) { + cache_writelock(nc); +- cache_update(nc, path, NULL, lineno); ++ cache_update(nc, NULL, path, NULL, lineno); + cache_unlock(nc); + local_free_vars(); + return 1; +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index 4a5674e..cc1964f 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -547,45 +547,20 @@ static int check_self_include(const char *key, struct lookup_context *ctxt) + return 0; + } + +-static struct autofs_point * ++static struct map_source * + prepare_plus_include(struct autofs_point *ap, time_t age, char *key, unsigned int inc) + { +- struct master *master; +- struct master_mapent *entry; + struct map_source *current; + struct map_source *source; +- struct autofs_point *iap; + char *type, *map, *fmt; + const char *argv[2]; +- int ret, argc; +- unsigned int timeout = ap->exp_timeout; +- unsigned int logopt = ap->logopt; +- unsigned int ghost = ap->ghost; ++ int argc; + char *buf, *tmp; + + current = ap->entry->current; + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + +- master = ap->entry->master; +- +- entry = master_new_mapent(master, ap->path, ap->entry->age); +- if (!entry) { +- error(ap->logopt, MODPREFIX "malloc failed for entry"); +- return NULL; +- } +- +- ret = master_add_autofs_point(entry, timeout, logopt, ghost, 0); +- if (!ret) { +- master_free_mapent(entry); +- error(ap->logopt, +- MODPREFIX "failed to add autofs_point to entry"); +- return NULL; +- } +- iap = entry->ap; +- iap->kpipefd = ap->kpipefd; +- set_mnt_logging(iap); +- + /* + * TODO: + * Initially just consider the passed in key to be a simple map +@@ -598,7 +573,6 @@ prepare_plus_include(struct autofs_point *ap, time_t age, char *key, unsigned in + /* skip plus */ + buf = strdup(key + 1); + if (!buf) { +- master_free_mapent(entry); + error(ap->logopt, MODPREFIX "failed to strdup key"); + return NULL; + } +@@ -629,21 +603,23 @@ prepare_plus_include(struct autofs_point *ap, time_t age, char *key, unsigned in + argv[0] = map; + argv[1] = NULL; + +- source = master_add_map_source(entry, type, fmt, age, argc, argv); ++ source = master_find_source_instance(current, type, fmt, argc, argv); + if (!source) { +- master_free_mapent(entry); +- free(buf); +- error(ap->logopt, "failed to creat map_source"); +- return NULL; ++ source = master_add_source_instance(current, type, fmt, age, argc, argv); ++ if (!source) { ++ free(buf); ++ error(ap->logopt, "failed to add included map instance"); ++ return NULL; ++ } + } +- source->mc = current->mc; ++ + source->depth = current->depth + 1; + if (inc) + source->recurse = 1; + + free(buf); + +- return iap; ++ return source; + } + + int lookup_read_map(struct autofs_point *ap, time_t age, void *context) +@@ -715,7 +691,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + * included map. + */ + if (*key == '+') { +- struct autofs_point *iap; ++ struct map_source *inc_source; + unsigned int inc; + int status; + +@@ -726,21 +702,18 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + master_source_current_wait(ap->entry); + ap->entry->current = source; + +- iap = prepare_plus_include(ap, age, key, inc); +- if (!iap) { ++ inc_source = prepare_plus_include(ap, age, key, inc); ++ if (!inc_source) { + debug(ap->logopt, + "failed to select included map %s", key); + continue; + } + + /* Gim'ee some o' that 16k stack baby !! */ +- status = lookup_nss_read_map(iap, age); ++ status = lookup_nss_read_map(ap, inc_source, age); + if (!status) + warn(ap->logopt, + "failed to read included map %s", key); +- +- master_free_mapent_sources(iap->entry, 0); +- master_free_mapent(iap->entry); + } else { + char *s_key; + +@@ -749,7 +722,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + continue; + + cache_writelock(mc); +- cache_update(mc, s_key, mapent, age); ++ cache_update(mc, source, s_key, mapent, age); + cache_unlock(mc); + + free(s_key); +@@ -815,7 +788,7 @@ static int lookup_one(struct autofs_point *ap, + * included map. + */ + if (*mkey == '+') { +- struct autofs_point *iap; ++ struct map_source *inc_source; + unsigned int inc; + int status; + +@@ -827,8 +800,8 @@ static int lookup_one(struct autofs_point *ap, + master_source_current_wait(ap->entry); + ap->entry->current = source; + +- iap = prepare_plus_include(ap, age, mkey, inc); +- if (!iap) { ++ inc_source = prepare_plus_include(ap, age, mkey, inc); ++ if (!inc_source) { + debug(ap->logopt, + MODPREFIX + "failed to select included map %s", +@@ -837,11 +810,7 @@ static int lookup_one(struct autofs_point *ap, + } + + /* Gim'ee some o' that 16k stack baby !! */ +- status = lookup_nss_mount(iap, key, key_len); +- +- master_free_mapent_sources(iap->entry, 0); +- master_free_mapent(iap->entry); +- ++ status = lookup_nss_mount(ap, inc_source, key, key_len); + if (status) { + fclose(f); + return CHE_COMPLETED; +@@ -868,7 +837,7 @@ static int lookup_one(struct autofs_point *ap, + free(s_key); + + cache_writelock(mc); +- ret = cache_update(mc, key, mapent, age); ++ ret = cache_update(mc, source, key, mapent, age); + cache_unlock(mc); + + fclose(f); +@@ -928,7 +897,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt) + continue; + + cache_writelock(mc); +- ret = cache_update(mc, "*", mapent, age); ++ ret = cache_update(mc, source, "*", mapent, age); + cache_unlock(mc); + + fclose(f); +@@ -952,7 +921,6 @@ static int check_map_indirect(struct autofs_point *ap, + struct map_source *source; + struct mapent_cache *mc; + struct mapent *exists; +- int need_map = 0; + int ret = CHE_OK; + + source = ap->entry->current; +@@ -961,12 +929,6 @@ static int check_map_indirect(struct autofs_point *ap, + + mc = source->mc; + +- cache_readlock(mc); +- exists = cache_lookup_distinct(mc, key); +- if (exists && exists->mc != mc) +- exists = NULL; +- cache_unlock(mc); +- + master_source_current_wait(ap->entry); + ap->entry->current = source; + +@@ -977,49 +939,53 @@ static int check_map_indirect(struct autofs_point *ap, + if (ret == CHE_FAIL) + return NSS_STATUS_NOTFOUND; + +- if ((ret & CHE_UPDATED) || +- (exists && (ret & CHE_MISSING))) +- need_map = 1; ++ if (ret & CHE_UPDATED) ++ source->stale = 1; ++ ++ pthread_cleanup_push(cache_lock_cleanup, mc); ++ cache_writelock(mc); ++ exists = cache_lookup_distinct(mc, key); ++ /* Not found in the map but found in the cache */ ++ if (exists && exists->source == source && ret & CHE_MISSING) { ++ if (exists->mapent) { ++ free(exists->mapent); ++ exists->mapent = NULL; ++ exists->status = 0; ++ source->stale = 1; ++ } ++ } ++ pthread_cleanup_pop(1); + + if (ret == CHE_MISSING) { ++ struct mapent *we; + int wild = CHE_MISSING; + + master_source_current_wait(ap->entry); + ap->entry->current = source; + + wild = lookup_wild(ap, ctxt); +- if (wild == CHE_COMPLETED || CHE_UPDATED || CHE_OK) +- return NSS_STATUS_SUCCESS; +-/* +- if (wild == CHE_FAIL) +- return NSS_STATUS_NOTFOUND; +-*/ ++ /* ++ * Check for map change and update as needed for ++ * following cache lookup. ++ */ + pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); +- if (wild == CHE_MISSING) +- cache_delete(mc, "*"); +- +- if (cache_delete(mc, key) && wild & (CHE_MISSING | CHE_FAIL)) +- rmdir_path(ap, key, ap->dev); ++ we = cache_lookup_distinct(mc, "*"); ++ if (we) { ++ /* Wildcard entry existed and is now gone */ ++ if (we->source == source && (wild & CHE_MISSING)) { ++ cache_delete(mc, "*"); ++ source->stale = 1; ++ } ++ } else { ++ /* Wildcard not in map but now is */ ++ if (wild & (CHE_OK || CHE_UPDATED)) ++ source->stale = 1; ++ } + pthread_cleanup_pop(1); +- } + +- /* Have parent update its map ? */ +- /* TODO: update specific map */ +- if (ap->ghost && need_map) { +- int status; +- +- source->stale = 1; +- +- status = pthread_mutex_lock(&ap->state_mutex); +- if (status) +- fatal(status); +- +- nextstate(ap->state_pipe[1], ST_READMAP); +- +- status = pthread_mutex_unlock(&ap->state_mutex); +- if (status) +- fatal(status); ++ if (wild & (CHE_OK || CHE_UPDATED)) ++ return NSS_STATUS_SUCCESS; + } + + if (ret == CHE_MISSING) +@@ -1109,7 +1075,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + + cache_readlock(mc); + me = cache_lookup(mc, key); +- if (me && me->mapent && *me->mapent) { ++ /* Stale mapent => check for wildcard */ ++ if (me && !me->mapent) ++ me = cache_lookup_distinct(mc, "*"); ++ if (me && (me->source == source || *me->key == '/')) { + pthread_cleanup_push(cache_lock_cleanup, mc); + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); +@@ -1132,7 +1101,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + cache_writelock(mc); + me = cache_lookup_distinct(mc, key); + if (!me) +- rv = cache_update(mc, key, NULL, now); ++ rv = cache_update(mc, source, key, NULL, now); + if (rv != CHE_FAIL) { + me = cache_lookup_distinct(mc, key); + me->status = now + NEGATIVE_TIMEOUT; +diff --git a/modules/lookup_hesiod.c b/modules/lookup_hesiod.c +index 562c51b..f30e9b2 100644 +--- a/modules/lookup_hesiod.c ++++ b/modules/lookup_hesiod.c +@@ -154,7 +154,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + } + + cache_writelock(mc); +- rv = cache_update(mc, name, best_record, time(NULL)); ++ rv = cache_update(mc, source, name, best_record, time(NULL)); + cache_unlock(mc); + if (rv == CHE_FAIL) + return NSS_STATUS_UNAVAIL; +diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c +index 7eb5060..f6a65ae 100644 +--- a/modules/lookup_hosts.c ++++ b/modules/lookup_hosts.c +@@ -103,7 +103,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + while ((host = gethostent()) != NULL) { + pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); +- cache_update(mc, host->h_name, NULL, age); ++ cache_update(mc, source, host->h_name, NULL, age); + cache_unlock(mc); + pthread_cleanup_pop(0); + } +@@ -257,7 +257,7 @@ done: + debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent); + + cache_writelock(mc); +- cache_update(mc, name, mapent, now); ++ cache_update(mc, source, name, mapent, now); + cache_unlock(mc); + + debug(LOGOPT_ANY, "source wait"); +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 3a1d36b..29ba0c8 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -1251,7 +1251,7 @@ static int read_one_map(struct autofs_point *ap, + goto next; + + cache_writelock(mc); +- cache_update(mc, s_key, mapent, age); ++ cache_update(mc, source, s_key, mapent, age); + cache_unlock(mc); + + free(s_key); +@@ -1313,6 +1313,7 @@ static int lookup_one(struct autofs_point *ap, + char *attrs[3]; + int scope = LDAP_SCOPE_SUBTREE; + LDAP *ldap; ++ struct mapent *we; + unsigned int wild = 0; + int ret = CHE_MISSING; + +@@ -1466,7 +1467,7 @@ static int lookup_one(struct autofs_point *ap, + goto next; + wild = 1; + cache_writelock(mc); +- cache_update(mc, "*", mapent, age); ++ cache_update(mc, source, "*", mapent, age); + cache_unlock(mc); + goto next; + } +@@ -1476,7 +1477,7 @@ static int lookup_one(struct autofs_point *ap, + goto next; + + cache_writelock(mc); +- ret = cache_update(mc, s_key, mapent, age); ++ ret = cache_update(mc, source, s_key, mapent, age); + cache_unlock(mc); + + free(s_key); +@@ -1493,10 +1494,34 @@ next: + ldap_msgfree(result); + unbind_ldap_connection(ldap, ctxt); + ++ /* Failed to find wild entry, update cache if needed */ ++ pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); +- if (!wild && cache_lookup(mc, "*")) +- cache_delete(mc, "*"); +- cache_unlock(mc); ++ we = cache_lookup_distinct(mc, "*"); ++ if (we) { ++ /* Wildcard entry existed and is now gone */ ++ if (we->source == source && !wild) { ++ cache_delete(mc, "*"); ++ source->stale = 1; ++ } ++ } else { ++ /* Wildcard not in map but now is */ ++ if (wild) ++ source->stale = 1; ++ } ++ /* Not found in the map but found in the cache */ ++ if (ret == CHE_MISSING) { ++ struct mapent *exists = cache_lookup_distinct(mc, qKey); ++ if (exists && exists->source == source) { ++ if (exists->mapent) { ++ free(exists->mapent); ++ exists->mapent = NULL; ++ source->stale = 1; ++ exists->status = 0; ++ } ++ } ++ } ++ pthread_cleanup_pop(1); + + return ret; + } +@@ -1507,10 +1532,10 @@ static int check_map_indirect(struct autofs_point *ap, + { + struct map_source *source; + struct mapent_cache *mc; +- struct mapent *me, *exists; ++ struct mapent *me; + time_t now = time(NULL); + time_t t_last_read; +- int ret, cur_state, need_map = 0; ++ int ret, cur_state; + + source = ap->entry->current; + ap->entry->current = NULL; +@@ -1518,12 +1543,6 @@ static int check_map_indirect(struct autofs_point *ap, + + mc = source->mc; + +- cache_readlock(mc); +- exists = cache_lookup_distinct(mc, key); +- if (exists && exists->mc != mc) +- exists = NULL; +- cache_unlock(mc); +- + master_source_current_wait(ap->entry); + ap->entry->current = source; + +@@ -1535,44 +1554,28 @@ static int check_map_indirect(struct autofs_point *ap, + } + pthread_setcancelstate(cur_state, NULL); + ++ /* ++ * Check for map change and update as needed for ++ * following cache lookup. ++ */ + cache_readlock(mc); ++ t_last_read = ap->exp_runfreq + 1; + me = cache_lookup_first(mc); +- t_last_read = me ? now - me->age : ap->exp_runfreq + 1; +- cache_unlock(mc); +- +- if (t_last_read > ap->exp_runfreq) { +- if ((ret & CHE_UPDATED) || +- (exists && (ret & CHE_MISSING))) +- need_map = 1; +- } +- +- if (ret == CHE_MISSING && exists) { +- pthread_cleanup_push(cache_lock_cleanup, mc); +- cache_writelock(mc); +- if (cache_delete(mc, key)) +- rmdir_path(ap, key, ap->dev); +- pthread_cleanup_pop(1); ++ while (me) { ++ if (me->source == source) { ++ t_last_read = now - me->age; ++ break; ++ } ++ me = cache_lookup_next(mc, me); + } ++ cache_unlock(mc); + +- /* Have parent update its map */ +- if (ap->ghost && need_map) { +- int status; +- ++ if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED) + source->stale = 1; + +- status = pthread_mutex_lock(&ap->state_mutex); +- if (status) +- fatal(status); +- +- nextstate(ap->state_pipe[1], ST_READMAP); +- +- status = pthread_mutex_unlock(&ap->state_mutex); +- if (status) +- fatal(status); +- } +- + cache_readlock(mc); +- if (ret == CHE_MISSING && !cache_lookup(mc, "*")) { ++ me = cache_lookup_distinct(mc, "*"); ++ if (ret == CHE_MISSING && (!me || me->source != source)) { + cache_unlock(mc); + return NSS_STATUS_NOTFOUND; + } +@@ -1648,7 +1651,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + + cache_readlock(mc); + me = cache_lookup(mc, key); +- if (me && me->mapent && *me->mapent) { ++ /* Stale mapent => check for wildcard */ ++ if (me && !me->mapent) ++ me = cache_lookup_distinct(mc, "*"); ++ if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); + strcpy(mapent, me->mapent); +@@ -1670,7 +1676,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + cache_writelock(mc); + me = cache_lookup_distinct(mc, key); + if (!me) +- rv = cache_update(mc, key, NULL, now); ++ rv = cache_update(mc, source, key, NULL, now); + if (rv != CHE_FAIL) { + me = cache_lookup_distinct(mc, key); + me->status = now + NEGATIVE_TIMEOUT; +diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c +index 683ec6c..eae8702 100644 +--- a/modules/lookup_nisplus.c ++++ b/modules/lookup_nisplus.c +@@ -234,7 +234,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + mapent = ENTRY_VAL(this, 1); + + cache_writelock(mc); +- cache_update(mc, s_key, mapent, age); ++ cache_update(mc, source, s_key, mapent, age); + cache_unlock(mc); + + free(s_key); +@@ -296,7 +296,7 @@ static int lookup_one(struct autofs_point *ap, + this = NIS_RES_OBJECT(result); + mapent = ENTRY_VAL(this, 1); + cache_writelock(mc); +- ret = cache_update(mc, key, mapent, age); ++ ret = cache_update(mc, source, key, mapent, age); + cache_unlock(mc); + + nis_freeresult(result); +@@ -348,7 +348,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt) + this = NIS_RES_OBJECT(result); + mapent = ENTRY_VAL(this, 1); + cache_writelock(mc); +- ret = cache_update(mc, "*", mapent, age); ++ ret = cache_update(mc, source, "*", mapent, age); + cache_unlock(mc); + + nis_freeresult(result); +@@ -366,7 +366,6 @@ static int check_map_indirect(struct autofs_point *ap, + struct mapent *me, *exists; + time_t now = time(NULL); + time_t t_last_read; +- int need_map = 0; + int ret = 0; + + source = ap->entry->current; +@@ -375,12 +374,6 @@ static int check_map_indirect(struct autofs_point *ap, + + mc = source->mc; + +- cache_readlock(mc); +- exists = cache_lookup_distinct(mc, key); +- if (exists && exists->mc != mc) +- exists = NULL; +- cache_unlock(mc); +- + master_source_current_wait(ap->entry); + ap->entry->current = source; + +@@ -396,51 +389,62 @@ static int check_map_indirect(struct autofs_point *ap, + return NSS_STATUS_UNAVAIL; + } + +- cache_readlock(mc); ++ pthread_cleanup_push(cache_lock_cleanup, mc); ++ cache_writelock(mc); ++ t_last_read = ap->exp_runfreq + 1; + me = cache_lookup_first(mc); +- t_last_read = me ? now - me->age : ap->exp_runfreq + 1; +- cache_unlock(mc); +- +- if (t_last_read > ap->exp_runfreq) +- if ((ret & CHE_UPDATED) || +- (exists && (ret & CHE_MISSING))) +- need_map = 1; ++ while (me) { ++ if (me->source == source) { ++ t_last_read = now - me->age; ++ break; ++ } ++ me = cache_lookup_next(mc, me); ++ } ++ exists = cache_lookup_distinct(mc, key); ++ /* Not found in the map but found in the cache */ ++ if (exists && exists->source == source && ret & CHE_MISSING) { ++ if (exists->mapent) { ++ free(exists->mapent); ++ exists->mapent = NULL; ++ source->stale = 1; ++ exists->status = 0; ++ } ++ } ++ pthread_cleanup_pop(1); ++ ++ if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED) ++ source->stale = 1; + + if (ret == CHE_MISSING) { + int wild = CHE_MISSING; ++ struct mapent *we; + + master_source_current_wait(ap->entry); + ap->entry->current = source; + + wild = lookup_wild(ap, ctxt); +- if (wild == CHE_UPDATED || CHE_OK) +- return NSS_STATUS_SUCCESS; +- ++ /* ++ * Check for map change and update as needed for ++ * following cache lookup. ++ */ + pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); +- if (wild == CHE_MISSING) +- cache_delete(mc, "*"); +- +- if (cache_delete(mc, key) && wild & (CHE_MISSING | CHE_FAIL)) +- rmdir_path(ap, key, ap->dev); ++ we = cache_lookup_distinct(mc, "*"); ++ if (we) { ++ /* Wildcard entry existed and is now gone */ ++ if (we->source == source && wild & CHE_MISSING) { ++ cache_delete(mc, "*"); ++ source->stale = 1; ++ } ++ } else { ++ /* Wildcard not in map but now is */ ++ if (wild & (CHE_OK || CHE_UPDATED)) ++ source->stale = 1; ++ } + pthread_cleanup_pop(1); +- } +- +- /* Have parent update its map */ +- if (ap->ghost && need_map) { +- int status; +- +- source->stale = 1; + +- status = pthread_mutex_lock(&ap->state_mutex); +- if (status) +- fatal(status); +- +- nextstate(ap->state_pipe[1], ST_READMAP); +- +- status = pthread_mutex_unlock(&ap->state_mutex); +- if (status) +- fatal(status); ++ if (wild & (CHE_UPDATED || CHE_OK)) ++ return NSS_STATUS_SUCCESS; + } + + if (ret == CHE_MISSING) +@@ -514,7 +518,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + + cache_readlock(mc); + me = cache_lookup(mc, key); +- if (me && me->mapent && *me->mapent) { ++ /* Stale mapent => check for wildcard */ ++ if (me && !me->mapent) ++ me = cache_lookup_distinct(mc, "*"); ++ if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); + strcpy(mapent, me->mapent); +@@ -535,7 +542,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + cache_writelock(mc); + me = cache_lookup_distinct(mc, key); + if (!me) +- rv = cache_update(mc, key, NULL, now); ++ rv = cache_update(mc, source, key, NULL, now); + if (rv != CHE_FAIL) { + me = cache_lookup_distinct(mc, key); + me->status = time(NULL) + NEGATIVE_TIMEOUT; +diff --git a/modules/lookup_program.c b/modules/lookup_program.c +index a22d400..1cdbf80 100644 +--- a/modules/lookup_program.c ++++ b/modules/lookup_program.c +@@ -339,7 +339,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + } + + cache_writelock(mc); +- ret = cache_update(mc, name, mapent, time(NULL)); ++ ret = cache_update(mc, source, name, mapent, time(NULL)); + cache_unlock(mc); + if (ret == CHE_FAIL) + return NSS_STATUS_UNAVAIL; +diff --git a/modules/lookup_userhome.c b/modules/lookup_userhome.c +index 00a01ea..efcab0b 100644 +--- a/modules/lookup_userhome.c ++++ b/modules/lookup_userhome.c +@@ -78,7 +78,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + } + + cache_writelock(mc); +- ret = cache_update(mc, name, NULL, time(NULL)); ++ ret = cache_update(mc, source, name, NULL, time(NULL)); + cache_unlock(mc); + + if (ret == CHE_FAIL) { +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index 5f03b2f..5a154cd 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -272,7 +272,7 @@ int yp_all_callback(int status, char *ypkey, int ypkeylen, + *(mapent + vallen) = '\0'; + + cache_writelock(mc); +- ret = cache_update(mc, key, mapent, age); ++ ret = cache_update(mc, source, key, mapent, age); + cache_unlock(mc); + + free(key); +@@ -389,7 +389,7 @@ static int lookup_one(struct autofs_point *ap, + } + + cache_writelock(mc); +- ret = cache_update(mc, key, mapent, age); ++ ret = cache_update(mc, source, key, mapent, age); + cache_unlock(mc); + free(mapent); + +@@ -441,7 +441,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt) + } + + cache_writelock(mc); +- ret = cache_update(mc, "*", mapent, age); ++ ret = cache_update(mc, source, "*", mapent, age); + cache_unlock(mc); + free(mapent); + +@@ -456,7 +456,6 @@ static int check_map_indirect(struct autofs_point *ap, + struct mapent_cache *mc; + struct mapent *exists; + unsigned int map_order; +- int need_map = 0; + int ret = 0; + + source = ap->entry->current; +@@ -465,12 +464,6 @@ static int check_map_indirect(struct autofs_point *ap, + + mc = source->mc; + +- cache_readlock(mc); +- exists = cache_lookup_distinct(mc, key); +- if (exists && exists->mc != mc) +- exists = NULL; +- cache_unlock(mc); +- + master_source_current_wait(ap->entry); + ap->entry->current = source; + +@@ -490,44 +483,53 @@ static int check_map_indirect(struct autofs_point *ap, + map_order = get_map_order(ctxt->domainname, ctxt->mapname); + if (map_order > ctxt->order) { + ctxt->order = map_order; +- need_map = 1; ++ source->stale = 1; + } + ++ pthread_cleanup_push(cache_lock_cleanup, mc); ++ cache_writelock(mc); ++ exists = cache_lookup_distinct(mc, key); ++ /* Not found in the map but found in the cache */ ++ if (exists && exists->source == source && ret & CHE_MISSING) { ++ if (exists->mapent) { ++ free(exists->mapent); ++ exists->mapent = NULL; ++ source->stale = 1; ++ exists->status = 0; ++ } ++ } ++ pthread_cleanup_pop(1); ++ + if (ret == CHE_MISSING) { ++ struct mapent *we; + int wild = CHE_MISSING; + + master_source_current_wait(ap->entry); + ap->entry->current = source; + + wild = lookup_wild(ap, ctxt); +- if (wild == CHE_UPDATED || CHE_OK) +- return NSS_STATUS_SUCCESS; +- ++ /* ++ * Check for map change and update as needed for ++ * following cache lookup. ++ */ + pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); +- if (wild == CHE_MISSING) +- cache_delete(mc, "*"); +- +- if (cache_delete(mc, key) && wild & (CHE_MISSING | CHE_FAIL)) +- rmdir_path(ap, key, ap->dev); ++ we = cache_lookup_distinct(mc, "*"); ++ if (we) { ++ /* Wildcard entry existed and is now gone */ ++ if (we->source == source && (wild & CHE_MISSING)) { ++ cache_delete(mc, "*"); ++ source->stale = 1; ++ } ++ } else { ++ /* Wildcard not in map but now is */ ++ if (wild & (CHE_OK || CHE_UPDATED)) ++ source->stale = 1; ++ } + pthread_cleanup_pop(1); +- } +- +- /* Have parent update its map if needed */ +- if (ap->ghost && need_map) { +- int status; + +- source->stale = 1; +- +- status = pthread_mutex_lock(&ap->state_mutex); +- if (status) +- fatal(status); +- +- nextstate(ap->state_pipe[1], ST_READMAP); +- +- status = pthread_mutex_unlock(&ap->state_mutex); +- if (status) +- fatal(status); ++ if (wild & (CHE_OK || CHE_UPDATED)) ++ return NSS_STATUS_SUCCESS; + } + + if (ret == CHE_MISSING) +@@ -602,7 +604,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + + cache_readlock(mc); + me = cache_lookup(mc, key); +- if (me && me->mapent && *me->mapent) { ++ /* Stale mapent => check for wildcard */ ++ if (me && !me->mapent) ++ me = cache_lookup_distinct(mc, "*"); ++ if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); + strcpy(mapent, me->mapent); +@@ -623,7 +628,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + cache_writelock(mc); + me = cache_lookup_distinct(mc, key); + if (!me) +- rv = cache_update(mc, key, NULL, now); ++ rv = cache_update(mc, source, key, NULL, now); + if (rv != CHE_FAIL) { + me = cache_lookup_distinct(mc, key); + me->status = now + NEGATIVE_TIMEOUT; +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 93fe3de..9323e7c 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -1080,7 +1080,7 @@ int parse_mount(struct autofs_point *ap, const char *name, + * Not in the cache, perhaps it's a program map + * or one that doesn't support enumeration + */ +- ret = cache_add(mc, name, mapent, time(NULL)); ++ ret = cache_add(mc, source, name, mapent, time(NULL)); + if (ret == CHE_FAIL) { + cache_unlock(mc); + free(options); diff --git a/autofs.spec b/autofs.spec index 7c58f0f..379d80d 100644 --- a/autofs.spec +++ b/autofs.spec @@ -4,7 +4,7 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.0.1 -Release: 5 +Release: 6 Epoch: 1 License: GPL Group: System Environment/Daemons @@ -19,6 +19,8 @@ Patch6: autofs-5.0.1-network_match-fix.patch Patch7: autofs-5.0.1-drop-default-prefix-from-config.patch Patch8: autofs-5.0.1-random-selection.patch Patch9: autofs-5.0.1-bad-cast.patch +Patch10: autofs-5.0.1-fix-browse-dir-create.patch +Patch11: autofs-5.0.1-map-update-source-only.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 Conflicts: kernel < 2.6.17 @@ -69,6 +71,8 @@ echo %{version}-%{release} > .version %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 +%patch11 -p1 %build #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir} @@ -121,6 +125,10 @@ fi %{_libdir}/autofs/ %changelog +* Fri Mar 29 2007 Ian Kent - 5.0.1-6 +- fix directory creation for browse mounts. +- fix wildcard map handling and improve nsswitch source map update. + * Fri Mar 16 2007 Ian Kent - 5.0.1-5 - drop "DEFAULT_" prefix from configuration names. - add option to select replicated server at random (instead of