File autofs-5.0.6-fix-submount-shutdown-race.patch of Package autofs.import5769

commit 96bdf5342ffbdb5c62daa6095f0d9ae7f4b37a58
Author: Ian Kent <ikent@redhat.com>
Date:   Thu Dec 1 15:27:17 2011 +0800

    autofs-5.0.6 - fix submount shutdown race
    
    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.

Index: autofs-5.0.5/CHANGELOG
===================================================================
--- autofs-5.0.5.orig/CHANGELOG
+++ autofs-5.0.5/CHANGELOG
@@ -87,6 +87,7 @@
 - fix fix LDAP result leaks on error paths.
 - code analysis fixes part 1.
 - fix wait for master source mutex.
+- fix submount shutdown race.
 
 03/09/2009 autofs-5.0.5
 -----------------------
Index: autofs-5.0.5/daemon/automount.c
===================================================================
--- autofs-5.0.5.orig/daemon/automount.c
+++ autofs-5.0.5/daemon/automount.c
@@ -1495,6 +1495,41 @@ static void handle_mounts_cleanup(void *
 	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;
@@ -1562,23 +1597,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);
@@ -1618,12 +1662,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);
openSUSE Build Service is sponsored by