autofs-5.0.9 - amd lookup fix host mount naming From: Ian Kent Currently the amd host mount type assumes the lookup name is the host name for the host mount but amd uses ${rhost} for this. This introduces the possibility of multiple concurrent mount requests since constructing a mount tree that isn't under the lookup name can't take advantage of the kernel queuing other concurrent lookups while the mount tree is constructed. --- daemon/lookup.c | 20 +++++++++++++---- modules/parse_amd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++-- modules/parse_sun.c | 22 ++++++++++++------ 3 files changed, 89 insertions(+), 14 deletions(-) diff --git a/daemon/lookup.c b/daemon/lookup.c index c56fdd3..40fe459 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -807,7 +807,8 @@ static int lookup_amd_instance(struct autofs_point *ap, m_key = malloc(strlen(ap->path) + strlen(me->multi->key) + 1); if (!m_key) { - error(ap->logopt, "failed to allocate storage for search key"); + error(ap->logopt, + "failed to allocate storage for search key"); return NSS_STATUS_UNKNOWN; } @@ -815,12 +816,12 @@ static int lookup_amd_instance(struct autofs_point *ap, strcat(m_key, "/"); strcat(m_key, me->multi->key); entry = master_find_amdmount(ap, m_key); + free(m_key); + if (!entry) { error(ap->logopt, "expected amd mount entry not found"); - free(m_key); return NSS_STATUS_UNKNOWN; } - free(m_key); if (strcmp(entry->type, "host")) { error(ap->logopt, "unexpected map type %s", entry->type); @@ -835,6 +836,17 @@ static int lookup_amd_instance(struct autofs_point *ap, } instance = master_find_source_instance(map, "hosts", "sun", argc, pargv); + /* If this is an nss map instance it may have an amd host map sub instance */ + if (!instance && map->instance) { + struct map_source *next = map->instance; + while (next) { + instance = master_find_source_instance(next, + "hosts", "sun", argc, pargv); + if (instance) + break; + next = next->next; + } + } if (!instance) { error(ap->logopt, "expected hosts map instance not found"); return NSS_STATUS_UNKNOWN; @@ -1166,7 +1178,6 @@ int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const c } if (ap->state != ST_INIT) send_map_update_request(ap); - pthread_cleanup_pop(1); /* * The last source lookup will return NSS_STATUS_NOTFOUND if the @@ -1175,6 +1186,7 @@ int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const c */ if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL) update_negative_cache(ap, source, name); + pthread_cleanup_pop(1); return !result; } diff --git a/modules/parse_amd.c b/modules/parse_amd.c index e86fb7f..2056ed9 100644 --- a/modules/parse_amd.c +++ b/modules/parse_amd.c @@ -1068,6 +1068,23 @@ static int do_nfsl_mount(struct autofs_point *ap, const char *name, return do_link_mount(ap, name, entry, flags); } +static int wait_for_expire(struct autofs_point *ap) +{ + int ret = 1; + + st_wait_task(ap, ST_EXPIRE, 0); + + st_mutex_lock(); + if (ap->state != ST_SHUTDOWN && + ap->state != ST_SHUTDOWN_PENDING && + ap->state != ST_SHUTDOWN_FORCE) { + ret = 0; + } + st_mutex_unlock(); + + return ret; +} + static int do_host_mount(struct autofs_point *ap, const char *name, struct amd_entry *entry, struct map_source *source, unsigned int flags) @@ -1080,6 +1097,36 @@ static int do_host_mount(struct autofs_point *ap, const char *name, int argc = 0; int ret = 1; + /* + * If the mount point name isn't the same as the host name + * then we need to symlink to it after the mount. Attempt + * the allocation and set entry->path to the base location + * of the hosts mount tree so we can find it in + * lookup_nss_mount() later. + */ + if (strcmp(name, entry->rhost)) { + char *target; + size_t len = strlen(ap->path) + strlen(entry->rhost) + 2; + target = malloc(len); + if (!target) { + warn(ap->logopt, MODPREFIX + "failed to alloc target to hosts mount base"); + goto out; + } + strcpy(target, ap->path); + strcat(target, "/"); + strcat(target, entry->rhost); + if (entry->path) + free(entry->path); + entry->path = target; + /* + * Wait for any expire before racing to mount the + * export tree or bail out if we're shutting down. + */ + if (!wait_for_expire(ap)) + goto out; + } + if (entry->opts) { argv[0] = entry->opts; argv[1] = NULL; @@ -1095,7 +1142,8 @@ static int do_host_mount(struct autofs_point *ap, const char *name, goto out; } - instance = master_find_source_instance(source, "hosts", "sun", argc, pargv); + instance = master_find_source_instance(source, + "hosts", "sun", argc, pargv); if (!instance) { instance = master_add_source_instance(source, "hosts", "sun", time(NULL), argc, pargv); @@ -1119,7 +1167,16 @@ static int do_host_mount(struct autofs_point *ap, const char *name, master_source_current_wait(ap->entry); ap->entry->current = source; - ret = lookup->lookup_mount(ap, name, strlen(name), lookup->context); + ret = lookup->lookup_mount(ap, entry->rhost, + strlen(entry->rhost), lookup->context); + + if (!strcmp(name, entry->rhost)) + goto out; + + if (do_mount(ap, ap->path, + name, strlen(name), entry->path, "bind", "symlink")) + warn(ap->logopt, MODPREFIX + "failed to create symlink to hosts mount base"); out: return ret; } diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 6f0e3c9..1fdea0b 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -1343,26 +1343,32 @@ int parse_mount(struct autofs_point *ap, const char *name, strcat(m_root, name); } + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); cache_readlock(mc); me = cache_lookup_distinct(mc, name); - if (me) { - /* So we know we're the multi-mount root */ - if (!me->multi) - me->multi = me; - } - if (!me) { free(options); cache_unlock(mc); + pthread_setcancelstate(cur_state, NULL); error(ap->logopt, MODPREFIX "can't find multi root %s", name); return 1; } + cache_multi_writelock(me); + /* Someone beat us to it, return success */ + if (me->multi) { + free(options); + cache_multi_unlock(me); + cache_unlock(mc); + pthread_setcancelstate(cur_state, NULL); + return 0; + } + /* So we know we're the multi-mount root */ + me->multi = me; + age = me->age; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - cache_multi_writelock(me); /* It's a multi-mount; deal with it */ do { char *path, *myoptions, *loc;