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