Blame daemon/state.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *
Packit 8480eb
 *  state.c - state machine functions.
Packit 8480eb
 *
Packit 8480eb
 *   Copyright 2006 Ian Kent <raven@themaw.net> - All Rights Reserved
Packit 8480eb
 *
Packit 8480eb
 *   This program is free software; you can redistribute it and/or modify
Packit 8480eb
 *   it under the terms of the GNU General Public License as published by
Packit 8480eb
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 *   USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 *   version; incorporated herein by reference.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <sys/ioctl.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
/* Attribute to create detached thread */
Packit 8480eb
extern pthread_attr_t th_attr_detached;
Packit 8480eb
Packit 8480eb
struct state_queue {
Packit 8480eb
	pthread_t thid;
Packit 8480eb
	struct list_head list;
Packit 8480eb
	struct list_head pending;
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
	enum states state;
Packit 8480eb
	unsigned int busy;
Packit 8480eb
	unsigned int done;
Packit 8480eb
	unsigned int cancel;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Packit 8480eb
static unsigned int signaled = 0;
Packit 8480eb
static LIST_HEAD(state_queue);
Packit 8480eb
Packit 8480eb
static void st_set_thid(struct autofs_point *, pthread_t);
Packit 8480eb
static void st_set_done(struct autofs_point *ap);
Packit 8480eb
Packit 8480eb
void st_mutex_lock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_lock(&mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void st_mutex_unlock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_unlock(&mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void dump_state_queue(void)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head = &state_queue;
Packit 8480eb
	struct list_head *p, *q;
Packit 8480eb
Packit 8480eb
	logmsg("dumping queue");
Packit 8480eb
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		struct state_queue *entry;
Packit 8480eb
Packit 8480eb
		entry = list_entry(p, struct state_queue, list);
Packit 8480eb
		logmsg("queue list head path %s state %d busy %d",
Packit 8480eb
		      entry->ap->path, entry->state, entry->busy);
Packit 8480eb
Packit 8480eb
		list_for_each(q, &entry->pending) {
Packit 8480eb
			struct state_queue *this;
Packit 8480eb
Packit 8480eb
			this = list_entry(q, struct state_queue, pending);
Packit 8480eb
			logmsg("queue list entry path %s state %d busy %d",
Packit 8480eb
			      this->ap->path, this->state, this->busy);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void nextstate(int statefd, enum states next)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
Packit 8480eb
	if (write(statefd, &next, sizeof(next)) != sizeof(next)) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("write failed %s", estr);
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Handle expire thread cleanup and return the next state the system
Packit 8480eb
 * should enter as a result.
Packit 8480eb
 */
Packit 8480eb
void expire_cleanup(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	pthread_t thid = pthread_self();
Packit 8480eb
	struct expire_args *ec;
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
	int success;
Packit 8480eb
	enum states next = ST_INVAL;
Packit 8480eb
Packit 8480eb
	ec = (struct expire_args *) arg;
Packit 8480eb
	ap = ec->ap;
Packit 8480eb
	success = ec->status;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
Packit 8480eb
	debug(ap->logopt,
Packit 8480eb
	      "got thid %lu path %s stat %d",
Packit 8480eb
	      (unsigned long) thid, ap->path, success);
Packit 8480eb
Packit 8480eb
	/* Check to see if expire process finished */
Packit 8480eb
	if (thid == ap->exp_thread) {
Packit 8480eb
		unsigned int idle;
Packit 8480eb
		int rv;
Packit 8480eb
Packit 8480eb
		ap->exp_thread = 0;
Packit 8480eb
Packit 8480eb
		switch (ap->state) {
Packit 8480eb
		case ST_EXPIRE:
Packit 8480eb
			/* FALLTHROUGH */
Packit 8480eb
		case ST_PRUNE:
Packit 8480eb
			/*
Packit 8480eb
			 * If we're a submount and we've just pruned or
Packit 8480eb
			 * expired everything away, try to shut down.
Packit 8480eb
			 *
Packit 8480eb
			 * Since we use the the fact that a mount will not
Packit 8480eb
			 * expire for at least ap->exp_timeout to avoid a
Packit 8480eb
			 * mount <-> expire race we need to wait before
Packit 8480eb
			 * letting a submount expire away. We also need
Packit 8480eb
			 * them to go away fairly quickly so the owner
Packit 8480eb
			 * mount expires in a reasonable time. Just skip
Packit 8480eb
			 * one expire check after it's no longer busy before
Packit 8480eb
			 * allowing it to shutdown.
Packit 8480eb
			 *
Packit 8480eb
			 * But if this mount point is an amd format map it
Packit 8480eb
			 * is better to keep the mount around longer. This
Packit 8480eb
			 * is because of the common heavy reuse of maps in
Packit 8480eb
			 * amd maps and we want to try and avoid constantly
Packit 8480eb
			 * re-reading large maps.
Packit 8480eb
			 */
Packit 8480eb
			if (ap->submount && !success) {
Packit 8480eb
				rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
Packit 8480eb
				if (!rv && idle && ap->submount > 1) {
Packit 8480eb
					struct map_source *map = ap->entry->maps;
Packit 8480eb
Packit 8480eb
					if (ap->submount > 4 ||
Packit 8480eb
					   !(map->flags & MAP_FLAG_FORMAT_AMD)) {
Packit 8480eb
						next = ST_SHUTDOWN_PENDING;
Packit 8480eb
						break;
Packit 8480eb
					}
Packit 8480eb
				}
Packit 8480eb
				ap->submount++;
Packit 8480eb
			} else if (ap->submount > 1)
Packit 8480eb
				ap->submount = 1;
Packit 8480eb
Packit 8480eb
			if (ap->state == ST_EXPIRE && !ap->submount)
Packit 8480eb
				alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
Packit 8480eb
			/* FALLTHROUGH */
Packit 8480eb
Packit 8480eb
		case ST_READY:
Packit 8480eb
			next = ST_READY;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ST_SHUTDOWN_PENDING:
Packit 8480eb
			/*
Packit 8480eb
			 * If we reveive a mount request while trying to
Packit 8480eb
			 * shutdown return to ready state unless we have
Packit 8480eb
			 * been signaled to shutdown.
Packit 8480eb
			 */
Packit 8480eb
			rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
Packit 8480eb
			if (!rv && !idle && !ap->shutdown) {
Packit 8480eb
				next = ST_READY;
Packit 8480eb
				if (!ap->submount)
Packit 8480eb
					alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			next = ST_SHUTDOWN;
Packit 8480eb
#ifdef ENABLE_IGNORE_BUSY_MOUNTS
Packit 8480eb
			break;
Packit 8480eb
#else
Packit 8480eb
			if (success == 0)
Packit 8480eb
				break;
Packit 8480eb
Packit 8480eb
			/* Failed shutdown returns to ready */
Packit 8480eb
			warn(ap->logopt, "filesystem %s still busy", ap->path);
Packit 8480eb
			if (!ap->submount)
Packit 8480eb
				alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
			next = ST_READY;
Packit 8480eb
			break;
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
		case ST_SHUTDOWN_FORCE:
Packit 8480eb
			next = ST_SHUTDOWN;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			error(ap->logopt, "bad state %d", ap->state);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (next != ST_INVAL) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			  "sigchld: exp %lu finished, switching from %d to %d",
Packit 8480eb
			  (unsigned long) thid, ap->state, next);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	st_set_done(ap);
Packit 8480eb
Packit 8480eb
	if (next != ST_INVAL)
Packit 8480eb
		__st_add_task(ap, next);
Packit 8480eb
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_ready(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	debug(ap->logopt,
Packit 8480eb
	      "st_ready(): state = %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	ap->shutdown = 0;
Packit 8480eb
	ap->state = ST_READY;
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
enum expire {
Packit 8480eb
	EXP_ERROR,
Packit 8480eb
	EXP_STARTED,
Packit 8480eb
	EXP_PARTIAL
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Generate expiry messages.  If "now" is true, timeouts are ignored.
Packit 8480eb
 *
Packit 8480eb
 * Returns: ERROR	- error
Packit 8480eb
 *          STARTED	- expiry process started
Packit 8480eb
 *          DONE	- nothing to expire
Packit 8480eb
 *          PARTIAL	- partial expire
Packit 8480eb
 */
Packit 8480eb
Packit 8480eb
void expire_proc_cleanup(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct expire_args *ea;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	ea = (struct expire_args *) arg;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&ea->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_cond_destroy(&ea->cond);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_destroy(&ea->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	free(ea);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit Service 42268b
static enum expire expire_proc(struct autofs_point *ap, int now)
Packit 8480eb
{
Packit 8480eb
	pthread_t thid;
Packit 8480eb
	struct expire_args *ea;
Packit 8480eb
	void *(*expire)(void *);
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	assert(ap->exp_thread == 0);
Packit 8480eb
Packit 8480eb
	ea = malloc(sizeof(struct expire_args));
Packit 8480eb
	if (!ea) {
Packit 8480eb
		error(ap->logopt, "failed to malloc expire cond struct");
Packit 8480eb
		return EXP_ERROR;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_init(&ea->mutex, NULL);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_cond_init(&ea->cond, NULL);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&ea->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	ea->ap = ap;
Packit Service 42268b
	ea->when = now;
Packit 8480eb
	ea->status = 1;
Packit 8480eb
Packit 8480eb
	if (ap->type == LKP_INDIRECT)
Packit 8480eb
		expire = expire_proc_indirect;
Packit 8480eb
	else
Packit 8480eb
		expire = expire_proc_direct;
Packit 8480eb
Packit 8480eb
	status = pthread_create(&thid, &th_attr_detached, expire, ea);
Packit 8480eb
	if (status) {
Packit 8480eb
		error(ap->logopt,
Packit 8480eb
		      "expire thread create for %s failed", ap->path);
Packit 8480eb
		expire_proc_cleanup((void *) ea);
Packit 8480eb
		return EXP_ERROR;
Packit 8480eb
	}
Packit 8480eb
	ap->exp_thread = thid;
Packit 8480eb
	st_set_thid(ap, thid);
Packit 8480eb
Packit 8480eb
	pthread_cleanup_push(expire_proc_cleanup, ea);
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "exp_proc = %lu path %s",
Packit 8480eb
		(unsigned long) ap->exp_thread, ap->path);
Packit 8480eb
Packit 8480eb
	ea->signaled = 0;
Packit 8480eb
	while (!ea->signaled) {
Packit 8480eb
		status = pthread_cond_wait(&ea->cond, &ea->mutex);
Packit 8480eb
		if (status)
Packit 8480eb
			fatal(status);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	pthread_cleanup_pop(1);
Packit 8480eb
Packit 8480eb
	return EXP_STARTED;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void do_readmap_cleanup(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct readmap_args *ra;
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
Packit 8480eb
	ra = (struct readmap_args *) arg;
Packit 8480eb
Packit 8480eb
	ap = ra->ap;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
	ap->readmap_thread = 0;
Packit 8480eb
	st_set_done(ap);
Packit 8480eb
	st_ready(ap);
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	free(ra);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit Service 42268b
static void tree_mnts_cleanup(void *arg)
Packit Service 42268b
{
Packit Service 42268b
	struct mnt_list *mnts = (struct mnt_list *) arg;
Packit Service 42268b
	tree_free_mnt_tree(mnts);
Packit Service 42268b
	return;
Packit Service 42268b
}
Packit Service 42268b
Packit Service 42268b
static void do_readmap_mount(struct autofs_point *ap, struct mnt_list *mnts,
Packit 8480eb
			     struct map_source *map, struct mapent *me, time_t now)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *nc;
Packit 8480eb
	struct mapent *ne, *nested, *valid;
Packit 8480eb
Packit 8480eb
	nc = ap->entry->master->nc;
Packit 8480eb
Packit 8480eb
	ne = cache_lookup_distinct(nc, me->key);
Packit 8480eb
	if (!ne) {
Packit 8480eb
		nested = cache_partial_match(nc, me->key);
Packit 8480eb
		if (nested) {
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      "removing invalid nested null entry %s",
Packit 8480eb
			      nested->key);
Packit 8480eb
			nested = cache_partial_match(nc, me->key);
Packit 8480eb
			if (nested)
Packit 8480eb
				cache_delete(nc, nested->key);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (me->age < now || (ne && map->master_line > ne->age)) {
Packit 8480eb
		/*
Packit 8480eb
		 * The map instance may have changed, such as the map name or
Packit 8480eb
		 * the mount options, but the direct map entry may still exist
Packit 8480eb
		 * in one of the other maps. If so then update the new cache
Packit 8480eb
		 * entry device and inode so we can find it at lookup. Later,
Packit 8480eb
		 * the mount for the new cache entry will just update the
Packit 8480eb
		 * timeout.
Packit 8480eb
		 *
Packit 8480eb
		 * TODO: how do we recognise these orphaned map instances. We
Packit 8480eb
		 * can't just delete these instances when the cache becomes
Packit 8480eb
		 * empty because that is a valid state for a master map entry.
Packit 8480eb
		 * This is becuase of the requirement to continue running with
Packit 8480eb
		 * an empty cache awaiting a map re-load.
Packit 8480eb
		 */
Packit 8480eb
		valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT);
Packit 8480eb
		if (valid && valid->mc == me->mc) {
Packit 8480eb
			/*
Packit 8480eb
			 * We've found a map entry that has been removed from
Packit 8480eb
			 * the current cache so there is no need to update it.
Packit 8480eb
			 * The stale entry will be dealt with when we prune the
Packit 8480eb
			 * cache later.
Packit 8480eb
			 */
Packit 8480eb
			cache_unlock(valid->mc);
Packit 8480eb
			valid = NULL;
Packit 8480eb
		}
Packit 8480eb
		if (valid) {
Packit 8480eb
			struct mapent_cache *vmc = valid->mc;
Packit 8480eb
			struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
			time_t timeout;
Packit 8480eb
			time_t runfreq;
Packit 8480eb
Packit 8480eb
			cache_unlock(vmc);
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			     "updating cache entry for valid direct trigger %s",
Packit 8480eb
			     me->key);
Packit 8480eb
			cache_writelock(vmc);
Packit 8480eb
			valid = cache_lookup_distinct(vmc, me->key);
Packit 8480eb
			if (!valid) {
Packit 8480eb
				cache_unlock(vmc);
Packit 8480eb
				error(ap->logopt,
Packit 8480eb
				     "failed to find expected existing valid map entry");
Packit 8480eb
				return;
Packit 8480eb
			}
Packit 8480eb
			/* Take over the mount if there is one */
Packit 8480eb
			valid->ioctlfd = me->ioctlfd;
Packit 8480eb
			me->ioctlfd = -1;
Packit 8480eb
			/* Set device and inode number of the new mapent */
Packit 8480eb
			cache_set_ino_index(vmc, me->key, me->dev, me->ino);
Packit 8480eb
			cache_unlock(vmc);
Packit 8480eb
			/* Set timeout and calculate the expire run frequency */
Packit 8480eb
			timeout = get_exp_timeout(ap, map);
Packit 8480eb
			ops->timeout(ap->logopt, valid->ioctlfd, timeout);
Packit 8480eb
			if (timeout) {
Packit 8480eb
				runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
Packit 8480eb
				if (ap->exp_runfreq)
Packit 8480eb
					ap->exp_runfreq = min(ap->exp_runfreq, runfreq);
Packit 8480eb
				else
Packit 8480eb
					ap->exp_runfreq = runfreq;
Packit 8480eb
			}
Packit Service 42268b
		} else if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
Packit Service 42268b
			do_umount_autofs_direct(ap, mnts, me);
Packit 8480eb
		else
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      "%s is mounted", me->key);
Packit 8480eb
	} else
Packit Service 42268b
		do_mount_autofs_direct(ap, mnts, me, get_exp_timeout(ap, map));
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void *do_readmap(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
	struct map_source *map;
Packit 8480eb
	struct mapent_cache *nc, *mc;
Packit 8480eb
	struct readmap_args *ra;
Packit Service 42268b
	struct mnt_list *mnts;
Packit 8480eb
	int status;
Packit 8480eb
	time_t now;
Packit 8480eb
Packit 8480eb
	ra = (struct readmap_args *) arg;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&ra->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	ap = ra->ap;
Packit 8480eb
	now = ra->now;
Packit 8480eb
Packit 8480eb
	ra->signaled = 1;
Packit 8480eb
	status = pthread_cond_signal(&ra->cond);
Packit 8480eb
	if (status) {
Packit 8480eb
		error(ap->logopt, "failed to signal expire condition");
Packit 8480eb
		pthread_mutex_unlock(&ra->mutex);
Packit 8480eb
		fatal(status);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&ra->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	pthread_cleanup_push(do_readmap_cleanup, ra);
Packit 8480eb
Packit 8480eb
	info(ap->logopt, "re-reading map for %s", ap->path);
Packit 8480eb
Packit 8480eb
	status = lookup_nss_read_map(ap, NULL, now);
Packit 8480eb
	if (!status)
Packit 8480eb
		pthread_exit(NULL);
Packit 8480eb
Packit 8480eb
	if (ap->type == LKP_INDIRECT) {
Packit 8480eb
		struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
		time_t timeout = get_exp_timeout(ap, ap->entry->maps);
Packit 8480eb
		ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
Packit 8480eb
		ops->timeout(ap->logopt, ap->ioctlfd, timeout);
Packit 8480eb
		lookup_prune_cache(ap, now);
Packit 8480eb
		status = lookup_ghost(ap, ap->path);
Packit 8480eb
	} else {
Packit 8480eb
		struct mapent *me;
Packit 8480eb
		unsigned int append_alarm = !ap->exp_runfreq;
Packit 8480eb
Packit Service 42268b
		mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
Packit Service 42268b
		pthread_cleanup_push(tree_mnts_cleanup, mnts);
Packit 8480eb
		nc = ap->entry->master->nc;
Packit 8480eb
		cache_readlock(nc);
Packit 8480eb
		pthread_cleanup_push(cache_lock_cleanup, nc);
Packit 8480eb
		master_source_readlock(ap->entry);
Packit 8480eb
		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Packit 8480eb
		map = ap->entry->maps;
Packit 8480eb
		while (map) {
Packit 8480eb
			/* Is map source up to date or no longer valid */
Packit 8480eb
			if (!map->stale && !check_stale_instances(map)) {
Packit 8480eb
				map = map->next;
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
			mc = map->mc;
Packit 8480eb
			pthread_cleanup_push(cache_lock_cleanup, mc);
Packit 8480eb
			cache_readlock(mc);
Packit 8480eb
			me = cache_enumerate(mc, NULL);
Packit 8480eb
			while (me) {
Packit Service 42268b
				do_readmap_mount(ap, mnts, map, me, now);
Packit 8480eb
				me = cache_enumerate(mc, me);
Packit 8480eb
			}
Packit 8480eb
			lookup_prune_one_cache(ap, map->mc, now);
Packit 8480eb
			pthread_cleanup_pop(1);
Packit 8480eb
			clear_stale_instances(map);
Packit 8480eb
			map->stale = 0;
Packit 8480eb
			map = map->next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* If the direct mount map was empty at startup no expire
Packit 8480eb
		 * alarm will have been added. So add it here if there are
Packit 8480eb
		 * now map entries.
Packit 8480eb
		 */
Packit 8480eb
		if (append_alarm && ap->exp_runfreq)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq +
Packit 8480eb
				  rand() % ap->exp_runfreq);
Packit 8480eb
Packit 8480eb
		pthread_cleanup_pop(1);
Packit 8480eb
		pthread_cleanup_pop(1);
Packit Service 42268b
		pthread_cleanup_pop(1);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	pthread_cleanup_pop(1);
Packit 8480eb
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void st_readmap_cleanup(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct readmap_args *ra;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	ra = (struct readmap_args *) arg;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&ra->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_cond_destroy(&ra->cond);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_destroy(&ra->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_readmap(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	pthread_t thid;
Packit 8480eb
	struct readmap_args *ra;
Packit 8480eb
	int status;
Packit 8480eb
	int now = monotonic_time(NULL);
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_READY);
Packit 8480eb
	assert(ap->readmap_thread == 0);
Packit 8480eb
Packit 8480eb
	ap->state = ST_READMAP;
Packit 8480eb
Packit 8480eb
	ra = malloc(sizeof(struct readmap_args));
Packit 8480eb
	if (!ra) {
Packit 8480eb
		error(ap->logopt, "failed to malloc readmap cond struct");
Packit 8480eb
		/* It didn't work: return to ready */
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_init(&ra->mutex, NULL);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_cond_init(&ra->cond, NULL);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&ra->mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	ra->ap = ap;
Packit 8480eb
	ra->now = now;
Packit 8480eb
Packit 8480eb
	status = pthread_create(&thid, &th_attr_detached, do_readmap, ra);
Packit 8480eb
	if (status) {
Packit 8480eb
		error(ap->logopt, "readmap thread create failed");
Packit 8480eb
		st_readmap_cleanup(ra);
Packit 8480eb
		free(ra);
Packit 8480eb
		/* It didn't work: return to ready */
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	ap->readmap_thread = thid;
Packit 8480eb
	st_set_thid(ap, thid);
Packit 8480eb
Packit 8480eb
	pthread_cleanup_push(st_readmap_cleanup, ra);
Packit 8480eb
Packit 8480eb
	ra->signaled = 0;
Packit 8480eb
	while (!ra->signaled) {
Packit 8480eb
		status = pthread_cond_wait(&ra->cond, &ra->mutex);
Packit 8480eb
		if (status)
Packit 8480eb
			fatal(status);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	pthread_cleanup_pop(1);
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_prepare_shutdown(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	int exp;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
Packit 8480eb
	ap->state = ST_SHUTDOWN_PENDING;
Packit 8480eb
Packit 8480eb
	/* Unmount everything */
Packit 8480eb
	exp = expire_proc(ap, 1);
Packit 8480eb
	switch (exp) {
Packit 8480eb
	case EXP_ERROR:
Packit 8480eb
	case EXP_PARTIAL:
Packit 8480eb
		/* It didn't work: return to ready */
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	case EXP_STARTED:
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_force_shutdown(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	int exp;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
Packit 8480eb
	ap->state = ST_SHUTDOWN_FORCE;
Packit 8480eb
Packit 8480eb
	/* Unmount everything */
Packit 8480eb
	exp = expire_proc(ap, 1);
Packit 8480eb
	switch (exp) {
Packit 8480eb
	case EXP_ERROR:
Packit 8480eb
	case EXP_PARTIAL:
Packit 8480eb
		/* It didn't work: return to ready */
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	case EXP_STARTED:
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_shutdown(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE);
Packit 8480eb
Packit 8480eb
	ap->state = ST_SHUTDOWN;
Packit 8480eb
	nextstate(ap->state_pipe[1], ST_SHUTDOWN);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_prune(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_READY);
Packit 8480eb
	ap->state = ST_PRUNE;
Packit 8480eb
Packit 8480eb
	switch (expire_proc(ap, 1)) {
Packit 8480eb
	case EXP_ERROR:
Packit 8480eb
	case EXP_PARTIAL:
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	case EXP_STARTED:
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int st_expire(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Packit 8480eb
Packit 8480eb
	assert(ap->state == ST_READY);
Packit 8480eb
	ap->state = ST_EXPIRE;
Packit 8480eb
Packit 8480eb
	switch (expire_proc(ap, 0)) {
Packit 8480eb
	case EXP_ERROR:
Packit 8480eb
	case EXP_PARTIAL:
Packit 8480eb
		if (!ap->submount)
Packit 8480eb
			alarm_add(ap, ap->exp_runfreq);
Packit 8480eb
		st_ready(ap);
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	case EXP_STARTED:
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct state_queue *st_alloc_task(struct autofs_point *ap, enum states state)
Packit 8480eb
{
Packit 8480eb
	struct state_queue *task;
Packit 8480eb
Packit 8480eb
	task = malloc(sizeof(struct state_queue));
Packit 8480eb
	if (!task)
Packit 8480eb
		return NULL;
Packit 8480eb
	memset(task, 0, sizeof(struct state_queue));
Packit 8480eb
Packit 8480eb
	task->ap = ap;
Packit 8480eb
	task->state = state;
Packit 8480eb
Packit 8480eb
	INIT_LIST_HEAD(&task->list);
Packit 8480eb
	INIT_LIST_HEAD(&task->pending);
Packit 8480eb
Packit 8480eb
	return task;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Insert alarm entry on ordered list.
Packit 8480eb
 * State queue mutex and ap state mutex, in that order, must be held.
Packit 8480eb
 */
Packit 8480eb
int __st_add_task(struct autofs_point *ap, enum states state)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head;
Packit 8480eb
	struct list_head *p, *q;
Packit 8480eb
	struct state_queue *new;
Packit 8480eb
	unsigned int empty = 1;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	/* Task termination marker, poke state machine */
Packit 8480eb
	if (state == ST_READY) {
Packit 8480eb
		st_ready(ap);
Packit 8480eb
Packit 8480eb
		signaled = 1;
Packit 8480eb
		status = pthread_cond_signal(&cond;;
Packit 8480eb
		if (status)
Packit 8480eb
			fatal(status);
Packit 8480eb
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ap->state == ST_SHUTDOWN)
Packit 8480eb
		return 1;
Packit 8480eb
Packit 8480eb
	if (state == ST_SHUTDOWN)
Packit 8480eb
		return st_shutdown(ap);
Packit 8480eb
Packit 8480eb
	head = &state_queue;
Packit 8480eb
Packit 8480eb
	/* Add to task queue for autofs_point ? */
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		struct state_queue *task;
Packit 8480eb
Packit 8480eb
		task = list_entry(p, struct state_queue, list);
Packit 8480eb
Packit 8480eb
		if (task->ap != ap)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		empty = 0;
Packit 8480eb
Packit 8480eb
		/* Don't add duplicate tasks */
Packit 8480eb
		if ((task->state == state && !task->done) ||
Packit 8480eb
		   (ap->state == ST_SHUTDOWN_PENDING ||
Packit 8480eb
		    ap->state == ST_SHUTDOWN_FORCE))
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		/* No pending tasks */
Packit 8480eb
		if (list_empty(&task->pending)) {
Packit 8480eb
			new = st_alloc_task(ap, state);
Packit 8480eb
			if (new)
Packit 8480eb
				list_add_tail(&new->pending, &task->pending);
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		list_for_each(q, &task->pending) {
Packit 8480eb
			struct state_queue *p_task;
Packit 8480eb
Packit 8480eb
			p_task = list_entry(q, struct state_queue, pending);
Packit 8480eb
Packit 8480eb
			if (p_task->state == state ||
Packit 8480eb
			   (ap->state == ST_SHUTDOWN_PENDING ||
Packit 8480eb
			    ap->state == ST_SHUTDOWN_FORCE))
Packit 8480eb
				goto done;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		new = st_alloc_task(ap, state);
Packit 8480eb
		if (new)
Packit 8480eb
			list_add_tail(&new->pending, &task->pending);
Packit 8480eb
done:
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (empty) {
Packit 8480eb
		new = st_alloc_task(ap, state);
Packit 8480eb
		if (new)
Packit 8480eb
			list_add(&new->list, head);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	signaled = 1;
Packit 8480eb
	status = pthread_cond_signal(&cond;;
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int st_add_task(struct autofs_point *ap, enum states state)
Packit 8480eb
{
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
	ret = __st_add_task(ap, state);
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Remove state queue tasks for ap.
Packit 8480eb
 * State queue mutex and ap state mutex, in that order, must be held.
Packit 8480eb
 */
Packit 8480eb
void st_remove_tasks(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head;
Packit 8480eb
	struct list_head *p, *q;
Packit 8480eb
	struct state_queue *task, *waiting;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
Packit 8480eb
	head = &state_queue;
Packit 8480eb
Packit 8480eb
	if (list_empty(head)) {
Packit 8480eb
		st_mutex_unlock();
Packit 8480eb
		return;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	p = head->next;
Packit 8480eb
	while (p != head) {
Packit 8480eb
		task = list_entry(p, struct state_queue, list);
Packit 8480eb
		p = p->next;
Packit 8480eb
Packit 8480eb
		if (task->ap != ap)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		if (task->busy) {
Packit 8480eb
			/* We only cancel readmap, prune and expire */
Packit 8480eb
			if (task->state == ST_EXPIRE ||
Packit 8480eb
			    task->state == ST_PRUNE ||
Packit 8480eb
			    task->state == ST_READMAP)
Packit 8480eb
				task->cancel = 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		q = (&task->pending)->next;
Packit 8480eb
		while(q != &task->pending) {
Packit 8480eb
			waiting = list_entry(q, struct state_queue, pending);
Packit 8480eb
			q = q->next;
Packit 8480eb
Packit 8480eb
			/* Don't remove existing shutdown task */
Packit 8480eb
			if (waiting->state != ST_SHUTDOWN_PENDING &&
Packit 8480eb
			    waiting->state != ST_SHUTDOWN_FORCE) {
Packit 8480eb
				list_del(&waiting->pending);
Packit 8480eb
				free(waiting);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	signaled = 1;
Packit 8480eb
	status = pthread_cond_signal(&cond;;
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int st_task_active(struct autofs_point *ap, enum states state)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head;
Packit 8480eb
	struct list_head *p, *q;
Packit 8480eb
	struct state_queue *task, *waiting;
Packit 8480eb
	unsigned int active = 0;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
Packit 8480eb
	head = &state_queue;
Packit 8480eb
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		task = list_entry(p, struct state_queue, list);
Packit 8480eb
Packit 8480eb
		if (task->ap != ap)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		if (task->state == state) {
Packit 8480eb
			active = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (state == ST_ANY) {
Packit 8480eb
			active = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		list_for_each(q, &task->pending) {
Packit 8480eb
			waiting = list_entry(q, struct state_queue, pending);
Packit 8480eb
Packit 8480eb
			if (waiting->state == state) {
Packit 8480eb
				active = 1;
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (state == ST_ANY) {
Packit 8480eb
				active = 1;
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return active;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds)
Packit 8480eb
{
Packit 8480eb
	unsigned int wait = 0;
Packit 8480eb
	unsigned int duration = 0;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	while (1) {
Packit 8480eb
		struct timespec t = { 0, 200000000 };
Packit 8480eb
		struct timespec r;
Packit 8480eb
Packit 8480eb
		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit 8480eb
			memcpy(&t, &r, sizeof(struct timespec));
Packit 8480eb
Packit 8480eb
		if (wait++ == 4) {
Packit 8480eb
			wait = 0;
Packit 8480eb
			duration++;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!st_task_active(ap, state)) {
Packit 8480eb
			ret = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (seconds && duration >= seconds)
Packit 8480eb
			break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int st_wait_state(struct autofs_point *ap, enum states state)
Packit 8480eb
{
Packit 8480eb
	while (1) {
Packit 8480eb
		struct timespec t = { 0, 200000000 };
Packit 8480eb
		struct timespec r;
Packit 8480eb
Packit 8480eb
		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit 8480eb
			memcpy(&t, &r, sizeof(struct timespec));
Packit 8480eb
Packit 8480eb
		st_mutex_lock();
Packit 8480eb
		if (ap->state == state) {
Packit 8480eb
			st_mutex_unlock();
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
		st_mutex_unlock();
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
Packit 8480eb
static int run_state_task(struct state_queue *task)
Packit 8480eb
{
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
	enum states next_state, state;
Packit 8480eb
	unsigned long ret = 0;
Packit 8480eb
 
Packit 8480eb
	ap = task->ap;
Packit 8480eb
	next_state = task->state;
Packit 8480eb
Packit 8480eb
	state = ap->state;
Packit 8480eb
Packit 8480eb
	if (next_state != state) {
Packit 8480eb
		switch (next_state) {
Packit 8480eb
		case ST_PRUNE:
Packit 8480eb
			ret = st_prune(ap);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ST_EXPIRE:
Packit 8480eb
			ret = st_expire(ap);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ST_READMAP:
Packit 8480eb
			ret = st_readmap(ap);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ST_SHUTDOWN_PENDING:
Packit 8480eb
			ret = st_prepare_shutdown(ap);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ST_SHUTDOWN_FORCE:
Packit 8480eb
			ret = st_force_shutdown(ap);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			error(ap->logopt, "bad next state %d", next_state);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void st_set_thid(struct autofs_point *ap, pthread_t thid)
Packit 8480eb
{
Packit 8480eb
	struct list_head *p, *head = &state_queue;
Packit 8480eb
	struct state_queue *task;
Packit 8480eb
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		task = list_entry(p, struct state_queue, list);
Packit 8480eb
		if (task->ap == ap) {
Packit 8480eb
			task->thid = thid;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Requires state mutex to be held */
Packit 8480eb
static void st_set_done(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	struct list_head *p, *head;
Packit 8480eb
	struct state_queue *task;
Packit 8480eb
Packit 8480eb
	head = &state_queue;
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		task = list_entry(p, struct state_queue, list);
Packit 8480eb
		if (task->ap == ap) {
Packit 8480eb
			task->done = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void *st_queue_handler(void *arg)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head;
Packit 8480eb
	struct list_head *p;
Packit 8480eb
	int status, ret;
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
Packit 8480eb
	while (1) {
Packit 8480eb
		/*
Packit 8480eb
		 * If the state queue list is empty, wait until an
Packit 8480eb
		 * entry is added.
Packit 8480eb
		 */
Packit 8480eb
		head = &state_queue;
Packit 8480eb
Packit 8480eb
		while (list_empty(head)) {
Packit 8480eb
			status = pthread_cond_wait(&cond, &mutex);
Packit 8480eb
			if (status)
Packit 8480eb
				fatal(status);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		p = head->next;
Packit 8480eb
		while(p != head) {
Packit 8480eb
			struct state_queue *task;
Packit 8480eb
Packit 8480eb
			task = list_entry(p, struct state_queue, list);
Packit 8480eb
			p = p->next;
Packit 8480eb
Packit 8480eb
			if (task->cancel) {
Packit 8480eb
				list_del(&task->list);
Packit 8480eb
				free(task);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			task->busy = 1;
Packit 8480eb
Packit 8480eb
			ret = run_state_task(task);
Packit 8480eb
			if (!ret) {
Packit 8480eb
				list_del(&task->list);
Packit 8480eb
				free(task);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		while (1) {
Packit 8480eb
			signaled = 0;
Packit 8480eb
			while (!signaled) {
Packit 8480eb
				status = pthread_cond_wait(&cond, &mutex);
Packit 8480eb
				if (status)
Packit 8480eb
					fatal(status);
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			head = &state_queue;
Packit 8480eb
			p = head->next;
Packit 8480eb
			while (p != head) {
Packit 8480eb
				struct state_queue *task, *next;
Packit 8480eb
Packit 8480eb
				task = list_entry(p, struct state_queue, list);
Packit 8480eb
				p = p->next;
Packit 8480eb
Packit 8480eb
				/* Task may have been canceled before it started */
Packit 8480eb
				if (!task->thid && task->cancel)
Packit 8480eb
					goto remove;
Packit 8480eb
Packit 8480eb
				if (!task->busy) {
Packit 8480eb
					/* Start a new task */
Packit 8480eb
					task->busy = 1;
Packit 8480eb
Packit 8480eb
					ret = run_state_task(task);
Packit 8480eb
					if (!ret)
Packit 8480eb
						goto remove;
Packit 8480eb
					continue;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				/* Still starting up */
Packit 8480eb
				if (!task->thid)
Packit 8480eb
					continue;
Packit 8480eb
Packit 8480eb
				if (task->cancel) {
Packit 8480eb
					pthread_cancel(task->thid);
Packit 8480eb
					task->cancel = 0;
Packit 8480eb
					continue;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				/* Still busy */
Packit 8480eb
				if (!task->done)
Packit 8480eb
					continue;
Packit 8480eb
Packit 8480eb
remove:
Packit 8480eb
				/* No more tasks for this queue */
Packit 8480eb
				if (list_empty(&task->pending)) {
Packit 8480eb
					list_del(&task->list);
Packit 8480eb
					free(task);
Packit 8480eb
					continue;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				/* Next task */
Packit 8480eb
				next = list_entry((&task->pending)->next,
Packit 8480eb
							struct state_queue, pending);
Packit 8480eb
Packit 8480eb
				list_del(&task->list);
Packit 8480eb
				list_del_init(&next->pending);
Packit 8480eb
				free(task);
Packit 8480eb
Packit 8480eb
				list_add_tail(&next->list, head);
Packit 8480eb
				if (p == head)
Packit 8480eb
					p = head->next;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (list_empty(head))
Packit 8480eb
				break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int st_start_handler(void)
Packit 8480eb
{
Packit 8480eb
	pthread_t thid;
Packit 8480eb
	pthread_attr_t attrs;
Packit 8480eb
	pthread_attr_t *pattrs = &attrs;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	status = pthread_attr_init(pattrs);
Packit 8480eb
	if (status)
Packit 8480eb
		pattrs = NULL;
Packit 8480eb
	else {
Packit 8480eb
		pthread_attr_setdetachstate(pattrs, PTHREAD_CREATE_DETACHED);
Packit 8480eb
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
Packit 8480eb
		pthread_attr_setstacksize(pattrs, PTHREAD_STACK_MIN*4);
Packit 8480eb
#endif
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_create(&thid, pattrs, st_queue_handler, NULL);
Packit 8480eb
Packit 8480eb
	if (pattrs)
Packit 8480eb
		pthread_attr_destroy(pattrs);
Packit 8480eb
Packit 8480eb
	return !status;
Packit 8480eb
}
Packit 8480eb