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> 3833f19beeSJohn Baldwin #include <sys/mount.h> 399405072aSJeff Roberson #include <sys/mutex.h> 409405072aSJeff Roberson #include <sys/namei.h> 419405072aSJeff Roberson #include <sys/proc.h> 429405072aSJeff Roberson #include <sys/vnode.h> 439405072aSJeff Roberson #include <sys/alq.h> 449405072aSJeff Roberson #include <sys/malloc.h> 459405072aSJeff Roberson #include <sys/unistd.h> 469405072aSJeff Roberson #include <sys/fcntl.h> 479405072aSJeff Roberson #include <sys/eventhandler.h> 489405072aSJeff Roberson 499405072aSJeff Roberson /* Async. Logging Queue */ 509405072aSJeff Roberson struct alq { 519405072aSJeff Roberson int aq_entmax; /* Max entries */ 529405072aSJeff Roberson int aq_entlen; /* Entry length */ 539405072aSJeff Roberson char *aq_entbuf; /* Buffer for stored entries */ 549405072aSJeff Roberson int aq_flags; /* Queue flags */ 559405072aSJeff Roberson struct mtx aq_mtx; /* Queue lock */ 569405072aSJeff Roberson struct vnode *aq_vp; /* Open vnode handle */ 579e9256e2SJeff Roberson struct ucred *aq_cred; /* Credentials of the opening thread */ 589405072aSJeff Roberson struct ale *aq_first; /* First ent */ 599405072aSJeff Roberson struct ale *aq_entfree; /* First free ent */ 609405072aSJeff Roberson struct ale *aq_entvalid; /* First ent valid for writing */ 619405072aSJeff Roberson LIST_ENTRY(alq) aq_act; /* List of active queues */ 629405072aSJeff Roberson LIST_ENTRY(alq) aq_link; /* List of all queues */ 639405072aSJeff Roberson }; 649405072aSJeff Roberson 659405072aSJeff Roberson #define AQ_WANTED 0x0001 /* Wakeup sleeper when io is done */ 669405072aSJeff Roberson #define AQ_ACTIVE 0x0002 /* on the active list */ 679405072aSJeff Roberson #define AQ_FLUSHING 0x0004 /* doing IO */ 689405072aSJeff Roberson #define AQ_SHUTDOWN 0x0008 /* Queue no longer valid */ 699405072aSJeff Roberson 709405072aSJeff Roberson #define ALQ_LOCK(alq) mtx_lock_spin(&(alq)->aq_mtx) 719405072aSJeff Roberson #define ALQ_UNLOCK(alq) mtx_unlock_spin(&(alq)->aq_mtx) 729405072aSJeff Roberson 739405072aSJeff Roberson static MALLOC_DEFINE(M_ALD, "ALD", "ALD"); 749405072aSJeff Roberson 759405072aSJeff Roberson /* 769405072aSJeff Roberson * The ald_mtx protects the ald_queues list and the ald_active list. 779405072aSJeff Roberson */ 789405072aSJeff Roberson static struct mtx ald_mtx; 799405072aSJeff Roberson static LIST_HEAD(, alq) ald_queues; 809405072aSJeff Roberson static LIST_HEAD(, alq) ald_active; 819405072aSJeff Roberson static int ald_shutingdown = 0; 82a414302fSJeff Roberson struct thread *ald_thread; 83a414302fSJeff Roberson static struct proc *ald_proc; 849405072aSJeff Roberson 859405072aSJeff Roberson #define ALD_LOCK() mtx_lock(&ald_mtx) 869405072aSJeff Roberson #define ALD_UNLOCK() mtx_unlock(&ald_mtx) 879405072aSJeff Roberson 889405072aSJeff Roberson /* Daemon functions */ 899405072aSJeff Roberson static int ald_add(struct alq *); 909405072aSJeff Roberson static int ald_rem(struct alq *); 919405072aSJeff Roberson static void ald_startup(void *); 929405072aSJeff Roberson static void ald_daemon(void); 939405072aSJeff Roberson static void ald_shutdown(void *, int); 949405072aSJeff Roberson static void ald_activate(struct alq *); 959405072aSJeff Roberson static void ald_deactivate(struct alq *); 969405072aSJeff Roberson 979405072aSJeff Roberson /* Internal queue functions */ 989405072aSJeff Roberson static void alq_shutdown(struct alq *); 999405072aSJeff Roberson static int alq_doio(struct alq *); 1009405072aSJeff Roberson 1019405072aSJeff Roberson 1029405072aSJeff Roberson /* 1039405072aSJeff Roberson * Add a new queue to the global list. Fail if we're shutting down. 1049405072aSJeff Roberson */ 1059405072aSJeff Roberson static int 1069405072aSJeff Roberson ald_add(struct alq *alq) 1079405072aSJeff Roberson { 1089405072aSJeff Roberson int error; 1099405072aSJeff Roberson 1109405072aSJeff Roberson error = 0; 1119405072aSJeff Roberson 1129405072aSJeff Roberson ALD_LOCK(); 1139405072aSJeff Roberson if (ald_shutingdown) { 1149405072aSJeff Roberson error = EBUSY; 1159405072aSJeff Roberson goto done; 1169405072aSJeff Roberson } 1179405072aSJeff Roberson LIST_INSERT_HEAD(&ald_queues, alq, aq_link); 1189405072aSJeff Roberson done: 1199405072aSJeff Roberson ALD_UNLOCK(); 1209405072aSJeff Roberson return (error); 1219405072aSJeff Roberson } 1229405072aSJeff Roberson 1239405072aSJeff Roberson /* 1249405072aSJeff Roberson * Remove a queue from the global list unless we're shutting down. If so, 1259405072aSJeff Roberson * the ald will take care of cleaning up it's resources. 1269405072aSJeff Roberson */ 1279405072aSJeff Roberson static int 1289405072aSJeff Roberson ald_rem(struct alq *alq) 1299405072aSJeff Roberson { 1309405072aSJeff Roberson int error; 1319405072aSJeff Roberson 1329405072aSJeff Roberson error = 0; 1339405072aSJeff Roberson 1349405072aSJeff Roberson ALD_LOCK(); 1359405072aSJeff Roberson if (ald_shutingdown) { 1369405072aSJeff Roberson error = EBUSY; 1379405072aSJeff Roberson goto done; 1389405072aSJeff Roberson } 1399405072aSJeff Roberson LIST_REMOVE(alq, aq_link); 1409405072aSJeff Roberson done: 1419405072aSJeff Roberson ALD_UNLOCK(); 1429405072aSJeff Roberson return (error); 1439405072aSJeff Roberson } 1449405072aSJeff Roberson 1459405072aSJeff Roberson /* 1469405072aSJeff Roberson * Put a queue on the active list. This will schedule it for writing. 1479405072aSJeff Roberson */ 1489405072aSJeff Roberson static void 1499405072aSJeff Roberson ald_activate(struct alq *alq) 1509405072aSJeff Roberson { 1519405072aSJeff Roberson LIST_INSERT_HEAD(&ald_active, alq, aq_act); 1529405072aSJeff Roberson wakeup(&ald_active); 1539405072aSJeff Roberson } 1549405072aSJeff Roberson 1559405072aSJeff Roberson static void 1569405072aSJeff Roberson ald_deactivate(struct alq *alq) 1579405072aSJeff Roberson { 1589405072aSJeff Roberson LIST_REMOVE(alq, aq_act); 1599405072aSJeff Roberson alq->aq_flags &= ~AQ_ACTIVE; 1609405072aSJeff Roberson } 1619405072aSJeff Roberson 1629405072aSJeff Roberson static void 1639405072aSJeff Roberson ald_startup(void *unused) 1649405072aSJeff Roberson { 1659405072aSJeff Roberson mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET); 1669405072aSJeff Roberson LIST_INIT(&ald_queues); 1679405072aSJeff Roberson LIST_INIT(&ald_active); 1689405072aSJeff Roberson } 1699405072aSJeff Roberson 1709405072aSJeff Roberson static void 1719405072aSJeff Roberson ald_daemon(void) 1729405072aSJeff Roberson { 1739405072aSJeff Roberson int needwakeup; 1749405072aSJeff Roberson struct alq *alq; 1759405072aSJeff Roberson 176a414302fSJeff Roberson ald_thread = FIRST_THREAD_IN_PROC(ald_proc); 177a414302fSJeff Roberson 1789405072aSJeff Roberson EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL, 1799405072aSJeff Roberson SHUTDOWN_PRI_FIRST); 1809405072aSJeff Roberson 1819405072aSJeff Roberson ALD_LOCK(); 1829405072aSJeff Roberson 1839405072aSJeff Roberson for (;;) { 1849405072aSJeff Roberson while ((alq = LIST_FIRST(&ald_active)) == NULL) 1859405072aSJeff Roberson msleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0); 1869405072aSJeff Roberson 1879405072aSJeff Roberson ALQ_LOCK(alq); 1889405072aSJeff Roberson ald_deactivate(alq); 1899405072aSJeff Roberson ALD_UNLOCK(); 1909405072aSJeff Roberson needwakeup = alq_doio(alq); 1919405072aSJeff Roberson ALQ_UNLOCK(alq); 1929405072aSJeff Roberson if (needwakeup) 1939405072aSJeff Roberson wakeup(alq); 1949405072aSJeff Roberson ALD_LOCK(); 1959405072aSJeff Roberson } 1969405072aSJeff Roberson } 1979405072aSJeff Roberson 1989405072aSJeff Roberson static void 1999405072aSJeff Roberson ald_shutdown(void *arg, int howto) 2009405072aSJeff Roberson { 2019405072aSJeff Roberson struct alq *alq; 2029405072aSJeff Roberson 2039405072aSJeff Roberson ALD_LOCK(); 2049405072aSJeff Roberson ald_shutingdown = 1; 2059405072aSJeff Roberson 2069405072aSJeff Roberson while ((alq = LIST_FIRST(&ald_queues)) != NULL) { 2079405072aSJeff Roberson LIST_REMOVE(alq, aq_link); 2089405072aSJeff Roberson ALD_UNLOCK(); 2099405072aSJeff Roberson alq_shutdown(alq); 2109405072aSJeff Roberson ALD_LOCK(); 2119405072aSJeff Roberson } 2129405072aSJeff Roberson ALD_UNLOCK(); 2139405072aSJeff Roberson } 2149405072aSJeff Roberson 2159405072aSJeff Roberson static void 2169405072aSJeff Roberson alq_shutdown(struct alq *alq) 2179405072aSJeff Roberson { 2189405072aSJeff Roberson ALQ_LOCK(alq); 2199405072aSJeff Roberson 2209405072aSJeff Roberson /* Stop any new writers. */ 2219405072aSJeff Roberson alq->aq_flags |= AQ_SHUTDOWN; 2229405072aSJeff Roberson 2239405072aSJeff Roberson /* Drain IO */ 2249405072aSJeff Roberson while (alq->aq_flags & (AQ_FLUSHING|AQ_ACTIVE)) { 2259405072aSJeff Roberson alq->aq_flags |= AQ_WANTED; 2269405072aSJeff Roberson ALQ_UNLOCK(alq); 2279405072aSJeff Roberson tsleep(alq, PWAIT, "aldclose", 0); 2289405072aSJeff Roberson ALQ_LOCK(alq); 2299405072aSJeff Roberson } 2309405072aSJeff Roberson ALQ_UNLOCK(alq); 2319405072aSJeff Roberson 232a414302fSJeff Roberson vn_close(alq->aq_vp, FWRITE, alq->aq_cred, 2339e9256e2SJeff Roberson curthread); 2349e9256e2SJeff Roberson crfree(alq->aq_cred); 2359405072aSJeff Roberson } 2369405072aSJeff Roberson 2379405072aSJeff Roberson /* 2389405072aSJeff Roberson * Flush all pending data to disk. This operation will block. 2399405072aSJeff Roberson */ 2409405072aSJeff Roberson static int 2419405072aSJeff Roberson alq_doio(struct alq *alq) 2429405072aSJeff Roberson { 2439405072aSJeff Roberson struct thread *td; 2449405072aSJeff Roberson struct mount *mp; 2459405072aSJeff Roberson struct vnode *vp; 2469405072aSJeff Roberson struct uio auio; 2479405072aSJeff Roberson struct iovec aiov[2]; 2489405072aSJeff Roberson struct ale *ale; 2499405072aSJeff Roberson struct ale *alstart; 2509405072aSJeff Roberson int totlen; 2519405072aSJeff Roberson int iov; 25233f19beeSJohn Baldwin int vfslocked; 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 */ 29433f19beeSJohn Baldwin vfslocked = VFS_LOCK_GIANT(vp->v_mount); 2959405072aSJeff Roberson vn_start_write(vp, &mp, V_WAIT); 2969405072aSJeff Roberson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2979e9256e2SJeff Roberson VOP_LEASE(vp, td, alq->aq_cred, LEASE_WRITE); 29867536f03SRobert Watson /* 29967536f03SRobert Watson * XXX: VOP_WRITE error checks are ignored. 30067536f03SRobert Watson */ 30167536f03SRobert Watson #ifdef MAC 30267536f03SRobert Watson if (mac_check_vnode_write(alq->aq_cred, NOCRED, vp) == 0) 30367536f03SRobert Watson #endif 3049e9256e2SJeff Roberson VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred); 3059405072aSJeff Roberson VOP_UNLOCK(vp, 0, td); 3069405072aSJeff Roberson vn_finished_write(mp); 30733f19beeSJohn Baldwin VFS_UNLOCK_GIANT(vfslocked); 3089405072aSJeff Roberson 3099405072aSJeff Roberson ALQ_LOCK(alq); 3109405072aSJeff Roberson alq->aq_flags &= ~AQ_FLUSHING; 3119405072aSJeff Roberson 3129405072aSJeff Roberson if (alq->aq_entfree == NULL) 3139405072aSJeff Roberson alq->aq_entfree = alstart; 3149405072aSJeff Roberson 3159405072aSJeff Roberson if (alq->aq_flags & AQ_WANTED) { 3169405072aSJeff Roberson alq->aq_flags &= ~AQ_WANTED; 3179405072aSJeff Roberson return (1); 3189405072aSJeff Roberson } 3199405072aSJeff Roberson 3209405072aSJeff Roberson return(0); 3219405072aSJeff Roberson } 3229405072aSJeff Roberson 3239405072aSJeff Roberson static struct kproc_desc ald_kp = { 3249405072aSJeff Roberson "ALQ Daemon", 3259405072aSJeff Roberson ald_daemon, 326a414302fSJeff Roberson &ald_proc 3279405072aSJeff Roberson }; 3289405072aSJeff Roberson 3299405072aSJeff Roberson SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp) 3309405072aSJeff Roberson SYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL) 3319405072aSJeff Roberson 3329405072aSJeff Roberson 3339405072aSJeff Roberson /* User visible queue functions */ 3349405072aSJeff Roberson 3359405072aSJeff Roberson /* 3369405072aSJeff Roberson * Create the queue data structure, allocate the buffer, and open the file. 3379405072aSJeff Roberson */ 3389405072aSJeff Roberson int 339e551d452SRobert Watson alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 340e551d452SRobert Watson int size, int count) 3419405072aSJeff Roberson { 3429405072aSJeff Roberson struct thread *td; 3439405072aSJeff Roberson struct nameidata nd; 3449405072aSJeff Roberson struct ale *ale; 3459405072aSJeff Roberson struct ale *alp; 3469405072aSJeff Roberson struct alq *alq; 3479405072aSJeff Roberson char *bufp; 3489405072aSJeff Roberson int flags; 3499405072aSJeff Roberson int error; 35033f19beeSJohn Baldwin int i, vfslocked; 3519405072aSJeff Roberson 3529405072aSJeff Roberson *alqp = NULL; 3539405072aSJeff Roberson td = curthread; 3549405072aSJeff Roberson 35533f19beeSJohn Baldwin NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, file, td); 356a414302fSJeff Roberson flags = FWRITE | O_NOFOLLOW | O_CREAT; 3579405072aSJeff Roberson 358e551d452SRobert Watson error = vn_open_cred(&nd, &flags, cmode, cred, -1); 3599405072aSJeff Roberson if (error) 3609405072aSJeff Roberson return (error); 3619405072aSJeff Roberson 36233f19beeSJohn Baldwin vfslocked = NDHASGIANT(&nd); 363f220f7afSPawel Jakub Dawidek NDFREE(&nd, NDF_ONLY_PNBUF); 3649405072aSJeff Roberson /* We just unlock so we hold a reference */ 3659405072aSJeff Roberson VOP_UNLOCK(nd.ni_vp, 0, td); 36633f19beeSJohn Baldwin VFS_UNLOCK_GIANT(vfslocked); 3679405072aSJeff Roberson 368a163d034SWarner Losh alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO); 369a163d034SWarner Losh alq->aq_entbuf = malloc(count * size, M_ALD, M_WAITOK|M_ZERO); 370a163d034SWarner Losh alq->aq_first = malloc(sizeof(*ale) * count, M_ALD, M_WAITOK|M_ZERO); 3719405072aSJeff Roberson alq->aq_vp = nd.ni_vp; 3724b090e41SRobert Watson alq->aq_cred = crhold(cred); 3739405072aSJeff Roberson alq->aq_entmax = count; 3749405072aSJeff Roberson alq->aq_entlen = size; 3759405072aSJeff Roberson alq->aq_entfree = alq->aq_first; 3769405072aSJeff Roberson 3779405072aSJeff Roberson mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET); 3789405072aSJeff Roberson 3799405072aSJeff Roberson bufp = alq->aq_entbuf; 3809405072aSJeff Roberson ale = alq->aq_first; 3819405072aSJeff Roberson alp = NULL; 3829405072aSJeff Roberson 3839405072aSJeff Roberson /* Match up entries with buffers */ 3849405072aSJeff Roberson for (i = 0; i < count; i++) { 3859405072aSJeff Roberson if (alp) 3869405072aSJeff Roberson alp->ae_next = ale; 3879405072aSJeff Roberson ale->ae_data = bufp; 3889405072aSJeff Roberson alp = ale; 3899405072aSJeff Roberson ale++; 3909405072aSJeff Roberson bufp += size; 3919405072aSJeff Roberson } 3929405072aSJeff Roberson 3939405072aSJeff Roberson alp->ae_next = alq->aq_first; 3949405072aSJeff Roberson 3959405072aSJeff Roberson if ((error = ald_add(alq)) != 0) 3969405072aSJeff Roberson return (error); 3979405072aSJeff Roberson *alqp = alq; 3989405072aSJeff Roberson 3999405072aSJeff Roberson return (0); 4009405072aSJeff Roberson } 4019405072aSJeff Roberson 4029405072aSJeff Roberson /* 4039405072aSJeff Roberson * Copy a new entry into the queue. If the operation would block either 4049405072aSJeff Roberson * wait or return an error depending on the value of waitok. 4059405072aSJeff Roberson */ 4069405072aSJeff Roberson int 4079405072aSJeff Roberson alq_write(struct alq *alq, void *data, int waitok) 4089405072aSJeff Roberson { 4099405072aSJeff Roberson struct ale *ale; 4109405072aSJeff Roberson 4119405072aSJeff Roberson if ((ale = alq_get(alq, waitok)) == NULL) 4129405072aSJeff Roberson return (EWOULDBLOCK); 4139405072aSJeff Roberson 4149405072aSJeff Roberson bcopy(data, ale->ae_data, alq->aq_entlen); 4159405072aSJeff Roberson alq_post(alq, ale); 4169405072aSJeff Roberson 4179405072aSJeff Roberson return (0); 4189405072aSJeff Roberson } 4199405072aSJeff Roberson 4209405072aSJeff Roberson struct ale * 4219405072aSJeff Roberson alq_get(struct alq *alq, int waitok) 4229405072aSJeff Roberson { 4239405072aSJeff Roberson struct ale *ale; 4249405072aSJeff Roberson struct ale *aln; 4259405072aSJeff Roberson 4269405072aSJeff Roberson ale = NULL; 4279405072aSJeff Roberson 4289405072aSJeff Roberson ALQ_LOCK(alq); 4299405072aSJeff Roberson 4309405072aSJeff Roberson /* Loop until we get an entry or we're shutting down */ 4319405072aSJeff Roberson while ((alq->aq_flags & AQ_SHUTDOWN) == 0 && 4329405072aSJeff Roberson (ale = alq->aq_entfree) == NULL && 4339405072aSJeff Roberson (waitok & ALQ_WAITOK)) { 4349405072aSJeff Roberson alq->aq_flags |= AQ_WANTED; 4359405072aSJeff Roberson ALQ_UNLOCK(alq); 4369405072aSJeff Roberson tsleep(alq, PWAIT, "alqget", 0); 4379405072aSJeff Roberson ALQ_LOCK(alq); 4389405072aSJeff Roberson } 4399405072aSJeff Roberson 4409405072aSJeff Roberson if (ale != NULL) { 4419405072aSJeff Roberson aln = ale->ae_next; 4429405072aSJeff Roberson if ((aln->ae_flags & AE_VALID) == 0) 4439405072aSJeff Roberson alq->aq_entfree = aln; 44430fd5d08SJeff Roberson else 44530fd5d08SJeff Roberson alq->aq_entfree = NULL; 4469405072aSJeff Roberson } else 4479405072aSJeff Roberson ALQ_UNLOCK(alq); 4489405072aSJeff Roberson 4499405072aSJeff Roberson 4509405072aSJeff Roberson return (ale); 4519405072aSJeff Roberson } 4529405072aSJeff Roberson 4539405072aSJeff Roberson void 4549405072aSJeff Roberson alq_post(struct alq *alq, struct ale *ale) 4559405072aSJeff Roberson { 4569405072aSJeff Roberson int activate; 4579405072aSJeff Roberson 4589405072aSJeff Roberson ale->ae_flags |= AE_VALID; 4599405072aSJeff Roberson 4609405072aSJeff Roberson if (alq->aq_entvalid == NULL) 4619405072aSJeff Roberson alq->aq_entvalid = ale; 4629405072aSJeff Roberson 4639405072aSJeff Roberson if ((alq->aq_flags & AQ_ACTIVE) == 0) { 4649405072aSJeff Roberson alq->aq_flags |= AQ_ACTIVE; 4659405072aSJeff Roberson activate = 1; 4669405072aSJeff Roberson } else 4679405072aSJeff Roberson activate = 0; 4689405072aSJeff Roberson 4699405072aSJeff Roberson ALQ_UNLOCK(alq); 4709405072aSJeff Roberson if (activate) { 4719405072aSJeff Roberson ALD_LOCK(); 4729405072aSJeff Roberson ald_activate(alq); 4739405072aSJeff Roberson ALD_UNLOCK(); 4749405072aSJeff Roberson } 4759405072aSJeff Roberson } 4769405072aSJeff Roberson 4779405072aSJeff Roberson void 4789405072aSJeff Roberson alq_flush(struct alq *alq) 4799405072aSJeff Roberson { 4809405072aSJeff Roberson int needwakeup = 0; 4819405072aSJeff Roberson 4829405072aSJeff Roberson ALD_LOCK(); 4839405072aSJeff Roberson ALQ_LOCK(alq); 4849405072aSJeff Roberson if (alq->aq_flags & AQ_ACTIVE) { 4859405072aSJeff Roberson ald_deactivate(alq); 4869405072aSJeff Roberson ALD_UNLOCK(); 4879405072aSJeff Roberson needwakeup = alq_doio(alq); 4889405072aSJeff Roberson } else 4899405072aSJeff Roberson ALD_UNLOCK(); 4909405072aSJeff Roberson ALQ_UNLOCK(alq); 4919405072aSJeff Roberson 4929405072aSJeff Roberson if (needwakeup) 4939405072aSJeff Roberson wakeup(alq); 4949405072aSJeff Roberson } 4959405072aSJeff Roberson 4969405072aSJeff Roberson /* 4979405072aSJeff Roberson * Flush remaining data, close the file and free all resources. 4989405072aSJeff Roberson */ 4999405072aSJeff Roberson void 5009405072aSJeff Roberson alq_close(struct alq *alq) 5019405072aSJeff Roberson { 5029405072aSJeff Roberson /* 5039405072aSJeff Roberson * If we're already shuting down someone else will flush and close 5049405072aSJeff Roberson * the vnode. 5059405072aSJeff Roberson */ 5069405072aSJeff Roberson if (ald_rem(alq) != 0) 5079405072aSJeff Roberson return; 5089405072aSJeff Roberson 5099405072aSJeff Roberson /* 5109405072aSJeff Roberson * Drain all pending IO. 5119405072aSJeff Roberson */ 5129405072aSJeff Roberson alq_shutdown(alq); 5139405072aSJeff Roberson 5149405072aSJeff Roberson mtx_destroy(&alq->aq_mtx); 5159405072aSJeff Roberson free(alq->aq_first, M_ALD); 5169405072aSJeff Roberson free(alq->aq_entbuf, M_ALD); 5179405072aSJeff Roberson free(alq, M_ALD); 5189405072aSJeff Roberson } 519