19454b2d8SWarner Losh /*- 29405072aSJeff Roberson * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org> 3d28f42f9SLawrence Stewart * Copyright (c) 2008-2009, Lawrence Stewart <lstewart@freebsd.org> 4d28f42f9SLawrence Stewart * Copyright (c) 2009-2010, The FreeBSD Foundation 59405072aSJeff Roberson * All rights reserved. 69405072aSJeff Roberson * 7d28f42f9SLawrence Stewart * Portions of this software were developed at the Centre for Advanced 8d28f42f9SLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne, 9d28f42f9SLawrence Stewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 10d28f42f9SLawrence Stewart * 119405072aSJeff Roberson * Redistribution and use in source and binary forms, with or without 129405072aSJeff Roberson * modification, are permitted provided that the following conditions 139405072aSJeff Roberson * are met: 149405072aSJeff Roberson * 1. Redistributions of source code must retain the above copyright 159405072aSJeff Roberson * notice unmodified, this list of conditions, and the following 169405072aSJeff Roberson * disclaimer. 179405072aSJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 189405072aSJeff Roberson * notice, this list of conditions and the following disclaimer in the 199405072aSJeff Roberson * documentation and/or other materials provided with the distribution. 209405072aSJeff Roberson * 219405072aSJeff Roberson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 229405072aSJeff Roberson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 239405072aSJeff Roberson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 249405072aSJeff Roberson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 259405072aSJeff Roberson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 269405072aSJeff Roberson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 279405072aSJeff Roberson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 289405072aSJeff Roberson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 299405072aSJeff Roberson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 309405072aSJeff Roberson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 319405072aSJeff Roberson */ 329405072aSJeff Roberson 33677b542eSDavid E. O'Brien #include <sys/cdefs.h> 34677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 35677b542eSDavid E. O'Brien 36d28f42f9SLawrence Stewart #include "opt_mac.h" 37d28f42f9SLawrence Stewart 389405072aSJeff Roberson #include <sys/param.h> 399405072aSJeff Roberson #include <sys/systm.h> 409405072aSJeff Roberson #include <sys/kernel.h> 419405072aSJeff Roberson #include <sys/kthread.h> 429405072aSJeff Roberson #include <sys/lock.h> 4333f19beeSJohn Baldwin #include <sys/mount.h> 449405072aSJeff Roberson #include <sys/mutex.h> 459405072aSJeff Roberson #include <sys/namei.h> 469405072aSJeff Roberson #include <sys/proc.h> 479405072aSJeff Roberson #include <sys/vnode.h> 489405072aSJeff Roberson #include <sys/alq.h> 499405072aSJeff Roberson #include <sys/malloc.h> 509405072aSJeff Roberson #include <sys/unistd.h> 519405072aSJeff Roberson #include <sys/fcntl.h> 529405072aSJeff Roberson #include <sys/eventhandler.h> 539405072aSJeff Roberson 54aed55708SRobert Watson #include <security/mac/mac_framework.h> 55aed55708SRobert Watson 569405072aSJeff Roberson /* Async. Logging Queue */ 579405072aSJeff Roberson struct alq { 589405072aSJeff Roberson int aq_entmax; /* Max entries */ 599405072aSJeff Roberson int aq_entlen; /* Entry length */ 609405072aSJeff Roberson char *aq_entbuf; /* Buffer for stored entries */ 619405072aSJeff Roberson int aq_flags; /* Queue flags */ 629405072aSJeff Roberson struct mtx aq_mtx; /* Queue lock */ 639405072aSJeff Roberson struct vnode *aq_vp; /* Open vnode handle */ 649e9256e2SJeff Roberson struct ucred *aq_cred; /* Credentials of the opening thread */ 659405072aSJeff Roberson struct ale *aq_first; /* First ent */ 669405072aSJeff Roberson struct ale *aq_entfree; /* First free ent */ 679405072aSJeff Roberson struct ale *aq_entvalid; /* First ent valid for writing */ 689405072aSJeff Roberson LIST_ENTRY(alq) aq_act; /* List of active queues */ 699405072aSJeff Roberson LIST_ENTRY(alq) aq_link; /* List of all queues */ 709405072aSJeff Roberson }; 719405072aSJeff Roberson 729405072aSJeff Roberson #define AQ_WANTED 0x0001 /* Wakeup sleeper when io is done */ 739405072aSJeff Roberson #define AQ_ACTIVE 0x0002 /* on the active list */ 749405072aSJeff Roberson #define AQ_FLUSHING 0x0004 /* doing IO */ 759405072aSJeff Roberson #define AQ_SHUTDOWN 0x0008 /* Queue no longer valid */ 769405072aSJeff Roberson 779405072aSJeff Roberson #define ALQ_LOCK(alq) mtx_lock_spin(&(alq)->aq_mtx) 789405072aSJeff Roberson #define ALQ_UNLOCK(alq) mtx_unlock_spin(&(alq)->aq_mtx) 799405072aSJeff Roberson 809405072aSJeff Roberson static MALLOC_DEFINE(M_ALD, "ALD", "ALD"); 819405072aSJeff Roberson 829405072aSJeff Roberson /* 839405072aSJeff Roberson * The ald_mtx protects the ald_queues list and the ald_active list. 849405072aSJeff Roberson */ 859405072aSJeff Roberson static struct mtx ald_mtx; 869405072aSJeff Roberson static LIST_HEAD(, alq) ald_queues; 879405072aSJeff Roberson static LIST_HEAD(, alq) ald_active; 889405072aSJeff Roberson static int ald_shutingdown = 0; 89a414302fSJeff Roberson struct thread *ald_thread; 90a414302fSJeff Roberson static struct proc *ald_proc; 919405072aSJeff Roberson 929405072aSJeff Roberson #define ALD_LOCK() mtx_lock(&ald_mtx) 939405072aSJeff Roberson #define ALD_UNLOCK() mtx_unlock(&ald_mtx) 949405072aSJeff Roberson 959405072aSJeff Roberson /* Daemon functions */ 969405072aSJeff Roberson static int ald_add(struct alq *); 979405072aSJeff Roberson static int ald_rem(struct alq *); 989405072aSJeff Roberson static void ald_startup(void *); 999405072aSJeff Roberson static void ald_daemon(void); 1009405072aSJeff Roberson static void ald_shutdown(void *, int); 1019405072aSJeff Roberson static void ald_activate(struct alq *); 1029405072aSJeff Roberson static void ald_deactivate(struct alq *); 1039405072aSJeff Roberson 1049405072aSJeff Roberson /* Internal queue functions */ 1059405072aSJeff Roberson static void alq_shutdown(struct alq *); 106c0ea37a8SLawrence Stewart static void alq_destroy(struct alq *); 1079405072aSJeff Roberson static int alq_doio(struct alq *); 1089405072aSJeff Roberson 1099405072aSJeff Roberson 1109405072aSJeff Roberson /* 1119405072aSJeff Roberson * Add a new queue to the global list. Fail if we're shutting down. 1129405072aSJeff Roberson */ 1139405072aSJeff Roberson static int 1149405072aSJeff Roberson ald_add(struct alq *alq) 1159405072aSJeff Roberson { 1169405072aSJeff Roberson int error; 1179405072aSJeff Roberson 1189405072aSJeff Roberson error = 0; 1199405072aSJeff Roberson 1209405072aSJeff Roberson ALD_LOCK(); 1219405072aSJeff Roberson if (ald_shutingdown) { 1229405072aSJeff Roberson error = EBUSY; 1239405072aSJeff Roberson goto done; 1249405072aSJeff Roberson } 1259405072aSJeff Roberson LIST_INSERT_HEAD(&ald_queues, alq, aq_link); 1269405072aSJeff Roberson done: 1279405072aSJeff Roberson ALD_UNLOCK(); 1289405072aSJeff Roberson return (error); 1299405072aSJeff Roberson } 1309405072aSJeff Roberson 1319405072aSJeff Roberson /* 1329405072aSJeff Roberson * Remove a queue from the global list unless we're shutting down. If so, 1339405072aSJeff Roberson * the ald will take care of cleaning up it's resources. 1349405072aSJeff Roberson */ 1359405072aSJeff Roberson static int 1369405072aSJeff Roberson ald_rem(struct alq *alq) 1379405072aSJeff Roberson { 1389405072aSJeff Roberson int error; 1399405072aSJeff Roberson 1409405072aSJeff Roberson error = 0; 1419405072aSJeff Roberson 1429405072aSJeff Roberson ALD_LOCK(); 1439405072aSJeff Roberson if (ald_shutingdown) { 1449405072aSJeff Roberson error = EBUSY; 1459405072aSJeff Roberson goto done; 1469405072aSJeff Roberson } 1479405072aSJeff Roberson LIST_REMOVE(alq, aq_link); 1489405072aSJeff Roberson done: 1499405072aSJeff Roberson ALD_UNLOCK(); 1509405072aSJeff Roberson return (error); 1519405072aSJeff Roberson } 1529405072aSJeff Roberson 1539405072aSJeff Roberson /* 1549405072aSJeff Roberson * Put a queue on the active list. This will schedule it for writing. 1559405072aSJeff Roberson */ 1569405072aSJeff Roberson static void 1579405072aSJeff Roberson ald_activate(struct alq *alq) 1589405072aSJeff Roberson { 1599405072aSJeff Roberson LIST_INSERT_HEAD(&ald_active, alq, aq_act); 1609405072aSJeff Roberson wakeup(&ald_active); 1619405072aSJeff Roberson } 1629405072aSJeff Roberson 1639405072aSJeff Roberson static void 1649405072aSJeff Roberson ald_deactivate(struct alq *alq) 1659405072aSJeff Roberson { 1669405072aSJeff Roberson LIST_REMOVE(alq, aq_act); 1679405072aSJeff Roberson alq->aq_flags &= ~AQ_ACTIVE; 1689405072aSJeff Roberson } 1699405072aSJeff Roberson 1709405072aSJeff Roberson static void 1719405072aSJeff Roberson ald_startup(void *unused) 1729405072aSJeff Roberson { 1739405072aSJeff Roberson mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET); 1749405072aSJeff Roberson LIST_INIT(&ald_queues); 1759405072aSJeff Roberson LIST_INIT(&ald_active); 1769405072aSJeff Roberson } 1779405072aSJeff Roberson 1789405072aSJeff Roberson static void 1799405072aSJeff Roberson ald_daemon(void) 1809405072aSJeff Roberson { 1819405072aSJeff Roberson int needwakeup; 1829405072aSJeff Roberson struct alq *alq; 1839405072aSJeff Roberson 184a414302fSJeff Roberson ald_thread = FIRST_THREAD_IN_PROC(ald_proc); 185a414302fSJeff Roberson 1869405072aSJeff Roberson EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL, 1879405072aSJeff Roberson SHUTDOWN_PRI_FIRST); 1889405072aSJeff Roberson 1899405072aSJeff Roberson ALD_LOCK(); 1909405072aSJeff Roberson 1919405072aSJeff Roberson for (;;) { 192d28f42f9SLawrence Stewart while ((alq = LIST_FIRST(&ald_active)) == NULL && 193d28f42f9SLawrence Stewart !ald_shutingdown) 1949ffad7a9SLawrence Stewart mtx_sleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0); 1959405072aSJeff Roberson 196d28f42f9SLawrence Stewart /* Don't shutdown until all active ALQs are flushed. */ 197d28f42f9SLawrence Stewart if (ald_shutingdown && alq == NULL) { 198d28f42f9SLawrence Stewart ALD_UNLOCK(); 199d28f42f9SLawrence Stewart break; 200d28f42f9SLawrence Stewart } 201d28f42f9SLawrence Stewart 2029405072aSJeff Roberson ALQ_LOCK(alq); 2039405072aSJeff Roberson ald_deactivate(alq); 2049405072aSJeff Roberson ALD_UNLOCK(); 2059405072aSJeff Roberson needwakeup = alq_doio(alq); 2069405072aSJeff Roberson ALQ_UNLOCK(alq); 2079405072aSJeff Roberson if (needwakeup) 2089405072aSJeff Roberson wakeup(alq); 2099405072aSJeff Roberson ALD_LOCK(); 2109405072aSJeff Roberson } 211d28f42f9SLawrence Stewart 212d28f42f9SLawrence Stewart kproc_exit(0); 2139405072aSJeff Roberson } 2149405072aSJeff Roberson 2159405072aSJeff Roberson static void 2169405072aSJeff Roberson ald_shutdown(void *arg, int howto) 2179405072aSJeff Roberson { 2189405072aSJeff Roberson struct alq *alq; 2199405072aSJeff Roberson 2209405072aSJeff Roberson ALD_LOCK(); 221d28f42f9SLawrence Stewart 222d28f42f9SLawrence Stewart /* Ensure no new queues can be created. */ 2239405072aSJeff Roberson ald_shutingdown = 1; 2249405072aSJeff Roberson 225d28f42f9SLawrence Stewart /* Shutdown all ALQs prior to terminating the ald_daemon. */ 2269405072aSJeff Roberson while ((alq = LIST_FIRST(&ald_queues)) != NULL) { 2279405072aSJeff Roberson LIST_REMOVE(alq, aq_link); 2289405072aSJeff Roberson ALD_UNLOCK(); 2299405072aSJeff Roberson alq_shutdown(alq); 2309405072aSJeff Roberson ALD_LOCK(); 2319405072aSJeff Roberson } 232d28f42f9SLawrence Stewart 233d28f42f9SLawrence Stewart /* At this point, all ALQs are flushed and shutdown. */ 234d28f42f9SLawrence Stewart 235d28f42f9SLawrence Stewart /* 236d28f42f9SLawrence Stewart * Wake ald_daemon so that it exits. It won't be able to do 2379ffad7a9SLawrence Stewart * anything until we mtx_sleep because we hold the ald_mtx. 238d28f42f9SLawrence Stewart */ 239d28f42f9SLawrence Stewart wakeup(&ald_active); 240d28f42f9SLawrence Stewart 241d28f42f9SLawrence Stewart /* Wait for ald_daemon to exit. */ 2429ffad7a9SLawrence Stewart mtx_sleep(ald_proc, &ald_mtx, PWAIT, "aldslp", 0); 243d28f42f9SLawrence Stewart 2449405072aSJeff Roberson ALD_UNLOCK(); 2459405072aSJeff Roberson } 2469405072aSJeff Roberson 2479405072aSJeff Roberson static void 2489405072aSJeff Roberson alq_shutdown(struct alq *alq) 2499405072aSJeff Roberson { 2509405072aSJeff Roberson ALQ_LOCK(alq); 2519405072aSJeff Roberson 2529405072aSJeff Roberson /* Stop any new writers. */ 2539405072aSJeff Roberson alq->aq_flags |= AQ_SHUTDOWN; 2549405072aSJeff Roberson 2559405072aSJeff Roberson /* Drain IO */ 25697c11ef2SLawrence Stewart while (alq->aq_flags & AQ_ACTIVE) { 2579405072aSJeff Roberson alq->aq_flags |= AQ_WANTED; 258bff2d4d5SRoman Divacky msleep_spin(alq, &alq->aq_mtx, "aldclose", 0); 2599405072aSJeff Roberson } 2609405072aSJeff Roberson ALQ_UNLOCK(alq); 2619405072aSJeff Roberson 262a414302fSJeff Roberson vn_close(alq->aq_vp, FWRITE, alq->aq_cred, 2639e9256e2SJeff Roberson curthread); 2649e9256e2SJeff Roberson crfree(alq->aq_cred); 2659405072aSJeff Roberson } 2669405072aSJeff Roberson 267c0ea37a8SLawrence Stewart void 268c0ea37a8SLawrence Stewart alq_destroy(struct alq *alq) 269c0ea37a8SLawrence Stewart { 270c0ea37a8SLawrence Stewart /* Drain all pending IO. */ 271c0ea37a8SLawrence Stewart alq_shutdown(alq); 272c0ea37a8SLawrence Stewart 273c0ea37a8SLawrence Stewart mtx_destroy(&alq->aq_mtx); 274c0ea37a8SLawrence Stewart free(alq->aq_first, M_ALD); 275c0ea37a8SLawrence Stewart free(alq->aq_entbuf, M_ALD); 276c0ea37a8SLawrence Stewart free(alq, M_ALD); 277c0ea37a8SLawrence Stewart } 278c0ea37a8SLawrence Stewart 2799405072aSJeff Roberson /* 2809405072aSJeff Roberson * Flush all pending data to disk. This operation will block. 2819405072aSJeff Roberson */ 2829405072aSJeff Roberson static int 2839405072aSJeff Roberson alq_doio(struct alq *alq) 2849405072aSJeff Roberson { 2859405072aSJeff Roberson struct thread *td; 2869405072aSJeff Roberson struct mount *mp; 2879405072aSJeff Roberson struct vnode *vp; 2889405072aSJeff Roberson struct uio auio; 2899405072aSJeff Roberson struct iovec aiov[2]; 2909405072aSJeff Roberson struct ale *ale; 2919405072aSJeff Roberson struct ale *alstart; 2929405072aSJeff Roberson int totlen; 2939405072aSJeff Roberson int iov; 29433f19beeSJohn Baldwin int vfslocked; 2959405072aSJeff Roberson 2969405072aSJeff Roberson vp = alq->aq_vp; 2979405072aSJeff Roberson td = curthread; 2989405072aSJeff Roberson totlen = 0; 2999405072aSJeff Roberson iov = 0; 3009405072aSJeff Roberson 3019405072aSJeff Roberson alstart = ale = alq->aq_entvalid; 3029405072aSJeff Roberson alq->aq_entvalid = NULL; 3039405072aSJeff Roberson 3049405072aSJeff Roberson bzero(&aiov, sizeof(aiov)); 3059405072aSJeff Roberson bzero(&auio, sizeof(auio)); 3069405072aSJeff Roberson 3079405072aSJeff Roberson do { 3089405072aSJeff Roberson if (aiov[iov].iov_base == NULL) 3099405072aSJeff Roberson aiov[iov].iov_base = ale->ae_data; 3109405072aSJeff Roberson aiov[iov].iov_len += alq->aq_entlen; 3119405072aSJeff Roberson totlen += alq->aq_entlen; 3129405072aSJeff Roberson /* Check to see if we're wrapping the buffer */ 3139405072aSJeff Roberson if (ale->ae_data + alq->aq_entlen != ale->ae_next->ae_data) 3149405072aSJeff Roberson iov++; 3159405072aSJeff Roberson ale->ae_flags &= ~AE_VALID; 3169405072aSJeff Roberson ale = ale->ae_next; 3179405072aSJeff Roberson } while (ale->ae_flags & AE_VALID); 3189405072aSJeff Roberson 3199405072aSJeff Roberson alq->aq_flags |= AQ_FLUSHING; 3209405072aSJeff Roberson ALQ_UNLOCK(alq); 3219405072aSJeff Roberson 3229405072aSJeff Roberson if (iov == 2 || aiov[iov].iov_base == NULL) 3239405072aSJeff Roberson iov--; 3249405072aSJeff Roberson 3259405072aSJeff Roberson auio.uio_iov = &aiov[0]; 3269405072aSJeff Roberson auio.uio_offset = 0; 3279405072aSJeff Roberson auio.uio_segflg = UIO_SYSSPACE; 3289405072aSJeff Roberson auio.uio_rw = UIO_WRITE; 3299405072aSJeff Roberson auio.uio_iovcnt = iov + 1; 3309405072aSJeff Roberson auio.uio_resid = totlen; 3319405072aSJeff Roberson auio.uio_td = td; 3329405072aSJeff Roberson 3339405072aSJeff Roberson /* 3349405072aSJeff Roberson * Do all of the junk required to write now. 3359405072aSJeff Roberson */ 33633f19beeSJohn Baldwin vfslocked = VFS_LOCK_GIANT(vp->v_mount); 3379405072aSJeff Roberson vn_start_write(vp, &mp, V_WAIT); 338cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 33967536f03SRobert Watson /* 34067536f03SRobert Watson * XXX: VOP_WRITE error checks are ignored. 34167536f03SRobert Watson */ 34267536f03SRobert Watson #ifdef MAC 34330d239bcSRobert Watson if (mac_vnode_check_write(alq->aq_cred, NOCRED, vp) == 0) 34467536f03SRobert Watson #endif 3459e9256e2SJeff Roberson VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred); 34622db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 3479405072aSJeff Roberson vn_finished_write(mp); 34833f19beeSJohn Baldwin VFS_UNLOCK_GIANT(vfslocked); 3499405072aSJeff Roberson 3509405072aSJeff Roberson ALQ_LOCK(alq); 3519405072aSJeff Roberson alq->aq_flags &= ~AQ_FLUSHING; 3529405072aSJeff Roberson 3539405072aSJeff Roberson if (alq->aq_entfree == NULL) 3549405072aSJeff Roberson alq->aq_entfree = alstart; 3559405072aSJeff Roberson 3569405072aSJeff Roberson if (alq->aq_flags & AQ_WANTED) { 3579405072aSJeff Roberson alq->aq_flags &= ~AQ_WANTED; 3589405072aSJeff Roberson return (1); 3599405072aSJeff Roberson } 3609405072aSJeff Roberson 3619405072aSJeff Roberson return(0); 3629405072aSJeff Roberson } 3639405072aSJeff Roberson 3649405072aSJeff Roberson static struct kproc_desc ald_kp = { 3659405072aSJeff Roberson "ALQ Daemon", 3669405072aSJeff Roberson ald_daemon, 367a414302fSJeff Roberson &ald_proc 3689405072aSJeff Roberson }; 3699405072aSJeff Roberson 370237fdd78SRobert Watson SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp); 371237fdd78SRobert Watson SYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL); 3729405072aSJeff Roberson 3739405072aSJeff Roberson 3749405072aSJeff Roberson /* User visible queue functions */ 3759405072aSJeff Roberson 3769405072aSJeff Roberson /* 3779405072aSJeff Roberson * Create the queue data structure, allocate the buffer, and open the file. 3789405072aSJeff Roberson */ 3799405072aSJeff Roberson int 380e551d452SRobert Watson alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 381e551d452SRobert Watson int size, int count) 3829405072aSJeff Roberson { 3839405072aSJeff Roberson struct thread *td; 3849405072aSJeff Roberson struct nameidata nd; 3859405072aSJeff Roberson struct ale *ale; 3869405072aSJeff Roberson struct ale *alp; 3879405072aSJeff Roberson struct alq *alq; 3889405072aSJeff Roberson char *bufp; 3899405072aSJeff Roberson int flags; 3909405072aSJeff Roberson int error; 39133f19beeSJohn Baldwin int i, vfslocked; 3929405072aSJeff Roberson 3939405072aSJeff Roberson *alqp = NULL; 3949405072aSJeff Roberson td = curthread; 3959405072aSJeff Roberson 39633f19beeSJohn Baldwin NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, file, td); 397a414302fSJeff Roberson flags = FWRITE | O_NOFOLLOW | O_CREAT; 3989405072aSJeff Roberson 399e0c161b8SKonstantin Belousov error = vn_open_cred(&nd, &flags, cmode, 0, cred, NULL); 4009405072aSJeff Roberson if (error) 4019405072aSJeff Roberson return (error); 4029405072aSJeff Roberson 40333f19beeSJohn Baldwin vfslocked = NDHASGIANT(&nd); 404f220f7afSPawel Jakub Dawidek NDFREE(&nd, NDF_ONLY_PNBUF); 4059405072aSJeff Roberson /* We just unlock so we hold a reference */ 40622db15c0SAttilio Rao VOP_UNLOCK(nd.ni_vp, 0); 40733f19beeSJohn Baldwin VFS_UNLOCK_GIANT(vfslocked); 4089405072aSJeff Roberson 409a163d034SWarner Losh alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO); 410a163d034SWarner Losh alq->aq_entbuf = malloc(count * size, M_ALD, M_WAITOK|M_ZERO); 411a163d034SWarner Losh alq->aq_first = malloc(sizeof(*ale) * count, M_ALD, M_WAITOK|M_ZERO); 4129405072aSJeff Roberson alq->aq_vp = nd.ni_vp; 4134b090e41SRobert Watson alq->aq_cred = crhold(cred); 4149405072aSJeff Roberson alq->aq_entmax = count; 4159405072aSJeff Roberson alq->aq_entlen = size; 4169405072aSJeff Roberson alq->aq_entfree = alq->aq_first; 4179405072aSJeff Roberson 4189405072aSJeff Roberson mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET); 4199405072aSJeff Roberson 4209405072aSJeff Roberson bufp = alq->aq_entbuf; 4219405072aSJeff Roberson ale = alq->aq_first; 4229405072aSJeff Roberson alp = NULL; 4239405072aSJeff Roberson 4249405072aSJeff Roberson /* Match up entries with buffers */ 4259405072aSJeff Roberson for (i = 0; i < count; i++) { 4269405072aSJeff Roberson if (alp) 4279405072aSJeff Roberson alp->ae_next = ale; 4289405072aSJeff Roberson ale->ae_data = bufp; 4299405072aSJeff Roberson alp = ale; 4309405072aSJeff Roberson ale++; 4319405072aSJeff Roberson bufp += size; 4329405072aSJeff Roberson } 4339405072aSJeff Roberson 4349405072aSJeff Roberson alp->ae_next = alq->aq_first; 4359405072aSJeff Roberson 436c0ea37a8SLawrence Stewart if ((error = ald_add(alq)) != 0) { 437c0ea37a8SLawrence Stewart alq_destroy(alq); 4389405072aSJeff Roberson return (error); 439c0ea37a8SLawrence Stewart } 440c0ea37a8SLawrence Stewart 4419405072aSJeff Roberson *alqp = alq; 4429405072aSJeff Roberson 4439405072aSJeff Roberson return (0); 4449405072aSJeff Roberson } 4459405072aSJeff Roberson 4469405072aSJeff Roberson /* 4479405072aSJeff Roberson * Copy a new entry into the queue. If the operation would block either 4489405072aSJeff Roberson * wait or return an error depending on the value of waitok. 4499405072aSJeff Roberson */ 4509405072aSJeff Roberson int 4519405072aSJeff Roberson alq_write(struct alq *alq, void *data, int waitok) 4529405072aSJeff Roberson { 4539405072aSJeff Roberson struct ale *ale; 4549405072aSJeff Roberson 4559405072aSJeff Roberson if ((ale = alq_get(alq, waitok)) == NULL) 4569405072aSJeff Roberson return (EWOULDBLOCK); 4579405072aSJeff Roberson 4589405072aSJeff Roberson bcopy(data, ale->ae_data, alq->aq_entlen); 4599405072aSJeff Roberson alq_post(alq, ale); 4609405072aSJeff Roberson 4619405072aSJeff Roberson return (0); 4629405072aSJeff Roberson } 4639405072aSJeff Roberson 4649405072aSJeff Roberson struct ale * 4659405072aSJeff Roberson alq_get(struct alq *alq, int waitok) 4669405072aSJeff Roberson { 4679405072aSJeff Roberson struct ale *ale; 4689405072aSJeff Roberson struct ale *aln; 4699405072aSJeff Roberson 4709405072aSJeff Roberson ale = NULL; 4719405072aSJeff Roberson 4729405072aSJeff Roberson ALQ_LOCK(alq); 4739405072aSJeff Roberson 4749405072aSJeff Roberson /* Loop until we get an entry or we're shutting down */ 4759405072aSJeff Roberson while ((alq->aq_flags & AQ_SHUTDOWN) == 0 && 4769405072aSJeff Roberson (ale = alq->aq_entfree) == NULL && 4779405072aSJeff Roberson (waitok & ALQ_WAITOK)) { 4789405072aSJeff Roberson alq->aq_flags |= AQ_WANTED; 479bff2d4d5SRoman Divacky msleep_spin(alq, &alq->aq_mtx, "alqget", 0); 4809405072aSJeff Roberson } 4819405072aSJeff Roberson 4829405072aSJeff Roberson if (ale != NULL) { 4839405072aSJeff Roberson aln = ale->ae_next; 4849405072aSJeff Roberson if ((aln->ae_flags & AE_VALID) == 0) 4859405072aSJeff Roberson alq->aq_entfree = aln; 48630fd5d08SJeff Roberson else 48730fd5d08SJeff Roberson alq->aq_entfree = NULL; 4889405072aSJeff Roberson } else 4899405072aSJeff Roberson ALQ_UNLOCK(alq); 4909405072aSJeff Roberson 4919405072aSJeff Roberson 4929405072aSJeff Roberson return (ale); 4939405072aSJeff Roberson } 4949405072aSJeff Roberson 4959405072aSJeff Roberson void 4969405072aSJeff Roberson alq_post(struct alq *alq, struct ale *ale) 4979405072aSJeff Roberson { 4989405072aSJeff Roberson int activate; 4999405072aSJeff Roberson 5009405072aSJeff Roberson ale->ae_flags |= AE_VALID; 5019405072aSJeff Roberson 5029405072aSJeff Roberson if (alq->aq_entvalid == NULL) 5039405072aSJeff Roberson alq->aq_entvalid = ale; 5049405072aSJeff Roberson 5059405072aSJeff Roberson if ((alq->aq_flags & AQ_ACTIVE) == 0) { 5069405072aSJeff Roberson alq->aq_flags |= AQ_ACTIVE; 5079405072aSJeff Roberson activate = 1; 5089405072aSJeff Roberson } else 5099405072aSJeff Roberson activate = 0; 5109405072aSJeff Roberson 5119405072aSJeff Roberson ALQ_UNLOCK(alq); 5129405072aSJeff Roberson if (activate) { 5139405072aSJeff Roberson ALD_LOCK(); 5149405072aSJeff Roberson ald_activate(alq); 5159405072aSJeff Roberson ALD_UNLOCK(); 5169405072aSJeff Roberson } 5179405072aSJeff Roberson } 5189405072aSJeff Roberson 5199405072aSJeff Roberson void 5209405072aSJeff Roberson alq_flush(struct alq *alq) 5219405072aSJeff Roberson { 5229405072aSJeff Roberson int needwakeup = 0; 5239405072aSJeff Roberson 5249405072aSJeff Roberson ALD_LOCK(); 5259405072aSJeff Roberson ALQ_LOCK(alq); 5269405072aSJeff Roberson if (alq->aq_flags & AQ_ACTIVE) { 5279405072aSJeff Roberson ald_deactivate(alq); 5289405072aSJeff Roberson ALD_UNLOCK(); 5299405072aSJeff Roberson needwakeup = alq_doio(alq); 5309405072aSJeff Roberson } else 5319405072aSJeff Roberson ALD_UNLOCK(); 5329405072aSJeff Roberson ALQ_UNLOCK(alq); 5339405072aSJeff Roberson 5349405072aSJeff Roberson if (needwakeup) 5359405072aSJeff Roberson wakeup(alq); 5369405072aSJeff Roberson } 5379405072aSJeff Roberson 5389405072aSJeff Roberson /* 5399405072aSJeff Roberson * Flush remaining data, close the file and free all resources. 5409405072aSJeff Roberson */ 5419405072aSJeff Roberson void 5429405072aSJeff Roberson alq_close(struct alq *alq) 5439405072aSJeff Roberson { 544c0ea37a8SLawrence Stewart /* Only flush and destroy alq if not already shutting down. */ 545c0ea37a8SLawrence Stewart if (ald_rem(alq) == 0) 546c0ea37a8SLawrence Stewart alq_destroy(alq); 5479405072aSJeff Roberson } 548d28f42f9SLawrence Stewart 549d28f42f9SLawrence Stewart static int 550d28f42f9SLawrence Stewart alq_load_handler(module_t mod, int what, void *arg) 551d28f42f9SLawrence Stewart { 552d28f42f9SLawrence Stewart int ret; 553d28f42f9SLawrence Stewart 554d28f42f9SLawrence Stewart ret = 0; 555d28f42f9SLawrence Stewart 556d28f42f9SLawrence Stewart switch (what) { 557d28f42f9SLawrence Stewart case MOD_LOAD: 558d28f42f9SLawrence Stewart case MOD_SHUTDOWN: 559d28f42f9SLawrence Stewart break; 560d28f42f9SLawrence Stewart 561d28f42f9SLawrence Stewart case MOD_QUIESCE: 562d28f42f9SLawrence Stewart ALD_LOCK(); 563d28f42f9SLawrence Stewart /* Only allow unload if there are no open queues. */ 564d28f42f9SLawrence Stewart if (LIST_FIRST(&ald_queues) == NULL) { 565d28f42f9SLawrence Stewart ald_shutingdown = 1; 566d28f42f9SLawrence Stewart ALD_UNLOCK(); 567d28f42f9SLawrence Stewart ald_shutdown(NULL, 0); 568d28f42f9SLawrence Stewart mtx_destroy(&ald_mtx); 569d28f42f9SLawrence Stewart } else { 570d28f42f9SLawrence Stewart ALD_UNLOCK(); 571d28f42f9SLawrence Stewart ret = EBUSY; 572d28f42f9SLawrence Stewart } 573d28f42f9SLawrence Stewart break; 574d28f42f9SLawrence Stewart 575d28f42f9SLawrence Stewart case MOD_UNLOAD: 576d28f42f9SLawrence Stewart /* If MOD_QUIESCE failed we must fail here too. */ 577d28f42f9SLawrence Stewart if (ald_shutingdown == 0) 578d28f42f9SLawrence Stewart ret = EBUSY; 579d28f42f9SLawrence Stewart break; 580d28f42f9SLawrence Stewart 581d28f42f9SLawrence Stewart default: 582d28f42f9SLawrence Stewart ret = EINVAL; 583d28f42f9SLawrence Stewart break; 584d28f42f9SLawrence Stewart } 585d28f42f9SLawrence Stewart 586d28f42f9SLawrence Stewart return (ret); 587d28f42f9SLawrence Stewart } 588d28f42f9SLawrence Stewart 589d28f42f9SLawrence Stewart static moduledata_t alq_mod = 590d28f42f9SLawrence Stewart { 591d28f42f9SLawrence Stewart "alq", 592d28f42f9SLawrence Stewart alq_load_handler, 593d28f42f9SLawrence Stewart NULL 594d28f42f9SLawrence Stewart }; 595d28f42f9SLawrence Stewart 596d28f42f9SLawrence Stewart DECLARE_MODULE(alq, alq_mod, SI_SUB_SMP, SI_ORDER_ANY); 597d28f42f9SLawrence Stewart MODULE_VERSION(alq, 1); 598