On Fri, 2008-06-20 at 18:02 -0700, Jim Carter wrote:
> On Fri, 20 Jun 2008, Ian Kent wrote:
> 
> > So here is autofs-5.0.3-submount-shutdown-recovery-8.patch.
> > Please try it instead of revision 7.
> 
> The patch went on cleanly.  However, there was a problem in execution.
> The output was:
> 
> 17:00:14 --                   #1, chkd 0, run 0, OK 570, mtd 2, of 570
> 
> Jun 20 17:00:22 serval automount[2799]: unexpected pthreads error: -1 at 
> 901 in master.c

Ooops, I didn't pay enough attention when I read the pthread barrier man
page. That isn't actually an error return but now I'm wondering why I
haven't seen it in my test, very odd.

Let me fix it and we'll try again.

There are other problems but I need to know if this is a viable approach
before going further with it.

Try this instead.

autofs-5.0.3 - fix submount shutdown handling.

From: Ian Kent <[EMAIL PROTECTED]>

When using submount maps on a busy system autofs can hang.

This patch improves the submount shutdown logic and allows
submounts that become busy during shutdown to recover.
---

 daemon/automount.c     |   82 +++++++++++++++++++++---------------------
 daemon/direct.c        |    4 +-
 daemon/indirect.c      |   93 +++++++++++++++++++++++++++++++++++++-----------
 daemon/lookup.c        |    3 --
 daemon/state.c         |    5 ++-
 include/automount.h    |    3 +-
 include/master.h       |    3 +-
 lib/master.c           |   57 +++++++++--------------------
 modules/mount_autofs.c |    6 ++-
 9 files changed, 140 insertions(+), 116 deletions(-)


diff --git a/daemon/automount.c b/daemon/automount.c
index afbcb56..adfd42b 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1465,13 +1465,9 @@ static void handle_mounts_cleanup(void *arg)
        /* If we have been canceled then we may hold the state mutex. */
        mutex_operation_wait(&ap->state_mutex);
 
-       alarm_delete(ap);
-       st_remove_tasks(ap);
-
-       umount_autofs(ap, 1);
-
        destroy_logpri_fifo(ap);
-       master_signal_submount(ap, MASTER_SUBMNT_JOIN);
+       if (submount)
+               master_signal_submount(ap, MASTER_SUBMNT_SHUTDOWN);
        master_remove_mapent(ap->entry);
        master_free_mapent_sources(ap->entry, 1);
        master_free_mapent(ap->entry);
@@ -1533,71 +1529,75 @@ void *handle_mounts(void *arg)
        if (!ap->submount && ap->exp_timeout)
                alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq);
 
-       pthread_cleanup_push(handle_mounts_cleanup, ap);
-       pthread_setcancelstate(cancel_state, NULL);
-
        state_mutex_unlock(ap);
+       pthread_setcancelstate(cancel_state, NULL);
 
        while (ap->state != ST_SHUTDOWN) {
                if (handle_packet(ap)) {
-                       int ret, result;
+                       int ret, cur_state;
+
+                       /*
+                        * If we're a submount we need to ensure our parent
+                        * doesn't try to mount us again until our shutdown
+                        * is complete and that any outstanding mounts are
+                        * completed before we try to shutdown.
+                        */
+                       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 
&cur_state);
 
                        state_mutex_lock(ap);
+
+                       if (ap->state != ST_SHUTDOWN) {
+                               if (!ap->submount)
+                                       alarm_add(ap, ap->exp_runfreq);
+                               state_mutex_unlock(ap);
+                               /* Return to ST_READY is done immediately */
+                               st_add_task(ap, ST_READY);
+                               pthread_setcancelstate(cur_state, NULL);
+                               continue;
+                       }
+
+                       alarm_delete(ap);
+                       st_remove_tasks(ap);
+
                        /*
                         * For a direct mount map all mounts have already gone
-                        * by the time we get here.
+                        * by the time we get here and since we only ever
+                        * umount direct mounts at shutdown there is no need
+                        * to check for possible recovery.
                         */
                        if (ap->type == LKP_DIRECT) {
-                               status = 1;
+                               umount_autofs(ap, 1);
                                state_mutex_unlock(ap);
                                break;
                        }
 
                        /*
-                        * If the ioctl fails assume the kernel doesn't have
-                        * AUTOFS_IOC_ASKUMOUNT and just continue.
+                        * If umount_autofs returns non-zero it wasn't able
+                        * to complete the umount and has left the mount intact
+                        * so we can continue. This can happen if a lookup
+                        * occurs while we're trying to umount.
                         */
-                       ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result);
-                       if (ret == -1) {
+                       ret = umount_autofs(ap, 1);
+                       if (!ret) {
                                state_mutex_unlock(ap);
                                break;
                        }
 
-                       /* OK to exit */
-                       if (ap->state == ST_SHUTDOWN) {
-                               if (result) {
-                                       state_mutex_unlock(ap);
-                                       break;
-                               }
-#ifdef ENABLE_IGNORE_BUSY_MOUNTS
-                               /*
-                                * There weren't any active mounts but if the
-                                * filesystem is busy there may be a mount
-                                * request in progress so return to the ready
-                                * state unless a shutdown has been explicitly
-                                * requested.
-                                */
-                               if (ap->shutdown) {
-                                       state_mutex_unlock(ap);
-                                       break;
-                               }
-#endif
-                       }
-
                        /* Failed shutdown returns to ready */
                        warn(ap->logopt,
                             "can't shutdown: filesystem %s still busy",
                             ap->path);
                        if (!ap->submount)
                                alarm_add(ap, ap->exp_runfreq);
-                       nextstate(ap->state_pipe[1], ST_READY);
-
                        state_mutex_unlock(ap);
+                       /* Return to ST_READY is done immediately */
+                       st_add_task(ap, ST_READY);
+                       pthread_setcancelstate(cur_state, NULL);
+
                }
        }
 
-       pthread_cleanup_pop(1);
-       sched_yield();
+       handle_mounts_cleanup(ap);
 
        return NULL;
 }
diff --git a/daemon/direct.c b/daemon/direct.c
index cc03ccd..f7a78b9 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -867,12 +867,12 @@ void *expire_proc_direct(void *arg)
        if (status)
                fatal(status);
 
+       pthread_cleanup_push(expire_cleanup, &ec);
+
        status = pthread_mutex_unlock(&ea->mutex);
        if (status)
                fatal(status);
 
-       pthread_cleanup_push(expire_cleanup, &ec);
-
        left = 0;
 
        mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
diff --git a/daemon/indirect.c b/daemon/indirect.c
index c32b658..41afe30 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -233,11 +233,8 @@ int mount_autofs_indirect(struct autofs_point *ap)
        return 0;
 }
 
-int umount_autofs_indirect(struct autofs_point *ap)
+static void close_mount_fds(struct autofs_point *ap)
 {
-       char buf[MAX_ERR_BUF];
-       int ret, rv, retries;
-
        /*
         * Since submounts look after themselves the parent never knows
         * it needs to close the ioctlfd for offset mounts so we have
@@ -247,6 +244,25 @@ int umount_autofs_indirect(struct autofs_point *ap)
        if (ap->submount)
                lookup_source_close_ioctlfd(ap->parent, ap->path);
 
+       close(ap->state_pipe[0]);
+       close(ap->state_pipe[1]);
+       ap->state_pipe[0] = -1;
+       ap->state_pipe[1] = -1;
+
+       if (ap->pipefd >= 0)
+               close(ap->pipefd);
+
+       if (ap->kpipefd >= 0)
+               close(ap->kpipefd);
+
+       return;
+}
+
+int umount_autofs_indirect(struct autofs_point *ap)
+{
+       char buf[MAX_ERR_BUF];
+       int ret, rv, retries;
+
        /* If we are trying to shutdown make sure we can umount */
        rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
        if (rv == -1) {
@@ -255,23 +271,19 @@ int umount_autofs_indirect(struct autofs_point *ap)
                return 1;
        } else if (!ret) {
                error(ap->logopt, "ask umount returned busy %s", ap->path);
+#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN)
+               if (!ap->shutdown)
+                       return 1;
+#else
                return 1;
+#endif
        }
 
-       ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+       if (ap->shutdown)
+               ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+
        close(ap->ioctlfd);
        ap->ioctlfd = -1;
-       close(ap->state_pipe[0]);
-       close(ap->state_pipe[1]);
-       ap->state_pipe[0] = -1;
-       ap->state_pipe[1] = -1;
-
-       if (ap->pipefd >= 0)
-               close(ap->pipefd);
-
-       if (ap->kpipefd >= 0)
-               close(ap->kpipefd);
-
        sched_yield();
 
        retries = UMOUNT_RETRIES;
@@ -288,24 +300,61 @@ int umount_autofs_indirect(struct autofs_point *ap)
                case EINVAL:
                        error(ap->logopt,
                              "mount point %s does not exist", ap->path);
+                       close_mount_fds(ap);
                        return 0;
                        break;
                case EBUSY:
-                       error(ap->logopt,
+                       debug(ap->logopt,
                              "mount point %s is in use", ap->path);
-                       if (ap->state == ST_SHUTDOWN_FORCE)
+                       if (ap->state == ST_SHUTDOWN_FORCE) {
+                               close_mount_fds(ap);
                                goto force_umount;
-                       else
-                               return 0;
+                       } else {
+                               int cl_flags;
+                               /*
+                                * If the umount returns EBUSY there may be
+                                * a mount request in progress so we need to
+                                * recover unless we have been explicitly
+                                * asked to shutdown and configure option
+                                * ENABLE_IGNORE_BUSY_MOUNTS is enabled.
+                                */
+#ifdef ENABLE_IGNORE_BUSY_MOUNTS
+                               if (ap->shutdown) {
+                                       close_mount_fds(ap);
+                                       return 0;
+                               }
+#endif
+                               ap->ioctlfd = open(ap->path, O_RDONLY);
+                               if (ap->ioctlfd < 0) {
+                                       warn(ap->logopt,
+                                            "could not recover autofs path %s",
+                                            ap->path);
+                                       close_mount_fds(ap);
+                                       return 0;
+                               }
+
+                               if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) 
!= -1) {
+                                       cl_flags |= FD_CLOEXEC;
+                                       fcntl(ap->ioctlfd, F_SETFD, cl_flags);
+                               }
+                       }
                        break;
                case ENOTDIR:
                        error(ap->logopt, "mount point is not a directory");
+                       close_mount_fds(ap);
                        return 0;
                        break;
                }
                return 1;
        }
 
+       /*
+        * We have successfully umounted the mount so we now close
+        * the descriptors. The kernel end of the kernel pipe will
+        * have been put during the umount super block cleanup.
+        */
+       close_mount_fds(ap);
+
 force_umount:
        if (rv != 0) {
                warn(ap->logopt,
@@ -394,12 +443,12 @@ void *expire_proc_indirect(void *arg)
        if (status)
                fatal(status);
 
+       pthread_cleanup_push(expire_cleanup, &ec);
+
        status = pthread_mutex_unlock(&ea->mutex);
        if (status)
                fatal(status);
 
-       pthread_cleanup_push(expire_cleanup, &ec);
-
        left = 0;
 
        /* Get a list of real mounts and expire them if possible */
diff --git a/daemon/lookup.c b/daemon/lookup.c
index eac6053..af70fde 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -1139,8 +1139,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, 
const char *key)
        struct mapent *me;
        int ret = 0;
 
-       pthread_cleanup_push(master_source_lock_cleanup, entry);
-       master_source_readlock(entry);
        map = entry->maps;
        while (map) {
                mc = map->mc;
@@ -1158,7 +1156,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, 
const char *key)
                cache_unlock(mc);
                map = map->next;
        }
-       pthread_cleanup_pop(1);
 
        return ret;
 }
diff --git a/daemon/state.c b/daemon/state.c
index 5804707..8a1c29e 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -213,8 +213,10 @@ static unsigned int st_ready(struct autofs_point *ap)
        debug(ap->logopt,
              "st_ready(): state = %d path %s", ap->state, ap->path);
 
+       state_mutex_lock(ap);
        ap->shutdown = 0;
        ap->state = ST_READY;
+       state_mutex_unlock(ap);
 
        if (ap->submount)
                master_signal_submount(ap, MASTER_SUBMNT_CONTINUE);
@@ -677,9 +679,8 @@ int st_add_task(struct autofs_point *ap, enum states state)
 
        /* Task termination marker, poke state machine */
        if (state == ST_READY) {
-               state_mutex_lock(ap);
+               /* NOTE: no state mutex lock here */
                st_ready(ap);
-               state_mutex_unlock(ap);
 
                st_mutex_lock();
 
diff --git a/include/automount.h b/include/automount.h
index cd8ce7b..43c594d 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -457,8 +457,7 @@ struct autofs_point {
                                         * host from which to mount */
        struct autofs_point *parent;    /* Owner of mounts list for submount */
        pthread_mutex_t mounts_mutex;   /* Protect mount lists */
-       pthread_cond_t mounts_cond;     /* Submounts condition variable */
-       unsigned int mounts_signaled;   /* Submount signals task complete */
+       pthread_barrier_t submount_barrier; /* Submount completion barrier */
        struct list_head mounts;        /* List of autofs mounts at current 
level */
        unsigned int submount;          /* Is this a submount */
        unsigned int shutdown;          /* Shutdown notification */
diff --git a/include/master.h b/include/master.h
index 5f10d1f..24dddec 100644
--- a/include/master.h
+++ b/include/master.h
@@ -20,9 +20,8 @@
 #ifndef MASTER_H
 #define MASTER_H
 
-#define MASTER_SUBMNT_WAIT     0
 #define MASTER_SUBMNT_CONTINUE 1
-#define MASTER_SUBMNT_JOIN     2
+#define MASTER_SUBMNT_SHUTDOWN 2
 
 struct map_source {
        char *type;
diff --git a/lib/master.c b/lib/master.c
index 4a34dd4..11f89c3 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -113,18 +113,6 @@ int master_add_autofs_point(struct master_mapent *entry,
                return 0;
        }
 
-       status = pthread_cond_init(&ap->mounts_cond, NULL);
-       if (status) {
-               status = pthread_mutex_destroy(&ap->mounts_mutex);
-               if (status)
-                       fatal(status);
-               status = pthread_mutex_destroy(&ap->state_mutex);
-               if (status)
-                       fatal(status);
-               free(ap->path);
-               free(ap);
-               return 0;
-       }
        entry->ap = ap;
 
        return 1;
@@ -145,10 +133,6 @@ void master_free_autofs_point(struct autofs_point *ap)
        if (status)
                fatal(status);
 
-       status = pthread_cond_destroy(&ap->mounts_cond);
-       if (status)
-               fatal(status);
-
        free(ap->path);
        free(ap);
 }
@@ -878,24 +862,19 @@ int master_notify_submount(struct autofs_point *ap, const 
char *path, enum state
 
                nextstate(this->state_pipe[1], state);
 
+               status = pthread_barrier_init(&this->submount_barrier, NULL, 2);
+               if (status)
+                       fatal(status);
+
                state_mutex_unlock(this);
 
-               thid = this->thid;
-               ap->mounts_signaled = MASTER_SUBMNT_WAIT;
-               while (ap->mounts_signaled == MASTER_SUBMNT_WAIT) {
-                       status = pthread_cond_wait(&ap->mounts_cond, 
&ap->mounts_mutex);
-                       if (status)
-                               fatal(status);
-               }
+               mounts_mutex_unlock(ap);
 
-               if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) {
-                       status = pthread_join(thid, NULL);
-                       if (status)
-                               fatal(status);
-               } else
-                       ret = 0;
+               status = pthread_barrier_wait(&this->submount_barrier);
+               if (status && status != PTHREAD_BARRIER_SERIAL_THREAD)
+                       fatal(status);
 
-               break;
+               return ret;
        }
 
        mounts_mutex_unlock(ap);
@@ -903,28 +882,27 @@ int master_notify_submount(struct autofs_point *ap, const 
char *path, enum state
        return ret;
 }
 
-void master_signal_submount(struct autofs_point *ap, unsigned int join)
+/* Parent ap->mounts_mutex must already be held if joining on shutdown */
+void master_signal_submount(struct autofs_point *ap, unsigned int action)
 {
        int status;
 
        if (!ap->parent || !ap->submount)
                return;
 
-       mounts_mutex_lock(ap->parent);
-
-       ap->parent->mounts_signaled = join;
-
-       if (join == MASTER_SUBMNT_JOIN) {
+       if (action == MASTER_SUBMNT_SHUTDOWN) {
                /* We are finishing up */
                ap->parent->submnt_count--;
                list_del(&ap->mounts);
        }
 
-       status = pthread_cond_signal(&ap->parent->mounts_cond);
-       if (status)
+       status = pthread_barrier_wait(&ap->submount_barrier);
+       if (status && status != PTHREAD_BARRIER_SERIAL_THREAD)
                fatal(status);
 
-       mounts_mutex_unlock(ap->parent);
+       status = pthread_barrier_destroy(&ap->submount_barrier);
+       if (status)
+               fatal(status);
 
        return;
 }
@@ -970,6 +948,7 @@ void master_notify_state_change(struct master *master, int 
sig)
                        if (ap->state != ST_SHUTDOWN_FORCE &&
                            ap->state != ST_SHUTDOWN_PENDING) {
                                next = ST_SHUTDOWN_FORCE;
+                               ap->shutdown = 1;
                                nextstate(state_pipe, next);
                        }
                        break;
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index 356fb14..d1856e3 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -228,7 +228,7 @@ int mount_mount(struct autofs_point *ap, const char *root, 
const char *name,
        suc.done = 0;
        suc.status = 0;
 
-       if (pthread_create(&thid, NULL, handle_mounts, nap)) {
+       if (pthread_create(&thid, &thread_attr, handle_mounts, nap)) {
                crit(ap->logopt,
                     MODPREFIX
                     "failed to create mount handler thread for %s",
@@ -266,12 +266,12 @@ int mount_mount(struct autofs_point *ap, const char 
*root, const char *name,
        ap->submnt_count++;
        list_add(&nap->mounts, &ap->submounts);
 
-       mounts_mutex_unlock(ap);
-
        status = pthread_mutex_unlock(&suc.mutex);
        if (status)
                fatal(status);
 
+       mounts_mutex_unlock(ap);
+
        return 0;
 }
 


_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs

Reply via email to