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