xref: /freebsd/sys/kern/kern_alq.c (revision 9405072a95bb04a523c575dcda2d8baff812515d)
19405072aSJeff Roberson /*
29405072aSJeff Roberson  * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
39405072aSJeff Roberson  * All rights reserved.
49405072aSJeff Roberson  *
59405072aSJeff Roberson  * Redistribution and use in source and binary forms, with or without
69405072aSJeff Roberson  * modification, are permitted provided that the following conditions
79405072aSJeff Roberson  * are met:
89405072aSJeff Roberson  * 1. Redistributions of source code must retain the above copyright
99405072aSJeff Roberson  *    notice unmodified, this list of conditions, and the following
109405072aSJeff Roberson  *    disclaimer.
119405072aSJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
129405072aSJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
139405072aSJeff Roberson  *    documentation and/or other materials provided with the distribution.
149405072aSJeff Roberson  *
159405072aSJeff Roberson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
169405072aSJeff Roberson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
179405072aSJeff Roberson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
189405072aSJeff Roberson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
199405072aSJeff Roberson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
209405072aSJeff Roberson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
219405072aSJeff Roberson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
229405072aSJeff Roberson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
239405072aSJeff Roberson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
249405072aSJeff Roberson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
259405072aSJeff Roberson  *
269405072aSJeff Roberson  * $FreeBSD$
279405072aSJeff Roberson  *
289405072aSJeff Roberson  */
299405072aSJeff Roberson 
309405072aSJeff Roberson #include <sys/param.h>
319405072aSJeff Roberson #include <sys/systm.h>
329405072aSJeff Roberson #include <sys/kernel.h>
339405072aSJeff Roberson #include <sys/kthread.h>
349405072aSJeff Roberson #include <sys/lock.h>
359405072aSJeff Roberson #include <sys/mutex.h>
369405072aSJeff Roberson #include <sys/namei.h>
379405072aSJeff Roberson #include <sys/proc.h>
389405072aSJeff Roberson #include <sys/vnode.h>
399405072aSJeff Roberson #include <sys/alq.h>
409405072aSJeff Roberson #include <sys/malloc.h>
419405072aSJeff Roberson #include <sys/unistd.h>
429405072aSJeff Roberson #include <sys/fcntl.h>
439405072aSJeff Roberson #include <sys/eventhandler.h>
449405072aSJeff Roberson 
459405072aSJeff Roberson /* Async. Logging Queue */
469405072aSJeff Roberson struct alq {
479405072aSJeff Roberson 	int	aq_entmax;		/* Max entries */
489405072aSJeff Roberson 	int	aq_entlen;		/* Entry length */
499405072aSJeff Roberson 	char	*aq_entbuf;		/* Buffer for stored entries */
509405072aSJeff Roberson 	int	aq_flags;		/* Queue flags */
519405072aSJeff Roberson 	struct mtx	aq_mtx;		/* Queue lock */
529405072aSJeff Roberson 	struct vnode	*aq_vp;		/* Open vnode handle */
539405072aSJeff Roberson 	struct thread	*aq_td;		/* Thread that opened the vnode */
549405072aSJeff Roberson 	struct ale	*aq_first;	/* First ent */
559405072aSJeff Roberson 	struct ale	*aq_entfree;	/* First free ent */
569405072aSJeff Roberson 	struct ale	*aq_entvalid;	/* First ent valid for writing */
579405072aSJeff Roberson 	LIST_ENTRY(alq)	aq_act;		/* List of active queues */
589405072aSJeff Roberson 	LIST_ENTRY(alq)	aq_link;	/* List of all queues */
599405072aSJeff Roberson };
609405072aSJeff Roberson 
619405072aSJeff Roberson #define	AQ_WANTED	0x0001		/* Wakeup sleeper when io is done */
629405072aSJeff Roberson #define	AQ_ACTIVE	0x0002		/* on the active list */
639405072aSJeff Roberson #define	AQ_FLUSHING	0x0004		/* doing IO */
649405072aSJeff Roberson #define	AQ_SHUTDOWN	0x0008		/* Queue no longer valid */
659405072aSJeff Roberson 
669405072aSJeff Roberson #define	ALQ_LOCK(alq)	mtx_lock_spin(&(alq)->aq_mtx)
679405072aSJeff Roberson #define	ALQ_UNLOCK(alq)	mtx_unlock_spin(&(alq)->aq_mtx)
689405072aSJeff Roberson 
699405072aSJeff Roberson static MALLOC_DEFINE(M_ALD, "ALD", "ALD");
709405072aSJeff Roberson 
719405072aSJeff Roberson /*
729405072aSJeff Roberson  * The ald_mtx protects the ald_queues list and the ald_active list.
739405072aSJeff Roberson  */
749405072aSJeff Roberson static struct mtx ald_mtx;
759405072aSJeff Roberson static LIST_HEAD(, alq) ald_queues;
769405072aSJeff Roberson static LIST_HEAD(, alq) ald_active;
779405072aSJeff Roberson static struct proc *ald_thread;
789405072aSJeff Roberson static int ald_shutingdown = 0;
799405072aSJeff Roberson 
809405072aSJeff Roberson #define	ALD_LOCK()	mtx_lock(&ald_mtx)
819405072aSJeff Roberson #define	ALD_UNLOCK()	mtx_unlock(&ald_mtx)
829405072aSJeff Roberson 
839405072aSJeff Roberson /* Daemon functions */
849405072aSJeff Roberson static int ald_add(struct alq *);
859405072aSJeff Roberson static int ald_rem(struct alq *);
869405072aSJeff Roberson static void ald_startup(void *);
879405072aSJeff Roberson static void ald_daemon(void);
889405072aSJeff Roberson static void ald_shutdown(void *, int);
899405072aSJeff Roberson static void ald_activate(struct alq *);
909405072aSJeff Roberson static void ald_deactivate(struct alq *);
919405072aSJeff Roberson 
929405072aSJeff Roberson /* Internal queue functions */
939405072aSJeff Roberson static void alq_shutdown(struct alq *);
949405072aSJeff Roberson static int alq_doio(struct alq *);
959405072aSJeff Roberson 
969405072aSJeff Roberson 
979405072aSJeff Roberson /*
989405072aSJeff Roberson  * Add a new queue to the global list.  Fail if we're shutting down.
999405072aSJeff Roberson  */
1009405072aSJeff Roberson static int
1019405072aSJeff Roberson ald_add(struct alq *alq)
1029405072aSJeff Roberson {
1039405072aSJeff Roberson 	int error;
1049405072aSJeff Roberson 
1059405072aSJeff Roberson 	error = 0;
1069405072aSJeff Roberson 
1079405072aSJeff Roberson 	ALD_LOCK();
1089405072aSJeff Roberson 	if (ald_shutingdown) {
1099405072aSJeff Roberson 		error = EBUSY;
1109405072aSJeff Roberson 		goto done;
1119405072aSJeff Roberson 	}
1129405072aSJeff Roberson 	LIST_INSERT_HEAD(&ald_queues, alq, aq_link);
1139405072aSJeff Roberson done:
1149405072aSJeff Roberson 	ALD_UNLOCK();
1159405072aSJeff Roberson 	return (error);
1169405072aSJeff Roberson }
1179405072aSJeff Roberson 
1189405072aSJeff Roberson /*
1199405072aSJeff Roberson  * Remove a queue from the global list unless we're shutting down.  If so,
1209405072aSJeff Roberson  * the ald will take care of cleaning up it's resources.
1219405072aSJeff Roberson  */
1229405072aSJeff Roberson static int
1239405072aSJeff Roberson ald_rem(struct alq *alq)
1249405072aSJeff Roberson {
1259405072aSJeff Roberson 	int error;
1269405072aSJeff Roberson 
1279405072aSJeff Roberson 	error = 0;
1289405072aSJeff Roberson 
1299405072aSJeff Roberson 	ALD_LOCK();
1309405072aSJeff Roberson 	if (ald_shutingdown) {
1319405072aSJeff Roberson 		error = EBUSY;
1329405072aSJeff Roberson 		goto done;
1339405072aSJeff Roberson 	}
1349405072aSJeff Roberson 	LIST_REMOVE(alq, aq_link);
1359405072aSJeff Roberson done:
1369405072aSJeff Roberson 	ALD_UNLOCK();
1379405072aSJeff Roberson 	return (error);
1389405072aSJeff Roberson }
1399405072aSJeff Roberson 
1409405072aSJeff Roberson /*
1419405072aSJeff Roberson  * Put a queue on the active list.  This will schedule it for writing.
1429405072aSJeff Roberson  */
1439405072aSJeff Roberson static void
1449405072aSJeff Roberson ald_activate(struct alq *alq)
1459405072aSJeff Roberson {
1469405072aSJeff Roberson 	LIST_INSERT_HEAD(&ald_active, alq, aq_act);
1479405072aSJeff Roberson 	wakeup(&ald_active);
1489405072aSJeff Roberson }
1499405072aSJeff Roberson 
1509405072aSJeff Roberson static void
1519405072aSJeff Roberson ald_deactivate(struct alq *alq)
1529405072aSJeff Roberson {
1539405072aSJeff Roberson 	LIST_REMOVE(alq, aq_act);
1549405072aSJeff Roberson 	alq->aq_flags &= ~AQ_ACTIVE;
1559405072aSJeff Roberson }
1569405072aSJeff Roberson 
1579405072aSJeff Roberson static void
1589405072aSJeff Roberson ald_startup(void *unused)
1599405072aSJeff Roberson {
1609405072aSJeff Roberson 	mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET);
1619405072aSJeff Roberson 	LIST_INIT(&ald_queues);
1629405072aSJeff Roberson 	LIST_INIT(&ald_active);
1639405072aSJeff Roberson }
1649405072aSJeff Roberson 
1659405072aSJeff Roberson static void
1669405072aSJeff Roberson ald_daemon(void)
1679405072aSJeff Roberson {
1689405072aSJeff Roberson 	int needwakeup;
1699405072aSJeff Roberson 	struct alq *alq;
1709405072aSJeff Roberson 
1719405072aSJeff Roberson 	mtx_lock(&Giant);
1729405072aSJeff Roberson 
1739405072aSJeff Roberson 	EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL,
1749405072aSJeff Roberson 	    SHUTDOWN_PRI_FIRST);
1759405072aSJeff Roberson 
1769405072aSJeff Roberson 	ALD_LOCK();
1779405072aSJeff Roberson 
1789405072aSJeff Roberson 	for (;;) {
1799405072aSJeff Roberson 		while ((alq = LIST_FIRST(&ald_active)) == NULL)
1809405072aSJeff Roberson 			msleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0);
1819405072aSJeff Roberson 
1829405072aSJeff Roberson 		ALQ_LOCK(alq);
1839405072aSJeff Roberson 		ald_deactivate(alq);
1849405072aSJeff Roberson 		ALD_UNLOCK();
1859405072aSJeff Roberson 		needwakeup = alq_doio(alq);
1869405072aSJeff Roberson 		ALQ_UNLOCK(alq);
1879405072aSJeff Roberson 		if (needwakeup)
1889405072aSJeff Roberson 			wakeup(alq);
1899405072aSJeff Roberson 		ALD_LOCK();
1909405072aSJeff Roberson 	}
1919405072aSJeff Roberson }
1929405072aSJeff Roberson 
1939405072aSJeff Roberson static void
1949405072aSJeff Roberson ald_shutdown(void *arg, int howto)
1959405072aSJeff Roberson {
1969405072aSJeff Roberson 	struct alq *alq;
1979405072aSJeff Roberson 
1989405072aSJeff Roberson 	ALD_LOCK();
1999405072aSJeff Roberson 	ald_shutingdown = 1;
2009405072aSJeff Roberson 
2019405072aSJeff Roberson 	while ((alq = LIST_FIRST(&ald_queues)) != NULL) {
2029405072aSJeff Roberson 		LIST_REMOVE(alq, aq_link);
2039405072aSJeff Roberson 		ALD_UNLOCK();
2049405072aSJeff Roberson 		alq_shutdown(alq);
2059405072aSJeff Roberson 		ALD_LOCK();
2069405072aSJeff Roberson 	}
2079405072aSJeff Roberson 	ALD_UNLOCK();
2089405072aSJeff Roberson }
2099405072aSJeff Roberson 
2109405072aSJeff Roberson static void
2119405072aSJeff Roberson alq_shutdown(struct alq *alq)
2129405072aSJeff Roberson {
2139405072aSJeff Roberson 	ALQ_LOCK(alq);
2149405072aSJeff Roberson 
2159405072aSJeff Roberson 	/* Stop any new writers. */
2169405072aSJeff Roberson 	alq->aq_flags |= AQ_SHUTDOWN;
2179405072aSJeff Roberson 
2189405072aSJeff Roberson 	/* Drain IO */
2199405072aSJeff Roberson 	while (alq->aq_flags & (AQ_FLUSHING|AQ_ACTIVE)) {
2209405072aSJeff Roberson 		alq->aq_flags |= AQ_WANTED;
2219405072aSJeff Roberson 		ALQ_UNLOCK(alq);
2229405072aSJeff Roberson 		tsleep(alq, PWAIT, "aldclose", 0);
2239405072aSJeff Roberson 		ALQ_LOCK(alq);
2249405072aSJeff Roberson 	}
2259405072aSJeff Roberson 	ALQ_UNLOCK(alq);
2269405072aSJeff Roberson 
2279405072aSJeff Roberson 	vn_close(alq->aq_vp, FREAD|FWRITE, alq->aq_td->td_ucred,
2289405072aSJeff Roberson 	    alq->aq_td);
2299405072aSJeff Roberson }
2309405072aSJeff Roberson 
2319405072aSJeff Roberson /*
2329405072aSJeff Roberson  * Flush all pending data to disk.  This operation will block.
2339405072aSJeff Roberson  */
2349405072aSJeff Roberson static int
2359405072aSJeff Roberson alq_doio(struct alq *alq)
2369405072aSJeff Roberson {
2379405072aSJeff Roberson 	struct thread *td;
2389405072aSJeff Roberson 	struct mount *mp;
2399405072aSJeff Roberson 	struct vnode *vp;
2409405072aSJeff Roberson 	struct uio auio;
2419405072aSJeff Roberson 	struct iovec aiov[2];
2429405072aSJeff Roberson 	struct ale *ale;
2439405072aSJeff Roberson 	struct ale *alstart;
2449405072aSJeff Roberson 	int totlen;
2459405072aSJeff Roberson 	int iov;
2469405072aSJeff Roberson 
2479405072aSJeff Roberson 	vp = alq->aq_vp;
2489405072aSJeff Roberson 	td = curthread;
2499405072aSJeff Roberson 	totlen = 0;
2509405072aSJeff Roberson 	iov = 0;
2519405072aSJeff Roberson 
2529405072aSJeff Roberson 	alstart = ale = alq->aq_entvalid;
2539405072aSJeff Roberson 	alq->aq_entvalid = NULL;
2549405072aSJeff Roberson 
2559405072aSJeff Roberson 	bzero(&aiov, sizeof(aiov));
2569405072aSJeff Roberson 	bzero(&auio, sizeof(auio));
2579405072aSJeff Roberson 
2589405072aSJeff Roberson 	do {
2599405072aSJeff Roberson 		if (aiov[iov].iov_base == NULL)
2609405072aSJeff Roberson 			aiov[iov].iov_base = ale->ae_data;
2619405072aSJeff Roberson 		aiov[iov].iov_len += alq->aq_entlen;
2629405072aSJeff Roberson 		totlen += alq->aq_entlen;
2639405072aSJeff Roberson 		/* Check to see if we're wrapping the buffer */
2649405072aSJeff Roberson 		if (ale->ae_data + alq->aq_entlen != ale->ae_next->ae_data)
2659405072aSJeff Roberson 			iov++;
2669405072aSJeff Roberson 		ale->ae_flags &= ~AE_VALID;
2679405072aSJeff Roberson 		ale = ale->ae_next;
2689405072aSJeff Roberson 	} while (ale->ae_flags & AE_VALID);
2699405072aSJeff Roberson 
2709405072aSJeff Roberson 	alq->aq_flags |= AQ_FLUSHING;
2719405072aSJeff Roberson 	ALQ_UNLOCK(alq);
2729405072aSJeff Roberson 
2739405072aSJeff Roberson 	if (iov == 2 || aiov[iov].iov_base == NULL)
2749405072aSJeff Roberson 		iov--;
2759405072aSJeff Roberson 
2769405072aSJeff Roberson 	auio.uio_iov = &aiov[0];
2779405072aSJeff Roberson 	auio.uio_offset = 0;
2789405072aSJeff Roberson 	auio.uio_segflg = UIO_SYSSPACE;
2799405072aSJeff Roberson 	auio.uio_rw = UIO_WRITE;
2809405072aSJeff Roberson 	auio.uio_iovcnt = iov + 1;
2819405072aSJeff Roberson 	auio.uio_resid = totlen;
2829405072aSJeff Roberson 	auio.uio_td = td;
2839405072aSJeff Roberson 
2849405072aSJeff Roberson 	/*
2859405072aSJeff Roberson 	 * Do all of the junk required to write now.
2869405072aSJeff Roberson 	 */
2879405072aSJeff Roberson 	vn_start_write(vp, &mp, V_WAIT);
2889405072aSJeff Roberson 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2899405072aSJeff Roberson 	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2909405072aSJeff Roberson 	/* XXX error ignored */
2919405072aSJeff Roberson 	VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, td->td_ucred);
2929405072aSJeff Roberson 	VOP_UNLOCK(vp, 0, td);
2939405072aSJeff Roberson 	vn_finished_write(mp);
2949405072aSJeff Roberson 
2959405072aSJeff Roberson 	ALQ_LOCK(alq);
2969405072aSJeff Roberson 	alq->aq_flags &= ~AQ_FLUSHING;
2979405072aSJeff Roberson 
2989405072aSJeff Roberson 	if (alq->aq_entfree == NULL)
2999405072aSJeff Roberson 		alq->aq_entfree = alstart;
3009405072aSJeff Roberson 
3019405072aSJeff Roberson 	if (alq->aq_flags & AQ_WANTED) {
3029405072aSJeff Roberson 		alq->aq_flags &= ~AQ_WANTED;
3039405072aSJeff Roberson 		return (1);
3049405072aSJeff Roberson 	}
3059405072aSJeff Roberson 
3069405072aSJeff Roberson 	return(0);
3079405072aSJeff Roberson }
3089405072aSJeff Roberson 
3099405072aSJeff Roberson static struct kproc_desc ald_kp = {
3109405072aSJeff Roberson         "ALQ Daemon",
3119405072aSJeff Roberson         ald_daemon,
3129405072aSJeff Roberson         &ald_thread
3139405072aSJeff Roberson };
3149405072aSJeff Roberson 
3159405072aSJeff Roberson SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp)
3169405072aSJeff Roberson SYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL)
3179405072aSJeff Roberson 
3189405072aSJeff Roberson 
3199405072aSJeff Roberson /* User visible queue functions */
3209405072aSJeff Roberson 
3219405072aSJeff Roberson /*
3229405072aSJeff Roberson  * Create the queue data structure, allocate the buffer, and open the file.
3239405072aSJeff Roberson  */
3249405072aSJeff Roberson int
3259405072aSJeff Roberson alq_open(struct alq **alqp, const char *file, int size, int count)
3269405072aSJeff Roberson {
3279405072aSJeff Roberson 	struct thread *td;
3289405072aSJeff Roberson 	struct nameidata nd;
3299405072aSJeff Roberson 	struct ale *ale;
3309405072aSJeff Roberson 	struct ale *alp;
3319405072aSJeff Roberson 	struct alq *alq;
3329405072aSJeff Roberson 	char *bufp;
3339405072aSJeff Roberson 	int flags;
3349405072aSJeff Roberson 	int error;
3359405072aSJeff Roberson 	int i;
3369405072aSJeff Roberson 
3379405072aSJeff Roberson 	*alqp = NULL;
3389405072aSJeff Roberson 	td = curthread;
3399405072aSJeff Roberson 
3409405072aSJeff Roberson 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td);
3419405072aSJeff Roberson 	flags = FREAD | FWRITE | O_NOFOLLOW | O_CREAT;
3429405072aSJeff Roberson 
3439405072aSJeff Roberson 	error = vn_open(&nd, &flags, 0);
3449405072aSJeff Roberson 	if (error)
3459405072aSJeff Roberson 		return (error);
3469405072aSJeff Roberson 
3479405072aSJeff Roberson 	NDFREE(&nd, NDF_ONLY_PNBUF);
3489405072aSJeff Roberson 	/* We just unlock so we hold a reference */
3499405072aSJeff Roberson 	VOP_UNLOCK(nd.ni_vp, 0, td);
3509405072aSJeff Roberson 
3519405072aSJeff Roberson 	alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO);
3529405072aSJeff Roberson 	alq->aq_entbuf = malloc(count * size, M_ALD, M_WAITOK|M_ZERO);
3539405072aSJeff Roberson 	alq->aq_first = malloc(sizeof(*ale) * count, M_ALD, M_WAITOK|M_ZERO);
3549405072aSJeff Roberson 	alq->aq_vp = nd.ni_vp;
3559405072aSJeff Roberson 	alq->aq_td = td;
3569405072aSJeff Roberson 	alq->aq_entmax = count;
3579405072aSJeff Roberson 	alq->aq_entlen = size;
3589405072aSJeff Roberson 	alq->aq_entfree = alq->aq_first;
3599405072aSJeff Roberson 
3609405072aSJeff Roberson 	mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET);
3619405072aSJeff Roberson 
3629405072aSJeff Roberson 	bufp = alq->aq_entbuf;
3639405072aSJeff Roberson 	ale = alq->aq_first;
3649405072aSJeff Roberson 	alp = NULL;
3659405072aSJeff Roberson 
3669405072aSJeff Roberson 	/* Match up entries with buffers */
3679405072aSJeff Roberson 	for (i = 0; i < count; i++) {
3689405072aSJeff Roberson 		if (alp)
3699405072aSJeff Roberson 			alp->ae_next = ale;
3709405072aSJeff Roberson 		ale->ae_data = bufp;
3719405072aSJeff Roberson 		alp = ale;
3729405072aSJeff Roberson 		ale++;
3739405072aSJeff Roberson 		bufp += size;
3749405072aSJeff Roberson 	}
3759405072aSJeff Roberson 
3769405072aSJeff Roberson 	alp->ae_next = alq->aq_first;
3779405072aSJeff Roberson 
3789405072aSJeff Roberson 	if ((error = ald_add(alq)) != 0)
3799405072aSJeff Roberson 		return (error);
3809405072aSJeff Roberson 	*alqp = alq;
3819405072aSJeff Roberson 
3829405072aSJeff Roberson 	return (0);
3839405072aSJeff Roberson }
3849405072aSJeff Roberson 
3859405072aSJeff Roberson /*
3869405072aSJeff Roberson  * Copy a new entry into the queue.  If the operation would block either
3879405072aSJeff Roberson  * wait or return an error depending on the value of waitok.
3889405072aSJeff Roberson  */
3899405072aSJeff Roberson int
3909405072aSJeff Roberson alq_write(struct alq *alq, void *data, int waitok)
3919405072aSJeff Roberson {
3929405072aSJeff Roberson 	struct ale *ale;
3939405072aSJeff Roberson 
3949405072aSJeff Roberson 	if ((ale = alq_get(alq, waitok)) == NULL)
3959405072aSJeff Roberson 		return (EWOULDBLOCK);
3969405072aSJeff Roberson 
3979405072aSJeff Roberson 	bcopy(data, ale->ae_data, alq->aq_entlen);
3989405072aSJeff Roberson 	alq_post(alq, ale);
3999405072aSJeff Roberson 
4009405072aSJeff Roberson 	return (0);
4019405072aSJeff Roberson }
4029405072aSJeff Roberson 
4039405072aSJeff Roberson struct ale *
4049405072aSJeff Roberson alq_get(struct alq *alq, int waitok)
4059405072aSJeff Roberson {
4069405072aSJeff Roberson 	struct ale *ale;
4079405072aSJeff Roberson 	struct ale *aln;
4089405072aSJeff Roberson 
4099405072aSJeff Roberson 	ale = NULL;
4109405072aSJeff Roberson 
4119405072aSJeff Roberson 	ALQ_LOCK(alq);
4129405072aSJeff Roberson 
4139405072aSJeff Roberson 	/* Loop until we get an entry or we're shutting down */
4149405072aSJeff Roberson 	while ((alq->aq_flags & AQ_SHUTDOWN) == 0 &&
4159405072aSJeff Roberson 	    (ale = alq->aq_entfree) == NULL &&
4169405072aSJeff Roberson 	    (waitok & ALQ_WAITOK)) {
4179405072aSJeff Roberson 		alq->aq_flags |= AQ_WANTED;
4189405072aSJeff Roberson 		ALQ_UNLOCK(alq);
4199405072aSJeff Roberson 		tsleep(alq, PWAIT, "alqget", 0);
4209405072aSJeff Roberson 		ALQ_LOCK(alq);
4219405072aSJeff Roberson 	}
4229405072aSJeff Roberson 
4239405072aSJeff Roberson 	if (ale != NULL) {
4249405072aSJeff Roberson 		aln = ale->ae_next;
4259405072aSJeff Roberson 		if ((aln->ae_flags & AE_VALID) == 0)
4269405072aSJeff Roberson 			alq->aq_entfree = aln;
4279405072aSJeff Roberson 	} else
4289405072aSJeff Roberson 		ALQ_UNLOCK(alq);
4299405072aSJeff Roberson 
4309405072aSJeff Roberson 
4319405072aSJeff Roberson 	return (ale);
4329405072aSJeff Roberson }
4339405072aSJeff Roberson 
4349405072aSJeff Roberson void
4359405072aSJeff Roberson alq_post(struct alq *alq, struct ale *ale)
4369405072aSJeff Roberson {
4379405072aSJeff Roberson 	int activate;
4389405072aSJeff Roberson 
4399405072aSJeff Roberson 	ale->ae_flags |= AE_VALID;
4409405072aSJeff Roberson 
4419405072aSJeff Roberson 	if (alq->aq_entvalid == NULL)
4429405072aSJeff Roberson 		alq->aq_entvalid = ale;
4439405072aSJeff Roberson 
4449405072aSJeff Roberson 	if ((alq->aq_flags & AQ_ACTIVE) == 0) {
4459405072aSJeff Roberson 		alq->aq_flags |= AQ_ACTIVE;
4469405072aSJeff Roberson 		activate = 1;
4479405072aSJeff Roberson 	} else
4489405072aSJeff Roberson 		activate = 0;
4499405072aSJeff Roberson 
4509405072aSJeff Roberson 	ALQ_UNLOCK(alq);
4519405072aSJeff Roberson 	if (activate) {
4529405072aSJeff Roberson 		ALD_LOCK();
4539405072aSJeff Roberson 		ald_activate(alq);
4549405072aSJeff Roberson 		ALD_UNLOCK();
4559405072aSJeff Roberson 	}
4569405072aSJeff Roberson }
4579405072aSJeff Roberson 
4589405072aSJeff Roberson void
4599405072aSJeff Roberson alq_flush(struct alq *alq)
4609405072aSJeff Roberson {
4619405072aSJeff Roberson 	int needwakeup = 0;
4629405072aSJeff Roberson 
4639405072aSJeff Roberson 	ALD_LOCK();
4649405072aSJeff Roberson 	ALQ_LOCK(alq);
4659405072aSJeff Roberson 	if (alq->aq_flags & AQ_ACTIVE) {
4669405072aSJeff Roberson 		ald_deactivate(alq);
4679405072aSJeff Roberson 		ALD_UNLOCK();
4689405072aSJeff Roberson 		needwakeup = alq_doio(alq);
4699405072aSJeff Roberson 	} else
4709405072aSJeff Roberson 		ALD_UNLOCK();
4719405072aSJeff Roberson 	ALQ_UNLOCK(alq);
4729405072aSJeff Roberson 
4739405072aSJeff Roberson 	if (needwakeup)
4749405072aSJeff Roberson 		wakeup(alq);
4759405072aSJeff Roberson }
4769405072aSJeff Roberson 
4779405072aSJeff Roberson /*
4789405072aSJeff Roberson  * Flush remaining data, close the file and free all resources.
4799405072aSJeff Roberson  */
4809405072aSJeff Roberson void
4819405072aSJeff Roberson alq_close(struct alq *alq)
4829405072aSJeff Roberson {
4839405072aSJeff Roberson 	/*
4849405072aSJeff Roberson 	 * If we're already shuting down someone else will flush and close
4859405072aSJeff Roberson 	 * the vnode.
4869405072aSJeff Roberson 	 */
4879405072aSJeff Roberson 	if (ald_rem(alq) != 0)
4889405072aSJeff Roberson 		return;
4899405072aSJeff Roberson 
4909405072aSJeff Roberson 	/*
4919405072aSJeff Roberson 	 * Drain all pending IO.
4929405072aSJeff Roberson 	 */
4939405072aSJeff Roberson 	alq_shutdown(alq);
4949405072aSJeff Roberson 
4959405072aSJeff Roberson 	mtx_destroy(&alq->aq_mtx);
4969405072aSJeff Roberson 	free(alq->aq_first, M_ALD);
4979405072aSJeff Roberson 	free(alq->aq_entbuf, M_ALD);
4989405072aSJeff Roberson 	free(alq, M_ALD);
4999405072aSJeff Roberson }
500