autofs/autofs-5.0.6-fix-submount-shutdown-race.patch
Ian Kent ca38f0b091 * Tue Nov 8 2011 Ian Kent <ikent@redhat.com> - 1:5.0.6-3
- improve mount location error reporting.
- fix paged query more results check.
- fix dumpmaps not reading maps.
- fix result null check in read_one_map().
- Fix LDAP result leaks on error paths.
- code analysis fixes 1.
- fix not bind mounting local filesystem.
- update dir map-type patch for changed patch order.
- fix wait for master source mutex.
- fix submount shutdown race
- fix fix map source check in file lookup.
- add disable move mount configure option.
2011-11-08 13:13:22 +08:00

142 lines
3.9 KiB
Diff

autofs-5.0.6 - fix submount shutdown race
From: Ian Kent <ikent@redhat.com>
Shutdown of submounts is problematic because the kernel doesn't
know when they are going away and so cannot block path walks
while they shut down. After aquiring the locks that cause mount
requests to wait, the daemon checks if the submount is active before
finally umounting it. If the mount is found to be busy the shutdown
is abandoned and the submount returned to a ready state.
But, if a mount request arrives at the same time as the daemon is
attempting to aquire these locks pthreads appears to become confused
and blocks. So change to using the try version of the lock call and
handling the return appropriately.
---
CHANGELOG | 1 +
daemon/automount.c | 76 ++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 60 insertions(+), 17 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index cac450f..cb9ac75 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,7 @@
- fix not bind mounting local filesystem.
- add "dir" map-type.
- fix wait for master source mutex.
+- fix submount shutdown race.
28/06/2011 autofs-5.0.6
-----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 376e965..4f3151f 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1495,6 +1495,41 @@ static void handle_mounts_cleanup(void *arg)
return;
}
+static int submount_source_writelock_nested(struct autofs_point *ap)
+{
+ struct autofs_point *parent = ap->parent;
+ int status;
+
+ status = pthread_rwlock_trywrlock(&parent->entry->source_lock);
+ if (status)
+ goto done;
+
+ mounts_mutex_lock(parent);
+
+ status = pthread_rwlock_trywrlock(&ap->entry->source_lock);
+ if (status) {
+ mounts_mutex_unlock(parent);
+ master_source_unlock(parent->entry);
+ }
+
+done:
+ if (status && status != EBUSY) {
+ logmsg("submount nested master_mapent source write lock failed");
+ fatal(status);
+ }
+
+ return status;
+}
+
+static void submount_source_unlock_nested(struct autofs_point *ap)
+{
+ struct autofs_point *parent = ap->parent;
+
+ master_source_unlock(ap->entry);
+ mounts_mutex_unlock(parent);
+ master_source_unlock(parent->entry);
+}
+
void *handle_mounts(void *arg)
{
struct startup_cond *suc;
@@ -1565,23 +1600,32 @@ void *handle_mounts(void *arg)
master_mutex_lock();
if (ap->submount) {
- master_source_writelock(ap->parent->entry);
- mounts_mutex_lock(ap->parent);
- }
-
- master_source_writelock(ap->entry);
+ /*
+ * If a mount request arrives before the locks are
+ * aquired just return to ready state.
+ */
+ ret = submount_source_writelock_nested(ap);
+ if (ret) {
+ warn(ap->logopt,
+ "can't shutdown submount: mount in progress");
+ /* Return to ST_READY is done immediately */
+ st_add_task(ap, ST_READY);
+ master_mutex_unlock();
+ pthread_setcancelstate(cur_state, NULL);
+ continue;
+ }
+ } else
+ master_source_writelock(ap->entry);
if (ap->state != ST_SHUTDOWN) {
if (!ap->submount)
alarm_add(ap, ap->exp_runfreq);
/* Return to ST_READY is done immediately */
st_add_task(ap, ST_READY);
- master_source_unlock(ap->entry);
- if (ap->submount) {
- mounts_mutex_unlock(ap->parent);
- master_source_unlock(ap->parent->entry);
- }
-
+ if (ap->submount)
+ submount_source_unlock_nested(ap);
+ else
+ master_source_unlock(ap->entry);
master_mutex_unlock();
pthread_setcancelstate(cur_state, NULL);
@@ -1621,12 +1665,10 @@ void *handle_mounts(void *arg)
alarm_add(ap, ap->exp_runfreq);
/* Return to ST_READY is done immediately */
st_add_task(ap, ST_READY);
- master_source_unlock(ap->entry);
- if (ap->submount) {
- mounts_mutex_unlock(ap->parent);
- master_source_unlock(ap->parent->entry);
- }
-
+ if (ap->submount)
+ submount_source_unlock_nested(ap);
+ else
+ master_source_unlock(ap->entry);
master_mutex_unlock();
pthread_setcancelstate(cur_state, NULL);