diff --git a/CHANGELOG b/CHANGELOG
index b0a255a..3baff69 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@
with various combinations of submounts (still broken).
- cthon fix expire of various forms of nested mounts.
- cthon fix some shutdown races.
+- cthon corrections for above patch and fix shutdown expire.
13/7/2006 autofs-5.0.1 rc1
--------------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 35d443c..ff05ae2 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -198,8 +198,6 @@ static int walk_tree(const char *base, i
while (n--) {
int ret, size;
- sched_yield();
-
if (strcmp(de[n]->d_name, ".") == 0 ||
strcmp(de[n]->d_name, "..") == 0) {
free(de[n]);
@@ -387,7 +385,7 @@ int umount_multi(struct autofs_point *ap
me = lookup_source_mapent(ap, ind_key);
if (!me) {
- warn(ap->logopt, "no mounts found under %s", path);
+ warn(ap->logopt, "map entry not found for %s", path);
return 0;
}
}
@@ -421,7 +419,7 @@ int umount_multi(struct autofs_point *ap
}
cache_unlock(me->source->mc);
- if (left || is_autofs_fs || ap->submount)
+ if (left || is_autofs_fs)
return left;
/*
@@ -1034,10 +1032,8 @@ static void handle_mounts_cleanup(void *
st_remove_tasks(ap);
umount_autofs(ap, 1);
- if (submount)
- master_signal_submount(ap, MASTER_SUBMNT_JOIN);
- else
- master_remove_mapent(ap->entry);
+ master_signal_submount(ap, MASTER_SUBMNT_JOIN);
+ master_remove_mapent(ap->entry);
master_free_mapent_sources(ap->entry, 1);
master_free_mapent(ap->entry);
@@ -1161,8 +1157,8 @@ void *handle_mounts(void *arg)
* So, the solution is a recipe for disaster.
* Hope we don't get a really busy system!
*/
- sleep(1);
- /* sched_yield(); */
+ /*sleep(1);*/
+ sched_yield();
return NULL;
}
diff --git a/daemon/direct.c b/daemon/direct.c
index a2aea9c..c155617 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -112,13 +112,13 @@ static int autofs_init_direct(struct aut
int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
{
char buf[MAX_ERR_BUF];
- int ioctlfd, rv, left;
+ int ioctlfd, rv, left, retries;
left = umount_multi(ap, me->key, 1);
if (left) {
warn(ap->logopt, "could not unmount %d dirs under %s",
left, me->key);
- return -1;
+ return 1;
}
if (me->ioctlfd != -1) {
@@ -161,9 +161,19 @@ int do_umount_autofs_direct(struct autof
error(ap->logopt,
"couldn't get ioctl fd for offset %s", me->key);
debug(ap->logopt, "open: %s", estr);
+ return 1;
+ }
+
+ sched_yield();
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(me->key)) == -1 && retries--) {
+ struct timespec tm = {0, 100000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
}
- rv = umount(me->key);
if (rv == -1) {
switch (errno) {
case ENOENT:
@@ -230,7 +240,6 @@ int umount_autofs_direct(struct autofs_p
cache_readlock(mc);
me = cache_enumerate(mc, NULL);
while (me) {
- sched_yield();
/* TODO: check return, locking me */
do_umount_autofs_direct(ap, mnts, me);
me = cache_enumerate(mc, me);
@@ -491,7 +500,7 @@ int mount_autofs_direct(struct autofs_po
int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
{
char buf[MAX_ERR_BUF];
- int ioctlfd, rv = 1;
+ int ioctlfd, rv = 1, retries;
if (me->ioctlfd != -1) {
if (is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) {
@@ -543,7 +552,16 @@ int umount_autofs_offset(struct autofs_p
goto force_umount;
}
- rv = umount(me->key);
+ sched_yield();
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(me->key)) == -1 && retries--) {
+ struct timespec tm = {0, 100000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
+ }
+
if (rv == -1) {
switch (errno) {
case ENOENT:
@@ -703,6 +721,49 @@ out_err:
return -1;
}
+static int expire_direct(int ioctlfd, const char *path, unsigned int when, int count, unsigned int logopt)
+{
+ char *estr, buf[MAX_ERR_BUF];
+ int ret, retries = count;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+ int busy = 0;
+
+ ret = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &busy);
+ if (ret == -1) {
+ /* Mount has gone away */
+ if (errno == EBADF)
+ return 1;
+
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(logopt, "ioctl failed: %s", estr);
+ return 0;
+ }
+
+ /* No need to go further */
+ if (busy)
+ return 0;
+
+ sched_yield();
+
+ /* Ggenerate expire message for the mount. */
+ ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
+ if (ret == -1) {
+ /* Mount has gone away */
+ if (errno == EBADF)
+ return 1;
+
+ /* Need to wait for the kernel ? */
+ if (errno != EAGAIN)
+ return 0;
+ }
+ nanosleep(&tm, NULL);
+ }
+
+ return 1;
+}
+
void *expire_proc_direct(void *arg)
{
struct map_source *map;
@@ -710,7 +771,7 @@ void *expire_proc_direct(void *arg)
struct expire_args *ea;
struct autofs_point *ap;
struct mapent_cache *mc = NULL;
- struct mapent *ro, *me = NULL;
+ struct mapent *me = NULL;
unsigned int now;
int ioctlfd = -1;
int status, ret;
@@ -751,11 +812,9 @@ void *expire_proc_direct(void *arg)
continue;
/* Skip offsets */
- if (strstr(next->opts, "offsets"))
+ if (strstr(next->opts, "offset"))
continue;
- sched_yield();
-
/*
* All direct mounts must be present in the map
* entry cache.
@@ -787,48 +846,16 @@ void *expire_proc_direct(void *arg)
debug(ap->logopt, "send expire to trigger %s", next->path);
- /* Finally generate an expire message for the direct mount. */
- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &now);
- if (ret < 0 && errno != EAGAIN) {
+ ret = expire_direct(ioctlfd, next->path,
+ now, EXPIRE_RETRIES, ap->logopt);
+ if (!ret) {
debug(ap->logopt,
- "failed to expire mount %s", next->path);
- ea->status = 1;
+ "failed to expire mount %s", next->path);
+ ea->status++;
}
}
free_mnt_list(mnts);
- pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
- master_source_readlock(ap->entry);
- map = ap->entry->first;
- while (map) {
- mc = map->mc;
- pthread_cleanup_push(cache_lock_cleanup, mc);
- cache_readlock(mc);
- me = cache_enumerate(mc, NULL);
- while (me) {
- sched_yield();
-
- if (me->ioctlfd >= 0)
- /* Real mounts have an open ioctl fd */
- ioctlfd = me->ioctlfd;
- else {
- me = cache_enumerate(mc, me);
- continue;
- }
-
- if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
- if (!ret) {
- ea->status = 1;
- break;
- }
- }
- me = cache_enumerate(mc, me);
- }
- pthread_cleanup_pop(1);
- map = map->next;
- }
-
- pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
return NULL;
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 406bf72..af84629 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -281,8 +281,7 @@ int mount_autofs_indirect(struct autofs_
int umount_autofs_indirect(struct autofs_point *ap)
{
char buf[MAX_ERR_BUF];
- struct stat st;
- int ret, rv;
+ int ret, rv, retries;
/*
* Since submounts look after themselves the parent never knows
@@ -318,7 +317,16 @@ int umount_autofs_indirect(struct autofs
if (ap->kpipefd >= 0)
close(ap->kpipefd);
- rv = umount(ap->path);
+ sched_yield();
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(ap->path)) == -1 && retries--) {
+ struct timespec tm = {0, 100000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
+ }
+
if (rv == -1) {
switch (errno) {
case ENOENT:
@@ -356,6 +364,50 @@ force_umount:
return rv;
}
+static int expire_indirect(int ioctlfd, const char *path, unsigned int when, int count, unsigned int logopt)
+{
+ char *estr, buf[MAX_ERR_BUF];
+ int ret, retries = count;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+ int busy = 0;
+
+ ret = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &busy);
+ if (ret == -1) {
+ /* Mount has gone away */
+ if (errno == EBADF)
+ return 1;
+
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(logopt, "ioctl failed: %s", estr);
+ return 0;
+ }
+
+ /* No need to go further */
+ if (busy)
+ return 0;
+
+ sched_yield();
+
+ /* Ggenerate expire message for the mount. */
+ ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
+ if (ret == -1) {
+ /* Mount has gone away */
+ if (errno == EBADF)
+ return 1;
+
+ /* Need to wait for the kernel ? */
+ if (errno != EAGAIN)
+ return 0;
+ }
+
+ nanosleep(&tm, NULL);
+ }
+
+ return 1;
+}
+
void *expire_proc_indirect(void *arg)
{
struct map_source *map;
@@ -368,7 +420,6 @@ void *expire_proc_indirect(void *arg)
int offsets, submnts, count;
int ioctlfd, limit;
int status, ret;
- char buf[MAX_ERR_BUF];
ea = (struct expire_args *) arg;
@@ -407,8 +458,6 @@ void *expire_proc_indirect(void *arg)
if (!strcmp(next->fs_type, "autofs"))
continue;
- sched_yield();
-
/*
* If the mount corresponds to an offset trigger then
* the key is the path, otherwise it's the last component.
@@ -452,14 +501,13 @@ void *expire_proc_indirect(void *arg)
debug(ap->logopt, "expire %s", next->path);
- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_MULTI, &now);
- if (ret < 0 && errno != EAGAIN) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- warn(ap->logopt,
- "failed to expire mount %s:", next->path, estr);
- ea->status = 1;
+ ret = expire_indirect(ioctlfd, next->path,
+ now, EXPIRE_RETRIES, ap->logopt);
+ if (!ret) {
+ debug(ap->logopt,
+ "failed to expire mount %s", next->path);
+ ea->status++;
}
-
}
free_mnt_list(mnts);
@@ -469,17 +517,11 @@ void *expire_proc_indirect(void *arg)
* umount them here.
*/
limit = count_mounts(ap, ap->path);
- while (limit--) {
- ret = ioctl(ap->ioctlfd, AUTOFS_IOC_EXPIRE_MULTI, &now);
- if (ret < 0) {
- if (errno == EAGAIN)
- break;
- warn(ap->logopt,
- "failed to expire offsets under %s",
- ap->path);
- ea->status = 1;
- break;
- }
+ ret = expire_indirect(ap->ioctlfd, ap->path, now, limit, ap->logopt);
+ if (!ret) {
+ debug(ap->logopt,
+ "failed to expire offsets under %s", ap->path);
+ ea->status++;
}
count = offsets = submnts = 0;
diff --git a/include/automount.h b/include/automount.h
index 4c4d507..800e7b0 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -123,6 +123,8 @@ #define CHE_DUPLICATE 0x0020
#define HASHSIZE 77
#define NEGATIVE_TIMEOUT 10
+#define UMOUNT_RETRIES 25
+#define EXPIRE_RETRIES 15
struct mapent_cache {
pthread_rwlock_t rwlock;
diff --git a/lib/master.c b/lib/master.c
index bcda72a..d76ffac 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -131,13 +131,6 @@ void master_free_autofs_point(struct aut
if (!ap)
return;
- if (ap->submount) {
- mounts_mutex_lock(ap);
- ap->parent->submnt_count--;
- list_del(&ap->mounts);
- mounts_mutex_unlock(ap);
- }
-
status = pthread_mutex_destroy(&ap->state_mutex);
if (status)
fatal(status);
@@ -631,6 +624,9 @@ void master_add_mapent(struct master *ma
void master_remove_mapent(struct master_mapent *entry)
{
+ if (entry->ap->submount)
+ return;
+
master_mutex_lock();
if (!list_empty(&entry->list))
list_del_init(&entry->list);
@@ -739,13 +735,17 @@ int master_read_master(struct master *ma
return 1;
}
-static void notify_submounts(struct autofs_point *ap, enum states state)
+void master_notify_submounts(struct autofs_point *ap, enum states state)
{
struct list_head *head, *p;
struct autofs_point *this;
pthread_t thid;
int status;
+ /* Initiate from master entries only */
+ if (ap->submount || list_empty(&ap->submounts))
+ return;
+
mounts_mutex_lock(ap);
head = &ap->submounts;
@@ -756,7 +756,7 @@ static void notify_submounts(struct auto
p = p->next;
if (!list_empty(&this->submounts))
- notify_submounts(this, state);
+ master_notify_submounts(this, state);
state_mutex_lock(this);
@@ -776,11 +776,9 @@ static void notify_submounts(struct auto
if (status)
fatal(status);
if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) {
- mounts_mutex_unlock(ap);
status = pthread_join(thid, NULL);
if (status)
fatal(status);
- mounts_mutex_lock(ap);
}
}
}
@@ -790,30 +788,23 @@ static void notify_submounts(struct auto
return;
}
-void master_notify_submounts(struct autofs_point *ap, enum states state)
-{
- /* Initiate from master entries only */
- if (ap->submount || list_empty(&ap->submounts))
- return;
- master_mutex_lock();
- notify_submounts(ap, state);
- master_mutex_unlock();
- return;
-}
-
void master_signal_submount(struct autofs_point *ap, unsigned int join)
{
int status;
- if (!ap->parent)
+ if (!ap->parent || !ap->submount)
return;
mounts_mutex_lock(ap->parent);
- if (join)
+ if (join) {
+ /* We are finishing up */
+ ap->parent->submnt_count--;
+ list_del(&ap->mounts);
ap->parent->mounts_signaled = 1;
- else
+ } else
ap->parent->mounts_signaled = 2;
+
status = pthread_cond_signal(&ap->parent->mounts_cond);
if (status)
fatal(status);