autofs-5.1.8 - fix deadlock in lookups From: Ian Kent After adding locking to fix a crash during lookups we're seeing a deadlock becuase of recursive calls. But once the lookup is open we shouldn't need to open it again during the recursive call, fix it based on that. Signed-off-by: Ian Kent --- CHANGELOG | 1 daemon/lookup.c | 62 +++++++++++++++++++++++++++++++++------------------- daemon/master.c | 8 ++++++ include/master.h | 1 modules/parse_amd.c | 2 - 5 files changed, 51 insertions(+), 23 deletions(-) --- autofs-5.1.7.orig/CHANGELOG +++ autofs-5.1.7/CHANGELOG @@ -117,6 +117,7 @@ - don't immediately call function when waiting. - fix return status of mount_autofs(). - don't close lookup at umount. +- fix deadlock in lookups. 25/01/2021 autofs-5.1.7 - make bind mounts propagation slave by default. --- autofs-5.1.7.orig/daemon/lookup.c +++ autofs-5.1.7/daemon/lookup.c @@ -318,31 +318,49 @@ static int do_read_map(struct autofs_poi struct lookup_mod *lookup; int status; - pthread_cleanup_push(map_module_lock_cleanup, map); - map_module_writelock(map); - if (!map->lookup) { - status = open_lookup(map->type, "", map->format, - map->argc, map->argv, &lookup); - if (status == NSS_STATUS_SUCCESS) - map->lookup = lookup; - else - debug(ap->logopt, - "lookup module %s open failed", map->type); - } else { - status = map->lookup->lookup_reinit(map->format, - map->argc, map->argv, - &map->lookup->context); - if (status) - warn(ap->logopt, - "lookup module %s reinit failed", map->type); - } - pthread_cleanup_pop(1); - if (status != NSS_STATUS_SUCCESS) - return status; - if (!map->stale) return NSS_STATUS_SUCCESS; + /* If this readmap is the result of trying to mount a submount + * the readlock may already be held if the map is the same as + * that of the caller. In that case the map has already been + * read so just skip the map open/reinit. + */ + status = map_module_try_writelock(map); + if (status) { + if (!map->lookup) { + error(ap->logopt, "map module lock not held as expected"); + return NSS_STATUS_UNAVAIL; + } + } else { + if (!map->lookup) { + pthread_cleanup_push(map_module_lock_cleanup, map); + status = open_lookup(map->type, "", map->format, + map->argc, map->argv, &lookup); + pthread_cleanup_pop(0); + if (status != NSS_STATUS_SUCCESS) { + map_module_unlock(map); + debug(ap->logopt, + "lookup module %s open failed", map->type); + return status; + } + map->lookup = lookup; + } else { + pthread_cleanup_push(map_module_lock_cleanup, map); + status = map->lookup->lookup_reinit(map->format, + map->argc, map->argv, + &map->lookup->context); + pthread_cleanup_pop(0); + if (status) { + map_module_unlock(map); + warn(ap->logopt, + "lookup module %s reinit failed", map->type); + return status; + } + } + map_module_unlock(map); + } + master_source_current_wait(ap->entry); ap->entry->current = map; --- autofs-5.1.7.orig/daemon/master.c +++ autofs-5.1.7/daemon/master.c @@ -72,6 +72,14 @@ void map_module_writelock(struct map_sou fatal(status); } +int map_module_try_writelock(struct map_source *map) +{ + int status = pthread_rwlock_trywrlock(&map->module_lock); + if (status && status != EBUSY && status != EDEADLK) + fatal(status); + return status; +} + void map_module_readlock(struct map_source *map) { int status = pthread_rwlock_rdlock(&map->module_lock); --- autofs-5.1.7.orig/include/master.h +++ autofs-5.1.7/include/master.h @@ -128,6 +128,7 @@ int master_list_empty(struct master *); int master_done(struct master *); int master_kill(struct master *); void map_module_writelock(struct map_source *map); +int map_module_try_writelock(struct map_source *map); void map_module_readlock(struct map_source *map); void map_module_unlock(struct map_source *map); void map_module_lock_cleanup(void *arg); --- autofs-5.1.7.orig/modules/parse_amd.c +++ autofs-5.1.7/modules/parse_amd.c @@ -1391,7 +1391,7 @@ static int do_host_mount(struct autofs_p cache_unlock(source->mc); master_source_current_wait(ap->entry); - ap->entry->current = source; + ap->entry->current = instance; map_module_readlock(instance); lookup = instance->lookup;