diff --git a/CHANGELOG b/CHANGELOG index 93a4df5..8cfb220 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ - code cleanup. - fix race for current map source. - cthon map parser corrections. +- cthon multi-map locking fix and current race corrections. 13/7/2006 autofs-5.0.1 rc1 -------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 95eba4b..9faf485 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -217,7 +217,7 @@ static int umount_offsets(struct autofs_ map = ap->entry->first; while (map) { mc = map->mc; - cache_writelock(mc); + cache_readlock(mc); me = cache_lookup_distinct(mc, base); if (!me) me = cache_lookup_distinct(mc, ind_key); @@ -226,7 +226,6 @@ static int umount_offsets(struct autofs_ cache_unlock(mc); map = map->next; } - ap->entry->current = map; master_source_unlock(ap->entry); if (!me) @@ -268,12 +267,13 @@ static int umount_offsets(struct autofs_ } if (!ret && me->multi == me) { + cache_multi_lock(mc); status = cache_delete_offset_list(mc, me->key); + cache_multi_unlock(mc); if (status != CHE_OK) warn(ap->logopt, "couldn't delete offset list"); } cache_unlock(mc); - ap->entry->current = NULL; return ret; } @@ -351,7 +351,6 @@ static int umount_ent(struct autofs_poin "mounted on this path.", path); rv = -1; } - } status = pthread_mutex_unlock(&ap->state_mutex); @@ -383,6 +382,8 @@ 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]); @@ -413,6 +414,7 @@ static int walk_tree(const char *base, i static int rm_unwanted_fn(const char *file, const struct stat *st, int when, void *arg) { dev_t dev = *(int *) arg; + char buf[MAX_ERR_BUF]; struct stat newst; if (when == 0) { @@ -437,8 +439,9 @@ static int rm_unwanted_fn(const char *fi if (S_ISDIR(newst.st_mode)) { debug(LOGOPT_ANY, "removing directory %s", file); if (rmdir(file)) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); error(LOGOPT_ANY, - "unable to remove directory %s", file); + "unable to remove directory %s: %s", file, estr); return 0; } } else if (S_ISREG(newst.st_mode)) { @@ -1217,6 +1220,8 @@ static void handle_mounts_cleanup(void * if (master_list_empty(master_list)) kill(getpid(), SIGTERM); + sched_yield(); + if (clean) { if (rmdir(path) == -1) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); @@ -1337,7 +1342,7 @@ void *handle_mounts(void *arg) fatal(status); } } -/* + status = pthread_mutex_lock(&ap->mounts_mutex); if (status) fatal(status); @@ -1351,7 +1356,7 @@ void *handle_mounts(void *arg) status = pthread_mutex_unlock(&ap->mounts_mutex); if (status) fatal(status); -*/ + pthread_cleanup_pop(1); /* diff --git a/daemon/direct.c b/daemon/direct.c index 93af751..4ee8a03 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -197,7 +197,6 @@ int umount_autofs_direct(struct autofs_p master_source_readlock(ap->entry); map = ap->entry->first; while (map) { - ap->entry->current = map; mc = map->mc; pthread_cleanup_push(cache_lock_cleanup, mc); cache_readlock(mc); @@ -213,7 +212,6 @@ int umount_autofs_direct(struct autofs_p } pthread_cleanup_pop(1); tree_free_mnt_tree(mnts); - ap->entry->current = NULL; return 0; } @@ -264,7 +262,6 @@ static int unlink_mount_tree(struct auto int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me) { - struct map_source *map = ap->entry->current; struct mnt_params *mp; time_t timeout = ap->exp_timeout; struct stat st; @@ -382,7 +379,7 @@ got_version: "failed to stat direct mount trigger %s", me->key); goto out_close; } - cache_set_ino_index(map->mc, me->key, st.st_dev, st.st_ino); + cache_set_ino_index(me->source->mc, me->key, st.st_dev, st.st_ino); close(me->ioctlfd); me->ioctlfd = -1; @@ -442,7 +439,6 @@ int mount_autofs_direct(struct autofs_po continue; } - ap->entry->current = map; mc = map->mc; pthread_cleanup_push(cache_lock_cleanup, mc); cache_readlock(mc); diff --git a/include/automount.h b/include/automount.h index 8a5b800..a71606e 100644 --- a/include/automount.h +++ b/include/automount.h @@ -123,6 +123,7 @@ #define NEGATIVE_TIMEOUT 10 struct mapent_cache { pthread_rwlock_t rwlock; + pthread_mutex_t multi_mutex; unsigned int size; struct list_head *ino_index; struct mapent **hash; @@ -170,6 +171,8 @@ int cache_add_offset(struct mapent_cache int cache_update(struct mapent_cache *mc, struct map_source *source, const char *key, const char *mapent, time_t age); int cache_delete(struct mapent_cache *mc, const char *key); +void cache_multi_lock(struct mapent_cache *mc); +void cache_multi_unlock(struct mapent_cache *mc); int cache_delete_offset_list(struct mapent_cache *mc, const char *key); void cache_release(struct map_source *map); struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me); diff --git a/lib/cache.c b/lib/cache.c index ffc4c9b..4d0b196 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -98,6 +98,29 @@ void cache_lock_cleanup(void *arg) cache_unlock(mc); } +void cache_multi_lock(struct mapent_cache *mc) +{ + int status; + + status = pthread_mutex_lock(&mc->multi_mutex); + if (status) { + error(LOGOPT_ANY, "mapent cache multi mutex lock failed"); + fatal(status); + } + return; +} + +void cache_multi_unlock(struct mapent_cache *mc) +{ + int status; + + status = pthread_mutex_unlock(&mc->multi_mutex); + if (status) { + error(LOGOPT_ANY, "mapent cache multi mutex unlock failed"); + fatal(status); + } + return; +} struct mapent_cache *cache_init(struct map_source *map) { struct mapent_cache *mc; @@ -130,6 +153,10 @@ struct mapent_cache *cache_init(struct m if (status) fatal(status); + status = pthread_mutex_init(&mc->multi_mutex, NULL); + if (status) + fatal(status); + cache_writelock(mc); for (i = 0; i < mc->size; i++) { @@ -675,6 +702,10 @@ void cache_release(struct map_source *ma if (status) fatal(status); + status = pthread_mutex_destroy(&mc->multi_mutex); + if (status) + fatal(status); + free(mc->hash); free(mc->ino_index); free(mc); diff --git a/lib/master.c b/lib/master.c index 3cf0428..ea213ad 100644 --- a/lib/master.c +++ b/lib/master.c @@ -1142,3 +1142,13 @@ int master_kill(struct master *master) return 1; } +void dump_master(struct master *master) +{ + struct list_head *p, *head; + + head = &master->mounts; + list_for_each(p, head) { + struct master_mapent *this = list_entry(p, struct master_mapent, list); + debug(LOGOPT_ANY, "path %s", this->path); + } +} diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c index 0e5152e..16fd1bd 100644 --- a/modules/lookup_hosts.c +++ b/modules/lookup_hosts.c @@ -76,11 +76,17 @@ int lookup_read_master(struct master *ma int lookup_read_map(struct autofs_point *ap, time_t age, void *context) { - struct map_source *source = ap->entry->current; - struct mapent_cache *mc = source->mc; + struct map_source *source; + struct mapent_cache *mc; struct hostent *host; int status; + source = ap->entry->current; + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + + mc = source->mc; + status = pthread_mutex_lock(&hostent_mutex); if (status) { error(LOGOPT_ANY, MODPREFIX "failed to lock hostent mutex"); @@ -107,8 +113,8 @@ int lookup_read_map(struct autofs_point int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context) { struct lookup_context *ctxt = (struct lookup_context *) context; - struct map_source *source = ap->entry->current; - struct mapent_cache *mc = source->mc; + struct map_source *source; + struct mapent_cache *mc; struct mapent *me; char buf[MAX_ERR_BUF]; char *mapent = NULL; @@ -118,6 +124,12 @@ int lookup_mount(struct autofs_point *ap int status = NSS_STATUS_UNKNOWN; int ret; + source = ap->entry->current; + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + + mc = source->mc; + cache_readlock(mc); me = cache_lookup_distinct(mc, name); if (!me) { @@ -168,6 +180,9 @@ done: return status; if (mapent) { + master_source_current_wait(ap->entry); + ap->entry->current = source; + debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent); ret = ctxt->parse->parse_mount(ap, name, name_len, mapent, ctxt->parse->context); @@ -238,6 +253,9 @@ done: cache_update(mc, source, name, mapent, now); cache_unlock(mc); + master_source_current_wait(ap->entry); + ap->entry->current = source; + ret = ctxt->parse->parse_mount(ap, name, name_len, mapent, ctxt->parse->context); free(mapent); diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index 7986d3b..0bcd249 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -1541,7 +1541,7 @@ static int check_map_indirect(struct aut if (ap->ghost && need_map) { int status; - ap->entry->current->stale = 1; + source->stale = 1; status = pthread_mutex_lock(&ap->state_mutex); if (status) diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c index 4049f1b..4bc8820 100644 --- a/modules/lookup_nisplus.c +++ b/modules/lookup_nisplus.c @@ -422,7 +422,7 @@ static int check_map_indirect(struct aut if (ap->ghost && need_map) { int status; - ap->entry->current->stale = 1; + source->stale = 1; status = pthread_mutex_lock(&ap->state_mutex); if (status) diff --git a/modules/lookup_program.c b/modules/lookup_program.c index c7c2418..9c69b6f 100644 --- a/modules/lookup_program.c +++ b/modules/lookup_program.c @@ -105,8 +105,8 @@ int lookup_read_map(struct autofs_point int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context) { struct lookup_context *ctxt = (struct lookup_context *) context; - struct map_source *source = ap->entry->current; - struct mapent_cache *mc = source->mc; + struct map_source *source; + struct mapent_cache *mc; char *mapent = NULL, *mapp, *tmp; struct mapent *me; char buf[MAX_ERR_BUF]; @@ -124,6 +124,12 @@ int lookup_mount(struct autofs_point *ap int distance; int alloci = 1; + source = ap->entry->current; + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + + mc = source->mc; + /* Catch installed direct offset triggers */ cache_readlock(mc); me = cache_lookup_distinct(mc, name); @@ -143,6 +149,9 @@ int lookup_mount(struct autofs_point *ap /* Otherwise we found a valid offset so try mount it */ debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent); + master_source_current_wait(ap->entry); + ap->entry->current = source; + ret = ctxt->parse->parse_mount(ap, name, name_len, me->mapent, ctxt->parse->context); goto out_free; @@ -336,6 +345,9 @@ int lookup_mount(struct autofs_point *ap debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent); + master_source_current_wait(ap->entry); + ap->entry->current = source; + ret = ctxt->parse->parse_mount(ap, name, name_len, mapent, ctxt->parse->context); out_free: diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c index 741e6ec..fcee26b 100644 --- a/modules/lookup_yp.c +++ b/modules/lookup_yp.c @@ -526,7 +526,7 @@ static int check_map_indirect(struct aut if (ap->ghost && need_map) { int status; - ap->entry->current->stale = 1; + source->stale = 1; status = pthread_mutex_lock(&ap->state_mutex); if (status) diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 929698f..ca80bad 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -666,8 +666,10 @@ add_offset_entry(struct autofs_point *ap } else strcpy(m_mapent, loc); - cache_writelock(mc); + cache_readlock(mc); + cache_multi_lock(mc); ret = cache_add_offset(mc, name, m_key, m_mapent, age); + cache_multi_unlock(mc); cache_unlock(mc); if (ret == CHE_OK) @@ -1088,8 +1090,10 @@ int parse_mount(struct autofs_point *ap, if (!path) { error(ap->logopt, MODPREFIX "out of memory"); - cache_writelock(mc); + cache_readlock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(options); return 1; @@ -1097,8 +1101,10 @@ int parse_mount(struct autofs_point *ap, if (!*path) { error(ap->logopt, MODPREFIX "invalid path"); - cache_writelock(mc); + cache_readlock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(path); free(options); @@ -1110,8 +1116,10 @@ int parse_mount(struct autofs_point *ap, l = parse_mapent(p, options, &myoptions, &loc, ap->logopt); if (!l) { - cache_writelock(mc); + cache_readlock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(path); free(options); @@ -1130,8 +1138,10 @@ int parse_mount(struct autofs_point *ap, if (status != CHE_OK) { error(ap->logopt, MODPREFIX "error adding multi-mount"); - cache_writelock(mc); + cache_readlock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(path); free(options); @@ -1145,8 +1155,20 @@ int parse_mount(struct autofs_point *ap, free(myoptions); } while (*p == '/'); - /* Mount root offset if it exists */ cache_readlock(mc); + if (!me) { + error(ap->logopt, + MODPREFIX + "failed to find cache entry for %s", name); + cache_multi_lock(mc); + cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); + cache_unlock(mc); + free(options); + return 1; + } + + /* Mount root offset if it exists */ ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list); if (ro) { char *myoptions, *loc; @@ -1154,11 +1176,11 @@ int parse_mount(struct autofs_point *ap, rv = parse_mapent(ro->mapent, options, &myoptions, &loc, ap->logopt); if (!rv) { - cache_unlock(mc); error(ap->logopt, MODPREFIX "mount of root offset failed"); - cache_writelock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(options); return 1; @@ -1171,12 +1193,12 @@ int parse_mount(struct autofs_point *ap, free(loc); if (rv < 0) { - cache_unlock(mc); error(ap->logopt, MODPREFIX "mount multi-mount root %s failed", name); - cache_writelock(mc); + cache_multi_lock(mc); cache_delete_offset_list(mc, name); + cache_multi_unlock(mc); cache_unlock(mc); free(options); return rv; @@ -1184,12 +1206,8 @@ int parse_mount(struct autofs_point *ap, } if (!mount_multi_triggers(ap, m_root, me, "/")) { - cache_unlock(mc); error(ap->logopt, MODPREFIX "failed to mount offset triggers"); - cache_writelock(mc); - cache_delete_offset_list(mc, name); - cache_unlock(mc); free(options); return 1; } @@ -1340,11 +1358,13 @@ int parse_mount(struct autofs_point *ap, base = &me->key[start]; + cache_multi_lock(mc); if (!mount_multi_triggers(ap, m_root, me->multi, base)) { error(ap->logopt, MODPREFIX "failed to mount offset triggers"); rv = 1; } + cache_multi_unlock(mc); } cache_unlock(mc); }