diff --git a/CHANGELOG b/CHANGELOG index fc939ad..1969912 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ - expire individual submounts. - add ino_index locking. - fix nested submount expiring away when pwd is base of submount. +- more expire re-work to cope better with shutdown following cthon tests. 13/7/2006 autofs-5.0.1 rc1 -------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index cc6e9e0..446c184 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -304,12 +304,12 @@ static int counter_fn(const char *file, } /* Count mounted filesystems and symlinks */ -int count_mounts(struct autofs_point *ap, const char *path) +int count_mounts(const char *path, dev_t dev) { struct counter_args counter; counter.count = 0; - counter.dev = ap->dev; + counter.dev = dev; if (walk_tree(path, counter_fn, 0, &counter) == -1) return -1; @@ -366,26 +366,12 @@ static void update_map_cache(struct auto return; } -/* umount all filesystems mounted under path. If incl is true, then - it also tries to umount path itself */ -int umount_multi(struct autofs_point *ap, const char *path, int incl) +static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsigned int is_autofs_fs) { struct mapent_cache *mc; struct mapent *me; - struct statfs fs; - int is_autofs_fs; - int ret, left; unsigned int is_mm_root; - - debug(ap->logopt, "path %s incl %d", path, incl); - - ret = statfs(path, &fs); - if (ret == -1) { - error(ap->logopt, "could not stat fs of %s", path); - return 1; - } - - is_autofs_fs = fs.f_type == AUTOFS_SUPER_MAGIC ? 1 : 0; + int left; me = lookup_source_mapent(ap, path, LKP_DISTINCT); if (!me) { @@ -395,74 +381,104 @@ int umount_multi(struct autofs_point *ap if (ind_key) ind_key++; - me = lookup_source_mapent(ap, ind_key, LKP_DISTINCT); - if (!me) { - warn(ap->logopt, "map entry not found for %s", path); + me = lookup_source_mapent(ap, ind_key, LKP_NORMAL); + if (!me) return 0; - } } - cache_multi_lock(me->parent); - mc = me->source->mc; is_mm_root = (me->multi == me); left = 0; if (me->multi) { - struct autofs_point *oap = ap; char *root, *base; + size_t ap_len; - if (ap->submount) - oap = ap->parent; + ap_len = strlen(ap->path); - if (is_mm_root && !strchr(me->key, '/')) { + if (!strchr(me->multi->key, '/')) { /* Indirect multi-mount root */ - root = alloca(strlen(ap->path) + strlen(me->key) + 2); + root = alloca(ap_len + strlen(me->multi->key) + 2); strcpy(root, ap->path); strcat(root, "/"); - strcat(root, me->key); - base = NULL; - } else { + strcat(root, me->multi->key); + } else root = me->multi->key; + + if (is_mm_root) + base = NULL; + else base = me->key + strlen(root); - } - if (umount_multi_triggers(oap, root, me, base)) { + /* Lock the closest parent nesting point for umount */ + cache_multi_lock(me->parent); + if (umount_multi_triggers(ap, root, me, base)) { warn(ap->logopt, "could not umount some offsets under %s", path); left++; } + cache_multi_unlock(me->parent); } - if (left || is_autofs_fs) { - cache_multi_unlock(me->parent); - cache_unlock(mc); + cache_unlock(mc); + + if (left || is_autofs_fs) return left; - } /* * If this is the root of a multi-mount we've had to umount - * it already to ensure it's ok to remove any offset triggers + * it already to ensure it's ok to remove any offset triggers. */ - if (!is_mm_root) { + if (!is_mm_root && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { msg("unmounting dir = %s", path); - if (umount_ent(ap, path)) { warn(ap->logopt, "could not umount dir %s", path); left++; } } + return left; +} + +/* umount all filesystems mounted under path. If incl is true, then + it also tries to umount path itself */ +int umount_multi(struct autofs_point *ap, const char *path, int incl) +{ + struct statfs fs; + int is_autofs_fs; + int ret, left; + + debug(ap->logopt, "path %s incl %d", path, incl); + + ret = statfs(path, &fs); + if (ret == -1) { + error(ap->logopt, "could not stat fs of %s", path); + return 1; + } + + is_autofs_fs = fs.f_type == AUTOFS_SUPER_MAGIC ? 1 : 0; + + left = 0; + + /* + * If we are a submount we need to umount any offsets our + * parent may have mounted over top of us. + */ + /*if (ap->submount) + left += umount_subtree_mounts(ap->parent, path, is_autofs_fs);*/ + + left += umount_subtree_mounts(ap, path, is_autofs_fs); + + if (left || is_autofs_fs) + return left; + /* Delete detritus like unwanted mountpoints and symlinks */ if (left == 0) { update_map_cache(ap, path); check_rm_dirs(ap, path, incl); } - cache_multi_unlock(me->parent); - cache_unlock(mc); - return left; } diff --git a/daemon/direct.c b/daemon/direct.c index b9c0f04..18b56fe 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -33,6 +33,7 @@ #include #include #include #include +#include #include #include #include @@ -114,7 +115,7 @@ int do_umount_autofs_direct(struct autof char buf[MAX_ERR_BUF]; int ioctlfd, rv, left, retries; - left = umount_multi(ap, me->key, 1); + left = umount_multi(ap, me->key, 0); if (left) { warn(ap->logopt, "could not unmount %d dirs under %s", left, me->key); @@ -258,9 +259,9 @@ static int unlink_mount_tree(struct auto struct list_head *p; int rv, ret; pid_t pgrp = getpgrp(); - char spgrp[10]; + char spgrp[20]; - sprintf(spgrp, "%d", pgrp); + sprintf(spgrp, "pgrp=%d", pgrp); ret = 1; list_for_each(p, list) { @@ -727,7 +728,17 @@ out_err: static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt) { - int ret, retries = EXPIRE_RETRIES; + char buf[MAX_ERR_BUF]; + int ret, retries; + struct stat st; + + if (fstat(ioctlfd, &st) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(logopt, "fstat failed: %s", estr); + return 0; + } + + retries = (count_mounts(path, st.st_dev) + 1) * EXPIRE_RETRIES; while (retries--) { struct timespec tm = {0, 100000000}; @@ -747,7 +758,7 @@ static int expire_direct(int ioctlfd, co nanosleep(&tm, NULL); } - return 1; + return (retries >= 0); } void *expire_proc_direct(void *arg) @@ -824,10 +835,8 @@ void *expire_proc_direct(void *arg) debug(ap->logopt, "send expire to trigger %s", next->path); ret = expire_direct(ioctlfd, next->path, now, ap->logopt); - if (!ret) { - msg("mount apparently busy %s", next->path); + if (!ret) ea->status++; - } } free_mnt_list(mnts); diff --git a/daemon/indirect.c b/daemon/indirect.c index dadb9ee..e04f164 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -82,9 +82,9 @@ static int unlink_mount_tree(struct auto struct mnt_list *this; int rv, ret; pid_t pgrp = getpgrp(); - char spgrp[10]; + char spgrp[20]; - sprintf(spgrp, "%d", pgrp); + sprintf(spgrp, "pgrp=%d", pgrp); ret = 1; this = mnts; @@ -367,9 +367,19 @@ force_umount: return rv; } -static int expire_indirect(int ioctlfd, const char *path, unsigned int when, unsigned int count, unsigned int logopt) +static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when) { - int ret, retries = count; + char buf[MAX_ERR_BUF]; + int ret, retries; + struct stat st; + + if (fstat(ioctlfd, &st) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, "fstat failed: %s", estr); + return 0; + } + + retries = (count_mounts(path, st.st_dev) + 1) * EXPIRE_RETRIES; while (retries--) { struct timespec tm = {0, 100000000}; @@ -389,7 +399,7 @@ static int expire_indirect(int ioctlfd, nanosleep(&tm, NULL); } - return 1; + return (retries >= 0); } void *expire_proc_indirect(void *arg) @@ -400,9 +410,8 @@ void *expire_proc_indirect(void *arg) struct expire_args *ea; unsigned int now; int offsets, submnts, count; - int ioctlfd, limit; + int ioctlfd; int status, ret; - unsigned int retries = EXPIRE_RETRIES; ea = (struct expire_args *) arg; @@ -477,11 +486,9 @@ void *expire_proc_indirect(void *arg) debug(ap->logopt, "expire %s", next->path); - ret = expire_indirect(ioctlfd, next->path, now, retries, ap->logopt); - if (!ret) { - msg("mount apparently busy %s", next->path); + ret = expire_indirect(ap, ioctlfd, next->path, now); + if (!ret) ea->status++; - } } free_mnt_list(mnts); @@ -490,12 +497,10 @@ void *expire_proc_indirect(void *arg) * have some offset mounts with no '/' offset so we need to * umount them here. */ - limit = count_mounts(ap, ap->path) * 2; - 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++; + if (mnts) { + ret = expire_indirect(ap, ap->ioctlfd, ap->path, now); + if (!ret) + ea->status++; } count = offsets = submnts = 0; @@ -527,7 +532,7 @@ void *expire_proc_indirect(void *arg) /* If we are trying to shutdown make sure we can umount */ if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { if (!ret) { - warn(ap->logopt, "mount still busy %s", ap->path); + msg("mount still busy %s", ap->path); ea->status++; } } diff --git a/daemon/lookup.c b/daemon/lookup.c index aeda909..dd620cf 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -969,7 +969,7 @@ next: } /* Return with cache readlock held */ -struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type) +struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type) { struct master_mapent *entry = ap->entry; struct map_source *map; @@ -980,12 +980,49 @@ struct mapent *lookup_source_mapent(stru master_source_readlock(entry); map = entry->first; while (map) { + /* + * Only consider map sources that have been read since + * the map entry was last updated. + */ + if (ap->entry->age > map->age) { + map = map->next; + continue; + } + mc = map->mc; cache_readlock(mc); if (type == LKP_DISTINCT) me = cache_lookup_distinct(mc, key); else + me = cache_lookup(mc, key); + if (me) + break; + cache_unlock(mc); + map = map->next; + } + pthread_cleanup_pop(1); + + return me; +} + +/* Return with cache readlock held */ +struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type) +{ + struct master_mapent *entry = ap->entry; + struct map_source *map; + struct mapent_cache *mc; + struct mapent *me = NULL; + + pthread_cleanup_push(master_source_lock_cleanup, entry); + master_source_readlock(entry); + map = entry->first; + while (map) { + mc = map->mc; + cache_readlock(mc); + if (type == LKP_DISTINCT) me = cache_lookup_distinct(mc, key); + else + me = cache_lookup(mc, key); if (me) break; cache_unlock(mc); @@ -1012,8 +1049,10 @@ int lookup_source_close_ioctlfd(struct a cache_readlock(mc); me = cache_lookup_distinct(mc, key); if (me) { - close(me->ioctlfd); - me->ioctlfd = -1; + if (me->ioctlfd != -1) { + close(me->ioctlfd); + me->ioctlfd = -1; + } cache_unlock(mc); ret = 1; break; diff --git a/include/automount.h b/include/automount.h index 3192c92..e3ecc75 100644 --- a/include/automount.h +++ b/include/automount.h @@ -123,8 +123,8 @@ #define CHE_DUPLICATE 0x0020 #define HASHSIZE 77 #define NEGATIVE_TIMEOUT 10 -#define UMOUNT_RETRIES 50 -#define EXPIRE_RETRIES 25 +#define UMOUNT_RETRIES 6 +#define EXPIRE_RETRIES 3 struct mapent_cache { pthread_rwlock_t rwlock; @@ -229,6 +229,7 @@ int lookup_ghost(struct autofs_point *ap int lookup_nss_mount(struct autofs_point *ap, const char *name, int name_len); void lookup_close_lookup(struct autofs_point *ap); int lookup_prune_cache(struct autofs_point *ap, time_t age); +struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type); struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type); int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key); @@ -475,7 +476,7 @@ int handle_packet_expire_direct(struct a int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt); int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt); void rm_unwanted(const char *path, int incl, dev_t dev); -int count_mounts(struct autofs_point *ap, const char *path); +int count_mounts(const char *path, dev_t dev); #define state_mutex_lock(ap) \ do { \ diff --git a/lib/alarm.c b/lib/alarm.c index 8124796..89c9bc8 100755 --- a/lib/alarm.c +++ b/lib/alarm.c @@ -236,9 +236,9 @@ static void *alarm_handler(void *arg) list_del(¤t->list); free(current); - alarm_unlock(); - st_add_task(ap, ST_EXPIRE); - alarm_lock(); + state_mutex_lock(ap); + nextstate(ap->state_pipe[1], ST_EXPIRE); + state_mutex_unlock(ap); break; } diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 3f489ed..08fd34d 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -810,6 +810,54 @@ static int parse_mapent(const char *ent, return (p - ent); } +static int mount_subtree_offsets(struct autofs_point *ap, struct mapent_cache *mc, struct mapent *me) +{ + struct mapent *mm; + char *m_key; + int start; + char *base, *m_root; + char buf[MAX_ERR_BUF]; + + mm = me->multi; + + if (!mm) + return 1; + + cache_multi_lock(me->parent); + + m_key = mm->key; + + if (*m_key == '/') { + m_root = m_key; + start = strlen(m_key); + } else { + start = strlen(ap->path) + strlen(m_key) + 1; + m_root = alloca(start + 1); + if (!m_root) { + char *estr; + cache_multi_unlock(me->parent); + estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, MODPREFIX "alloca: %s", estr); + return 0; + } + strcpy(m_root, ap->path); + strcat(m_root, "/"); + strcat(m_root, m_key); + } + + base = &me->key[start]; + + if (!mount_multi_triggers(ap, m_root, me->multi, base)) { + cache_multi_unlock(me->parent); + error(ap->logopt, MODPREFIX "failed to mount offset triggers"); + return 0; + } + + cache_multi_unlock(me->parent); + + return 1; +} + /* * syntax is: * [-options] location [location] ... @@ -1085,6 +1133,7 @@ int parse_mount(struct autofs_point *ap, free(options); return 1; } + cache_multi_unlock(me); cache_unlock(mc); @@ -1093,7 +1142,6 @@ int parse_mount(struct autofs_point *ap, return rv; } else { /* Normal (and non-root multi-mount) entries */ - struct autofs_point *oap = ap; char *loc; int loclen; int l; @@ -1197,58 +1245,12 @@ int parse_mount(struct autofs_point *ap, * If it's a multi-mount insert the triggers * These are always direct mount triggers so root = "" */ - if (ap->submount) - oap = ap->parent; - - me = lookup_source_mapent(oap, name, LKP_DISTINCT); + cache_readlock(mc); + me = cache_lookup_distinct(mc, name); if (me) { - struct mapent *mm; - char *m_key; - int start; - char *base, *m_root; - - mc = me->source->mc; - mm = me->multi; - - if (!me->multi) { - cache_unlock(mc); - return rv; - } - - m_key = me->multi->key; - - if (*m_key == '/') { - m_root = m_key; - start = strlen(m_key); - } else { - start = strlen(ap->path) + strlen(m_key) + 1; - pthread_cleanup_push(cache_lock_cleanup, mc); - m_root = alloca(start + 1); - pthread_cleanup_pop(0); - if (!m_root) { - char *estr; - cache_unlock(mc); - estr = strerror_r(errno, buf, MAX_ERR_BUF); - error(ap->logopt, - MODPREFIX "alloca: %s", estr); - return 1; - } - strcpy(m_root, ap->path); - strcat(m_root, "/"); - strcat(m_root, m_key); - } - - base = &me->key[start]; - - cache_multi_lock(mm); - if (!mount_multi_triggers(oap, m_root, me->multi, base)) { - error(ap->logopt, - MODPREFIX "failed to mount offset triggers"); - rv = 1; - } - cache_multi_unlock(mm); - cache_unlock(mc); + mount_subtree_offsets(ap, mc, me); } + cache_unlock(mc); } return rv; }