xref: /freebsd/sys/kern/kern_alq.c (revision 9454b2d864463f856c6aaf147851104b25cf4037)
19454b2d8SWarner Losh /*-
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 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
3067536f03SRobert Watson #include "opt_mac.h"
3167536f03SRobert Watson 
329405072aSJeff Roberson #include <sys/param.h>
339405072aSJeff Roberson #include <sys/systm.h>
349405072aSJeff Roberson #include <sys/kernel.h>
359405072aSJeff Roberson #include <sys/kthread.h>
369405072aSJeff Roberson #include <sys/lock.h>
3767536f03SRobert Watson #include <sys/mac.h>
389405072aSJeff Roberson #include <sys/mutex.h>
399405072aSJeff Roberson #include <sys/namei.h>
409405072aSJeff Roberson #include <sys/proc.h>
419405072aSJeff Roberson #include <sys/vnode.h>
429405072aSJeff Roberson #include <sys/alq.h>
439405072aSJeff Roberson #include <sys/malloc.h>
449405072aSJeff Roberson #include <sys/unistd.h>
459405072aSJeff Roberson #include <sys/fcntl.h>
469405072aSJeff Roberson #include <sys/eventhandler.h>
479405072aSJeff Roberson 
489405072aSJeff Roberson /* Async. Logging Queue */
499405072aSJeff Roberson struct alq {
509405072aSJeff Roberson 	int	aq_entmax;		/* Max entries */
519405072aSJeff Roberson 	int	aq_entlen;		/* Entry length */
529405072aSJeff Roberson 	char	*aq_entbuf;		/* Buffer for stored entries */
539405072aSJeff Roberson 	int	aq_flags;		/* Queue flags */
549405072aSJeff Roberson 	struct mtx	aq_mtx;		/* Queue lock */
559405072aSJeff Roberson 	struct vnode	*aq_vp;		/* Open vnode handle */
569e9256e2SJeff Roberson 	struct ucred	*aq_cred;	/* Credentials of the opening thread */
579405072aSJeff Roberson 	struct ale	*aq_first;	/* First ent */
589405072aSJeff Roberson 	struct ale	*aq_entfree;	/* First free ent */
599405072aSJeff Roberson 	struct ale	*aq_entvalid;	/* First ent valid for writing */
609405072aSJeff Roberson 	LIST_ENTRY(alq)	aq_act;		/* List of active queues */
619405072aSJeff Roberson 	LIST_ENTRY(alq)	aq_link;	/* List of all queues */
629405072aSJeff Roberson };
639405072aSJeff Roberson 
649405072aSJeff Roberson #define	AQ_WANTED	0x0001		/* Wakeup sleeper when io is done */
659405072aSJeff Roberson #define	AQ_ACTIVE	0x0002		/* on the active list */
669405072aSJeff Roberson #define	AQ_FLUSHING	0x0004		/* doing IO */
679405072aSJeff Roberson #define	AQ_SHUTDOWN	0x0008		/* Queue no longer valid */
689405072aSJeff Roberson 
699405072aSJeff Roberson #define	ALQ_LOCK(alq)	mtx_lock_spin(&(alq)->aq_mtx)
709405072aSJeff Roberson #define	ALQ_UNLOCK(alq)	mtx_unlock_spin(&(alq)->aq_mtx)
719405072aSJeff Roberson 
729405072aSJeff Roberson static MALLOC_DEFINE(M_ALD, "ALD", "ALD");
739405072aSJeff Roberson 
749405072aSJeff Roberson /*
759405072aSJeff Roberson  * The ald_mtx protects the ald_queues list and the ald_active list.
769405072aSJeff Roberson  */
779405072aSJeff Roberson static struct mtx ald_mtx;
789405072aSJeff Roberson static LIST_HEAD(, alq) ald_queues;
799405072aSJeff Roberson static LIST_HEAD(, alq) ald_active;
809405072aSJeff Roberson static int ald_shutingdown = 0;
81a414302fSJeff Roberson struct thread *ald_thread;
82a414302fSJeff Roberson static struct proc *ald_proc;
839405072aSJeff Roberson 
849405072aSJeff Roberson #define	ALD_LOCK()	mtx_lock(&ald_mtx)
859405072aSJeff Roberson #define	ALD_UNLOCK()	mtx_unlock(&ald_mtx)
869405072aSJeff Roberson 
879405072aSJeff Roberson /* Daemon functions */
889405072aSJeff Roberson static int ald_add(struct alq *);
899405072aSJeff Roberson static int ald_rem(struct alq *);
909405072aSJeff Roberson static void ald_startup(void *);
919405072aSJeff Roberson static void ald_daemon(void);
929405072aSJeff Roberson static void ald_shutdown(void *, int);
939405072aSJeff Roberson static void ald_activate(struct alq *);
949405072aSJeff Roberson static void ald_deactivate(struct alq *);
959405072aSJeff Roberson 
969405072aSJeff Roberson /* Internal queue functions */
979405072aSJeff Roberson static void alq_shutdown(struct alq *);
989405072aSJeff Roberson static int alq_doio(struct alq *);
999405072aSJeff Roberson 
1009405072aSJeff Roberson 
1019405072aSJeff Roberson /*
1029405072aSJeff Roberson  * Add a new queue to the global list.  Fail if we're shutting down.
1039405072aSJeff Roberson  */
1049405072aSJeff Roberson static int
1059405072aSJeff Roberson ald_add(struct alq *alq)
1069405072aSJeff Roberson {
1079405072aSJeff Roberson 	int error;
1089405072aSJeff Roberson 
1099405072aSJeff Roberson 	error = 0;
1109405072aSJeff Roberson 
1119405072aSJeff Roberson 	ALD_LOCK();
1129405072aSJeff Roberson 	if (ald_shutingdown) {
1139405072aSJeff Roberson 		error = EBUSY;
1149405072aSJeff Roberson 		goto done;
1159405072aSJeff Roberson 	}
1169405072aSJeff Roberson 	LIST_INSERT_HEAD(&ald_queues, alq, aq_link);
1179405072aSJeff Roberson done:
1189405072aSJeff Roberson 	ALD_UNLOCK();
1199405072aSJeff Roberson 	return (error);
1209405072aSJeff Roberson }
1219405072aSJeff Roberson 
1229405072aSJeff Roberson /*
1239405072aSJeff Roberson  * Remove a queue from the global list unless we're shutting down.  If so,
1249405072aSJeff Roberson  * the ald will take care of cleaning up it's resources.
1259405072aSJeff Roberson  */
1269405072aSJeff Roberson static int
1279405072aSJeff Roberson ald_rem(struct alq *alq)
1289405072aSJeff Roberson {
1299405072aSJeff Roberson 	int error;
1309405072aSJeff Roberson 
1319405072aSJeff Roberson 	error = 0;
1329405072aSJeff Roberson 
1339405072aSJeff Roberson 	ALD_LOCK();
1349405072aSJeff Roberson 	if (ald_shutingdown) {
1359405072aSJeff Roberson 		error = EBUSY;
1369405072aSJeff Roberson 		goto done;
1379405072aSJeff Roberson 	}
1389405072aSJeff Roberson 	LIST_REMOVE(alq, aq_link);
1399405072aSJeff Roberson done:
1409405072aSJeff Roberson 	ALD_UNLOCK();
1419405072aSJeff Roberson 	return (error);
1429405072aSJeff Roberson }
1439405072aSJeff Roberson 
1449405072aSJeff Roberson /*
1459405072aSJeff Roberson  * Put a queue on the active list.  This will schedule it for writing.
1469405072aSJeff Roberson  */
1479405072aSJeff Roberson static void
1489405072aSJeff Roberson ald_activate(struct alq *alq)
1499405072aSJeff Roberson {
1509405072aSJeff Roberson 	LIST_INSERT_HEAD(&ald_active, alq, aq_act);
1519405072aSJeff Roberson 	wakeup(&ald_active);
1529405072aSJeff Roberson }
1539405072aSJeff Roberson 
1549405072aSJeff Roberson static void
1559405072aSJeff Roberson ald_deactivate(struct alq *alq)
1569405072aSJeff Roberson {
1579405072aSJeff Roberson 	LIST_REMOVE(alq, aq_act);
1589405072aSJeff Roberson 	alq->aq_flags &= ~AQ_ACTIVE;
1599405072aSJeff Roberson }
1609405072aSJeff Roberson 
1619405072aSJeff Roberson static void
1629405072aSJeff Roberson ald_startup(void *unused)
1639405072aSJeff Roberson {
1649405072aSJeff Roberson 	mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET);
1659405072aSJeff Roberson 	LIST_INIT(&ald_queues);
1669405072aSJeff Roberson 	LIST_INIT(&ald_active);
1679405072aSJeff Roberson }
1689405072aSJeff Roberson 
1699405072aSJeff Roberson static void
1709405072aSJeff Roberson ald_daemon(void)
1719405072aSJeff Roberson {
1729405072aSJeff Roberson 	int needwakeup;
1739405072aSJeff Roberson 	struct alq *alq;
1749405072aSJeff Roberson 
1759405072aSJeff Roberson 	mtx_lock(&Giant);
1769405072aSJeff Roberson 
177a414302fSJeff Roberson 	ald_thread = FIRST_THREAD_IN_PROC(ald_proc);
178a414302fSJeff Roberson 
1799405072aSJeff Roberson 	EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL,
1809405072aSJeff Roberson 	    SHUTDOWN_PRI_FIRST);
1819405072aSJeff Roberson 
1829405072aSJeff Roberson 	ALD_LOCK();
1839405072aSJeff Roberson 
1849405072aSJeff Roberson 	for (;;) {
1859405072aSJeff Roberson 		while ((alq = LIST_FIRST(&ald_active)) == NULL)
1869405072aSJeff Roberson 			msleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0);
1879405072aSJeff Roberson 
1889405072aSJeff Roberson 		ALQ_LOCK(alq);
1899405072aSJeff Roberson 		ald_deactivate(alq);
1909405072aSJeff Roberson 		ALD_UNLOCK();
1919405072aSJeff Roberson 		needwakeup = alq_doio(alq);
1929405072aSJeff Roberson 		ALQ_UNLOCK(alq);
1939405072aSJeff Roberson 		if (needwakeup)
1949405072aSJeff Roberson 			wakeup(alq);
1959405072aSJeff Roberson 		ALD_LOCK();
1969405072aSJeff Roberson 	}
1979405072aSJeff Roberson }
1989405072aSJeff Roberson 
1999405072aSJeff Roberson static void
2009405072aSJeff Roberson ald_shutdown(void *arg, int howto)
2019405072aSJeff Roberson {
2029405072aSJeff Roberson 	struct alq *alq;
2039405072aSJeff Roberson 
2049405072aSJeff Roberson 	ALD_LOCK();
2059405072aSJeff Roberson 	ald_shutingdown = 1;
2069405072aSJeff Roberson 
2079405072aSJeff Roberson 	while ((alq = LIST_FIRST(&ald_queues)) != NULL) {
2089405072aSJeff Roberson 		LIST_REMOVE(alq, aq_link);
2099405072aSJeff Roberson 		ALD_UNLOCK();
2109405072aSJeff Roberson 		alq_shutdown(alq);
2119405072aSJeff Roberson 		ALD_LOCK();
2129405072aSJeff Roberson 	}
2139405072aSJeff Roberson 	ALD_UNLOCK();
2149405072aSJeff Roberson }
2159405072aSJeff Roberson 
2169405072aSJeff Roberson static void
2179405072aSJeff Roberson alq_shutdown(struct alq *alq)
2189405072aSJeff Roberson {
2199405072aSJeff Roberson 	ALQ_LOCK(alq);
2209405072aSJeff Roberson 
2219405072aSJeff Roberson 	/* Stop any new writers. */
2229405072aSJeff Roberson 	alq->aq_flags |= AQ_SHUTDOWN;
2239405072aSJeff Roberson 
2249405072aSJeff Roberson 	/* Drain IO */
2259405072aSJeff Roberson 	while (alq->aq_flags & (AQ_FLUSHING|AQ_ACTIVE)) {
2269405072aSJeff Roberson 		alq->aq_flags |= AQ_WANTED;
2279405072aSJeff Roberson 		ALQ_UNLOCK(alq);
2289405072aSJeff Roberson 		tsleep(alq, PWAIT, "aldclose", 0);
2299405072aSJeff Roberson 		ALQ_LOCK(alq);
2309405072aSJeff Roberson 	}
2319405072aSJeff Roberson 	ALQ_UNLOCK(alq);
2329405072aSJeff Roberson 
233a414302fSJeff Roberson 	vn_close(alq->aq_vp, FWRITE, alq->aq_cred,
2349e9256e2SJeff Roberson 	    curthread);
2359e9256e2SJeff Roberson 	crfree(alq->aq_cred);
2369405072aSJeff Roberson }
2379405072aSJeff Roberson 
2389405072aSJeff Roberson /*
2399405072aSJeff Roberson  * Flush all pending data to disk.  This operation will block.
2409405072aSJeff Roberson  */
2419405072aSJeff Roberson static int
2429405072aSJeff Roberson alq_doio(struct alq *alq)
2439405072aSJeff Roberson {
2449405072aSJeff Roberson 	struct thread *td;
2459405072aSJeff Roberson 	struct mount *mp;
2469405072aSJeff Roberson 	struct vnode *vp;
2479405072aSJeff Roberson 	struct uio auio;
2489405072aSJeff Roberson 	struct iovec aiov[2];
2499405072aSJeff Roberson 	struct ale *ale;
2509405072aSJeff Roberson 	struct ale *alstart;
2519405072aSJeff Roberson 	int totlen;
2529405072aSJeff Roberson 	int iov;
2539405072aSJeff Roberson 
2549405072aSJeff Roberson 	vp = alq->aq_vp;
2559405072aSJeff Roberson 	td = curthread;
2569405072aSJeff Roberson 	totlen = 0;
2579405072aSJeff Roberson 	iov = 0;
2589405072aSJeff Roberson 
2599405072aSJeff Roberson 	alstart = ale = alq->aq_entvalid;
2609405072aSJeff Roberson 	alq->aq_entvalid = NULL;
2619405072aSJeff Roberson 
2629405072aSJeff Roberson 	bzero(&aiov, sizeof(aiov));
2639405072aSJeff Roberson 	bzero(&auio, sizeof(auio));
2649405072aSJeff Roberson 
2659405072aSJeff Roberson 	do {
2669405072aSJeff Roberson 		if (aiov[iov].iov_base == NULL)
2679405072aSJeff Roberson 			aiov[iov].iov_base = ale->ae_data;
2689405072aSJeff Roberson 		aiov[iov].iov_len += alq->aq_entlen;
2699405072aSJeff Roberson 		totlen += alq->aq_entlen;
2709405072aSJeff Roberson 		/* Check to see if we're wrapping the buffer */
2719405072aSJeff Roberson 		if (ale->ae_data + alq->aq_entlen != ale->ae_next->ae_data)
2729405072aSJeff Roberson 			iov++;
2739405072aSJeff Roberson 		ale->ae_flags &= ~AE_VALID;
2749405072aSJeff Roberson 		ale = ale->ae_next;
2759405072aSJeff Roberson 	} while (ale->ae_flags & AE_VALID);
2769405072aSJeff Roberson 
2779405072aSJeff Roberson 	alq->aq_flags |= AQ_FLUSHING;
2789405072aSJeff Roberson 	ALQ_UNLOCK(alq);
2799405072aSJeff Roberson 
2809405072aSJeff Roberson 	if (iov == 2 || aiov[iov].iov_base == NULL)
2819405072aSJeff Roberson 		iov--;
2829405072aSJeff Roberson 
2839405072aSJeff Roberson 	auio.uio_iov = &aiov[0];
2849405072aSJeff Roberson 	auio.uio_offset = 0;
2859405072aSJeff Roberson 	auio.uio_segflg = UIO_SYSSPACE;
2869405072aSJeff Roberson 	auio.uio_rw = UIO_WRITE;
2879405072aSJeff Roberson 	auio.uio_iovcnt = iov + 1;
2889405072aSJeff Roberson 	auio.uio_resid = totlen;
2899405072aSJeff Roberson 	auio.uio_td = td;
2909405072aSJeff Roberson 
2919405072aSJeff Roberson 	/*
2929405072aSJeff Roberson 	 * Do all of the junk required to write now.
2939405072aSJeff Roberson 	 */
2949405072aSJeff Roberson 	vn_start_write(vp, &mp, V_WAIT);
2959405072aSJeff Roberson 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2969e9256e2SJeff Roberson 	VOP_LEASE(vp, td, alq->aq_cred, LEASE_WRITE);
29767536f03SRobert Watson 	/*
29867536f03SRobert Watson 	 * XXX: VOP_WRITE error checks are ignored.
29967536f03SRobert Watson 	 */
30067536f03SRobert Watson #ifdef MAC
30167536f03SRobert Watson 	if (mac_check_vnode_write(alq->aq_cred, NOCRED, vp) == 0)
30267536f03SRobert Watson #endif
3039e9256e2SJeff Roberson 		VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred);
3049405072aSJeff Roberson 	VOP_UNLOCK(vp, 0, td);
3059405072aSJeff Roberson 	vn_finished_write(mp);
3069405072aSJeff Roberson 
3079405072aSJeff Roberson 	ALQ_LOCK(alq);
3089405072aSJeff Roberson 	alq->aq_flags &= ~AQ_FLUSHING;
3099405072aSJeff Roberson 
3109405072aSJeff Roberson 	if (alq->aq_entfree == NULL)
3119405072aSJeff Roberson 		alq->aq_entfree = alstart;
3129405072aSJeff Roberson 
3139405072aSJeff Roberson 	if (alq->aq_flags & AQ_WANTED) {
3149405072aSJeff Roberson 		alq->aq_flags &= ~AQ_WANTED;
3159405072aSJeff Roberson 		return (1);
3169405072aSJeff Roberson 	}
3179405072aSJeff Roberson 
3189405072aSJeff Roberson 	return(0);
3199405072aSJeff Roberson }
3209405072aSJeff Roberson 
3219405072aSJeff Roberson static struct kproc_desc ald_kp = {
3229405072aSJeff Roberson         "ALQ Daemon",
3239405072aSJeff Roberson         ald_daemon,
324a414302fSJeff Roberson         &ald_proc
3259405072aSJeff Roberson };
3269405072aSJeff Roberson 
3279405072aSJeff Roberson SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp)
3289405072aSJeff Roberson SYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL)
3299405072aSJeff Roberson 
3309405072aSJeff Roberson 
3319405072aSJeff Roberson /* User visible queue functions */
3329405072aSJeff Roberson 
3339405072aSJeff Roberson /*
3349405072aSJeff Roberson  * Create the queue data structure, allocate the buffer, and open the file.
3359405072aSJeff Roberson  */
3369405072aSJeff Roberson int
3374b090e41SRobert Watson alq_open(struct alq **alqp, const char *file, struct ucred *cred, int size,
3384b090e41SRobert Watson     int count)
3399405072aSJeff Roberson {
3409405072aSJeff Roberson 	struct thread *td;
3419405072aSJeff Roberson 	struct nameidata nd;
3429405072aSJeff Roberson 	struct ale *ale;
3439405072aSJeff Roberson 	struct ale *alp;
3449405072aSJeff Roberson 	struct alq *alq;
3459405072aSJeff Roberson 	char *bufp;
3469405072aSJeff Roberson 	int flags;
3479405072aSJeff Roberson 	int error;
3489405072aSJeff Roberson 	int i;
3499405072aSJeff Roberson 
3509405072aSJeff Roberson 	*alqp = NULL;
3519405072aSJeff Roberson 	td = curthread;
3529405072aSJeff Roberson 
3539405072aSJeff Roberson 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td);
354a414302fSJeff Roberson 	flags = FWRITE | O_NOFOLLOW | O_CREAT;
3559405072aSJeff Roberson 
3567c89f162SPoul-Henning Kamp 	error = vn_open_cred(&nd, &flags, 0, cred, -1);
3579405072aSJeff Roberson 	if (error)
3589405072aSJeff Roberson 		return (error);
3599405072aSJeff Roberson 
3609405072aSJeff Roberson 	NDFREE(&nd, NDF_ONLY_PNBUF);
3619405072aSJeff Roberson 	/* We just unlock so we hold a reference */
3629405072aSJeff Roberson 	VOP_UNLOCK(nd.ni_vp, 0, td);
3639405072aSJeff Roberson 
364a163d034SWarner Losh 	alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO);
365a163d034SWarner Losh 	alq->aq_entbuf = malloc(count * size, M_ALD, M_WAITOK|M_ZERO);
366a163d034SWarner Losh 	alq->aq_first = malloc(sizeof(*ale) * count, M_ALD, M_WAITOK|M_ZERO);
3679405072aSJeff Roberson 	alq->aq_vp = nd.ni_vp;
3684b090e41SRobert Watson 	alq->aq_cred = crhold(cred);
3699405072aSJeff Roberson 	alq->aq_entmax = count;
3709405072aSJeff Roberson 	alq->aq_entlen = size;
3719405072aSJeff Roberson 	alq->aq_entfree = alq->aq_first;
3729405072aSJeff Roberson 
3739405072aSJeff Roberson 	mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET);
3749405072aSJeff Roberson 
3759405072aSJeff Roberson 	bufp = alq->aq_entbuf;
3769405072aSJeff Roberson 	ale = alq->aq_first;
3779405072aSJeff Roberson 	alp = NULL;
3789405072aSJeff Roberson 
3799405072aSJeff Roberson 	/* Match up entries with buffers */
3809405072aSJeff Roberson 	for (i = 0; i < count; i++) {
3819405072aSJeff Roberson 		if (alp)
3829405072aSJeff Roberson 			alp->ae_next = ale;
3839405072aSJeff Roberson 		ale->ae_data = bufp;
3849405072aSJeff Roberson 		alp = ale;
3859405072aSJeff Roberson 		ale++;
3869405072aSJeff Roberson 		bufp += size;
3879405072aSJeff Roberson 	}
3889405072aSJeff Roberson 
3899405072aSJeff Roberson 	alp->ae_next = alq->aq_first;
3909405072aSJeff Roberson 
3919405072aSJeff Roberson 	if ((error = ald_add(alq)) != 0)
3929405072aSJeff Roberson 		return (error);
3939405072aSJeff Roberson 	*alqp = alq;
3949405072aSJeff Roberson 
3959405072aSJeff Roberson 	return (0);
3969405072aSJeff Roberson }
3979405072aSJeff Roberson 
3989405072aSJeff Roberson /*
3999405072aSJeff Roberson  * Copy a new entry into the queue.  If the operation would block either
4009405072aSJeff Roberson  * wait or return an error depending on the value of waitok.
4019405072aSJeff Roberson  */
4029405072aSJeff Roberson int
4039405072aSJeff Roberson alq_write(struct alq *alq, void *data, int waitok)
4049405072aSJeff Roberson {
4059405072aSJeff Roberson 	struct ale *ale;
4069405072aSJeff Roberson 
4079405072aSJeff Roberson 	if ((ale = alq_get(alq, waitok)) == NULL)
4089405072aSJeff Roberson 		return (EWOULDBLOCK);
4099405072aSJeff Roberson 
4109405072aSJeff Roberson 	bcopy(data, ale->ae_data, alq->aq_entlen);
4119405072aSJeff Roberson 	alq_post(alq, ale);
4129405072aSJeff Roberson 
4139405072aSJeff Roberson 	return (0);
4149405072aSJeff Roberson }
4159405072aSJeff Roberson 
4169405072aSJeff Roberson struct ale *
4179405072aSJeff Roberson alq_get(struct alq *alq, int waitok)
4189405072aSJeff Roberson {
4199405072aSJeff Roberson 	struct ale *ale;
4209405072aSJeff Roberson 	struct ale *aln;
4219405072aSJeff Roberson 
4229405072aSJeff Roberson 	ale = NULL;
4239405072aSJeff Roberson 
4249405072aSJeff Roberson 	ALQ_LOCK(alq);
4259405072aSJeff Roberson 
4269405072aSJeff Roberson 	/* Loop until we get an entry or we're shutting down */
4279405072aSJeff Roberson 	while ((alq->aq_flags & AQ_SHUTDOWN) == 0 &&
4289405072aSJeff Roberson 	    (ale = alq->aq_entfree) == NULL &&
4299405072aSJeff Roberson 	    (waitok & ALQ_WAITOK)) {
4309405072aSJeff Roberson 		alq->aq_flags |= AQ_WANTED;
4319405072aSJeff Roberson 		ALQ_UNLOCK(alq);
4329405072aSJeff Roberson 		tsleep(alq, PWAIT, "alqget", 0);
4339405072aSJeff Roberson 		ALQ_LOCK(alq);
4349405072aSJeff Roberson 	}
4359405072aSJeff Roberson 
4369405072aSJeff Roberson 	if (ale != NULL) {
4379405072aSJeff Roberson 		aln = ale->ae_next;
4389405072aSJeff Roberson 		if ((aln->ae_flags & AE_VALID) == 0)
4399405072aSJeff Roberson 			alq->aq_entfree = aln;
44030fd5d08SJeff Roberson 		else
44130fd5d08SJeff Roberson 			alq->aq_entfree = NULL;
4429405072aSJeff Roberson 	} else
4439405072aSJeff Roberson 		ALQ_UNLOCK(alq);
4449405072aSJeff Roberson 
4459405072aSJeff Roberson 
4469405072aSJeff Roberson 	return (ale);
4479405072aSJeff Roberson }
4489405072aSJeff Roberson 
4499405072aSJeff Roberson void
4509405072aSJeff Roberson alq_post(struct alq *alq, struct ale *ale)
4519405072aSJeff Roberson {
4529405072aSJeff Roberson 	int activate;
4539405072aSJeff Roberson 
4549405072aSJeff Roberson 	ale->ae_flags |= AE_VALID;
4559405072aSJeff Roberson 
4569405072aSJeff Roberson 	if (alq->aq_entvalid == NULL)
4579405072aSJeff Roberson 		alq->aq_entvalid = ale;
4589405072aSJeff Roberson 
4599405072aSJeff Roberson 	if ((alq->aq_flags & AQ_ACTIVE) == 0) {
4609405072aSJeff Roberson 		alq->aq_flags |= AQ_ACTIVE;
4619405072aSJeff Roberson 		activate = 1;
4629405072aSJeff Roberson 	} else
4639405072aSJeff Roberson 		activate = 0;
4649405072aSJeff Roberson 
4659405072aSJeff Roberson 	ALQ_UNLOCK(alq);
4669405072aSJeff Roberson 	if (activate) {
4679405072aSJeff Roberson 		ALD_LOCK();
4689405072aSJeff Roberson 		ald_activate(alq);
4699405072aSJeff Roberson 		ALD_UNLOCK();
4709405072aSJeff Roberson 	}
4719405072aSJeff Roberson }
4729405072aSJeff Roberson 
4739405072aSJeff Roberson void
4749405072aSJeff Roberson alq_flush(struct alq *alq)
4759405072aSJeff Roberson {
4769405072aSJeff Roberson 	int needwakeup = 0;
4779405072aSJeff Roberson 
4789405072aSJeff Roberson 	ALD_LOCK();
4799405072aSJeff Roberson 	ALQ_LOCK(alq);
4809405072aSJeff Roberson 	if (alq->aq_flags & AQ_ACTIVE) {
4819405072aSJeff Roberson 		ald_deactivate(alq);
4829405072aSJeff Roberson 		ALD_UNLOCK();
4839405072aSJeff Roberson 		needwakeup = alq_doio(alq);
4849405072aSJeff Roberson 	} else
4859405072aSJeff Roberson 		ALD_UNLOCK();
4869405072aSJeff Roberson 	ALQ_UNLOCK(alq);
4879405072aSJeff Roberson 
4889405072aSJeff Roberson 	if (needwakeup)
4899405072aSJeff Roberson 		wakeup(alq);
4909405072aSJeff Roberson }
4919405072aSJeff Roberson 
4929405072aSJeff Roberson /*
4939405072aSJeff Roberson  * Flush remaining data, close the file and free all resources.
4949405072aSJeff Roberson  */
4959405072aSJeff Roberson void
4969405072aSJeff Roberson alq_close(struct alq *alq)
4979405072aSJeff Roberson {
4989405072aSJeff Roberson 	/*
4999405072aSJeff Roberson 	 * If we're already shuting down someone else will flush and close
5009405072aSJeff Roberson 	 * the vnode.
5019405072aSJeff Roberson 	 */
5029405072aSJeff Roberson 	if (ald_rem(alq) != 0)
5039405072aSJeff Roberson 		return;
5049405072aSJeff Roberson 
5059405072aSJeff Roberson 	/*
5069405072aSJeff Roberson 	 * Drain all pending IO.
5079405072aSJeff Roberson 	 */
5089405072aSJeff Roberson 	alq_shutdown(alq);
5099405072aSJeff Roberson 
5109405072aSJeff Roberson 	mtx_destroy(&alq->aq_mtx);
5119405072aSJeff Roberson 	free(alq->aq_first, M_ALD);
5129405072aSJeff Roberson 	free(alq->aq_entbuf, M_ALD);
5139405072aSJeff Roberson 	free(alq, M_ALD);
5149405072aSJeff Roberson }
515