autofs-5.0.6 - fix remount deadlock From: Ian Kent When reconstructing the mount tree upon restart a writelock to the map entry cache cannot be taken when parsing a direct map entry because a readlock is already held higher up in the call tree. In the place this is done it isn't be necessary to alter the direct map entries in the cache. Also, it shouldn't be necessary to delete existing multi-mount cache entries to avoid a duplicate multi-mount entry error return. The check for a duplicate can be done in the cache handling functions. --- CHANGELOG | 1 + lib/cache.c | 8 ++++--- modules/parse_sun.c | 60 ++++++++++++++++++++++++++------------------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b6b08c..de4ca14 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,7 @@ - fix nfs4 contacts portmap. - make autofs wait longer for shutdown completion. - fix sss map age not updated. +- fix remount deadlock. 28/06/2011 autofs-5.0.6 ----------------------- diff --git a/lib/cache.c b/lib/cache.c index 9acf736..3464e7d 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -658,10 +658,12 @@ int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key, return CHE_FAIL; me = cache_lookup_distinct(mc, key); - if (me && me != owner) - return CHE_DUPLICATE; + if (me && me->age == age) { + if (me != owner) + return CHE_DUPLICATE; + } - ret = cache_add(mc, owner->source, key, mapent, age); + ret = cache_update(mc, owner->source, key, mapent, age); if (ret == CHE_FAIL) { warn(logopt, "failed to add key %s to cache", key); return CHE_FAIL; diff --git a/modules/parse_sun.c b/modules/parse_sun.c index d7e74e2..8b0f8b6 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -843,12 +843,17 @@ add_offset_entry(struct autofs_point *ap, const char *name, strcpy(m_mapent, loc); ret = cache_add_offset(mc, name, m_key, m_mapent, age); - if (ret == CHE_OK) + if (ret == CHE_DUPLICATE) + warn(ap->logopt, MODPREFIX + "syntax error or duplicate offset %s -> %s", path, loc); + else if (ret == CHE_FAIL) + debug(ap->logopt, MODPREFIX + "failed to add multi-mount offset %s -> %s", path, m_mapent); + else { + ret = CHE_OK; debug(ap->logopt, MODPREFIX "added multi-mount offset %s -> %s", path, m_mapent); - else - warn(ap->logopt, MODPREFIX - "syntax error or duplicate offset %s -> %s", path, loc); + } return ret; } @@ -1410,7 +1415,7 @@ int parse_mount(struct autofs_point *ap, const char *name, char buf[MAX_ERR_BUF]; struct map_source *source; struct mapent_cache *mc; - struct mapent *me = NULL; + struct mapent *me; char *pmapent, *options; const char *p; int mapent_len, rv = 0; @@ -1561,33 +1566,28 @@ int parse_mount(struct autofs_point *ap, const char *name, strcat(m_root, name); } - cache_writelock(mc); - me = cache_lookup_distinct(mc, name); - if (!me) { - int ret; - /* - * Not in the cache, perhaps it's a program map - * or one that doesn't support enumeration - */ - ret = cache_add(mc, source, name, mapent, time(NULL)); - if (ret == CHE_FAIL) { - cache_unlock(mc); - free(options); - return 1; + /* + * Can't take the write lock for direct mount entries here + * but they should always be present in the map entry cache. + */ + if (ap->type == LKP_INDIRECT) { + cache_writelock(mc); + me = cache_lookup_distinct(mc, name); + if (!me) { + int ret; + /* + * Not in the cache, perhaps it's a program map + * or one that doesn't support enumeration. + */ + ret = cache_add(mc, source, name, mapent, age); + if (ret == CHE_FAIL) { + cache_unlock(mc); + free(options); + return 1; + } } - } else { - /* - * If the entry exists it must not have any existing - * multi-mount subordinate entries since we are - * mounting this afresh. We need to do this to allow - * us to fail on the check for duplicate offsets in - * we don't know when submounts go away. - */ - cache_multi_writelock(me); - cache_delete_offset_list(mc, name); - cache_multi_unlock(me); + cache_unlock(mc); } - cache_unlock(mc); cache_readlock(mc); me = cache_lookup_distinct(mc, name);