autofs/SOURCES/autofs-5.1.8-fix-deadlock-i...

142 lines
4.2 KiB
Diff

autofs-5.1.8 - fix deadlock in lookups
From: Ian Kent <raven@themaw.net>
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 <raven@themaw.net>
---
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.4.orig/CHANGELOG
+++ autofs-5.1.4/CHANGELOG
@@ -110,6 +110,7 @@
- don't immediately call function when waiting.
- fix return status of mount_autofs().
- don't close lookup at umount.
+- fix deadlock in lookups.
xx/xx/2018 autofs-5.1.5
- fix flag file permission.
--- autofs-5.1.4.orig/daemon/lookup.c
+++ autofs-5.1.4/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.4.orig/daemon/master.c
+++ autofs-5.1.4/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.4.orig/include/master.h
+++ autofs-5.1.4/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.4.orig/modules/parse_amd.c
+++ autofs-5.1.4/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;