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);