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