1139804Simp/*- 2103785Sjeff * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org> 3205959Slstewart * Copyright (c) 2008-2009, Lawrence Stewart <lstewart@freebsd.org> 4205959Slstewart * Copyright (c) 2009-2010, The FreeBSD Foundation 5103785Sjeff * All rights reserved. 6103785Sjeff * 7205959Slstewart * Portions of this software were developed at the Centre for Advanced 8205959Slstewart * Internet Architectures, Swinburne University of Technology, Melbourne, 9205959Slstewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 10205959Slstewart * 11103785Sjeff * Redistribution and use in source and binary forms, with or without 12103785Sjeff * modification, are permitted provided that the following conditions 13103785Sjeff * are met: 14103785Sjeff * 1. Redistributions of source code must retain the above copyright 15103785Sjeff * notice unmodified, this list of conditions, and the following 16103785Sjeff * disclaimer. 17103785Sjeff * 2. Redistributions in binary form must reproduce the above copyright 18103785Sjeff * notice, this list of conditions and the following disclaimer in the 19103785Sjeff * documentation and/or other materials provided with the distribution. 20103785Sjeff * 21103785Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22103785Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23103785Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24103785Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25103785Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26103785Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27103785Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28103785Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29103785Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30103785Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31103785Sjeff */ 32103785Sjeff 33116182Sobrien#include <sys/cdefs.h> 34116182Sobrien__FBSDID("$FreeBSD: releng/10.2/sys/kern/kern_alq.c 264366 2014-04-12 06:50:11Z dchagin $"); 35116182Sobrien 36205959Slstewart#include "opt_mac.h" 37205959Slstewart 38103785Sjeff#include <sys/param.h> 39103785Sjeff#include <sys/systm.h> 40103785Sjeff#include <sys/kernel.h> 41103785Sjeff#include <sys/kthread.h> 42103785Sjeff#include <sys/lock.h> 43157233Sjhb#include <sys/mount.h> 44103785Sjeff#include <sys/mutex.h> 45103785Sjeff#include <sys/namei.h> 46103785Sjeff#include <sys/proc.h> 47103785Sjeff#include <sys/vnode.h> 48103785Sjeff#include <sys/alq.h> 49103785Sjeff#include <sys/malloc.h> 50103785Sjeff#include <sys/unistd.h> 51103785Sjeff#include <sys/fcntl.h> 52103785Sjeff#include <sys/eventhandler.h> 53103785Sjeff 54163606Srwatson#include <security/mac/mac_framework.h> 55163606Srwatson 56103785Sjeff/* Async. Logging Queue */ 57103785Sjeffstruct alq { 58207223Slstewart char *aq_entbuf; /* Buffer for stored entries */ 59103785Sjeff int aq_entmax; /* Max entries */ 60103785Sjeff int aq_entlen; /* Entry length */ 61207223Slstewart int aq_freebytes; /* Bytes available in buffer */ 62207223Slstewart int aq_buflen; /* Total length of our buffer */ 63207223Slstewart int aq_writehead; /* Location for next write */ 64207223Slstewart int aq_writetail; /* Flush starts at this location */ 65207223Slstewart int aq_wrapearly; /* # bytes left blank at end of buf */ 66103785Sjeff int aq_flags; /* Queue flags */ 67207223Slstewart int aq_waiters; /* Num threads waiting for resources 68207223Slstewart * NB: Used as a wait channel so must 69207223Slstewart * not be first field in the alq struct 70207223Slstewart */ 71207223Slstewart struct ale aq_getpost; /* ALE for use by get/post */ 72103785Sjeff struct mtx aq_mtx; /* Queue lock */ 73103785Sjeff struct vnode *aq_vp; /* Open vnode handle */ 74103830Sjeff struct ucred *aq_cred; /* Credentials of the opening thread */ 75103785Sjeff LIST_ENTRY(alq) aq_act; /* List of active queues */ 76103785Sjeff LIST_ENTRY(alq) aq_link; /* List of all queues */ 77103785Sjeff}; 78103785Sjeff 79103785Sjeff#define AQ_WANTED 0x0001 /* Wakeup sleeper when io is done */ 80103785Sjeff#define AQ_ACTIVE 0x0002 /* on the active list */ 81103785Sjeff#define AQ_FLUSHING 0x0004 /* doing IO */ 82103785Sjeff#define AQ_SHUTDOWN 0x0008 /* Queue no longer valid */ 83207223Slstewart#define AQ_ORDERED 0x0010 /* Queue enforces ordered writes */ 84207223Slstewart#define AQ_LEGACY 0x0020 /* Legacy queue (fixed length writes) */ 85103785Sjeff 86103785Sjeff#define ALQ_LOCK(alq) mtx_lock_spin(&(alq)->aq_mtx) 87103785Sjeff#define ALQ_UNLOCK(alq) mtx_unlock_spin(&(alq)->aq_mtx) 88103785Sjeff 89207223Slstewart#define HAS_PENDING_DATA(alq) ((alq)->aq_freebytes != (alq)->aq_buflen) 90207223Slstewart 91103785Sjeffstatic MALLOC_DEFINE(M_ALD, "ALD", "ALD"); 92103785Sjeff 93103785Sjeff/* 94103785Sjeff * The ald_mtx protects the ald_queues list and the ald_active list. 95103785Sjeff */ 96103785Sjeffstatic struct mtx ald_mtx; 97103785Sjeffstatic LIST_HEAD(, alq) ald_queues; 98103785Sjeffstatic LIST_HEAD(, alq) ald_active; 99103785Sjeffstatic int ald_shutingdown = 0; 100103995Sjeffstruct thread *ald_thread; 101103995Sjeffstatic struct proc *ald_proc; 102250951Slstewartstatic eventhandler_tag alq_eventhandler_tag = NULL; 103103785Sjeff 104103785Sjeff#define ALD_LOCK() mtx_lock(&ald_mtx) 105103785Sjeff#define ALD_UNLOCK() mtx_unlock(&ald_mtx) 106103785Sjeff 107103785Sjeff/* Daemon functions */ 108103785Sjeffstatic int ald_add(struct alq *); 109103785Sjeffstatic int ald_rem(struct alq *); 110103785Sjeffstatic void ald_startup(void *); 111103785Sjeffstatic void ald_daemon(void); 112103785Sjeffstatic void ald_shutdown(void *, int); 113103785Sjeffstatic void ald_activate(struct alq *); 114103785Sjeffstatic void ald_deactivate(struct alq *); 115103785Sjeff 116103785Sjeff/* Internal queue functions */ 117103785Sjeffstatic void alq_shutdown(struct alq *); 118206026Slstewartstatic void alq_destroy(struct alq *); 119103785Sjeffstatic int alq_doio(struct alq *); 120103785Sjeff 121103785Sjeff 122103785Sjeff/* 123103785Sjeff * Add a new queue to the global list. Fail if we're shutting down. 124103785Sjeff */ 125103785Sjeffstatic int 126103785Sjeffald_add(struct alq *alq) 127103785Sjeff{ 128103785Sjeff int error; 129103785Sjeff 130103785Sjeff error = 0; 131103785Sjeff 132103785Sjeff ALD_LOCK(); 133103785Sjeff if (ald_shutingdown) { 134103785Sjeff error = EBUSY; 135103785Sjeff goto done; 136103785Sjeff } 137103785Sjeff LIST_INSERT_HEAD(&ald_queues, alq, aq_link); 138103785Sjeffdone: 139103785Sjeff ALD_UNLOCK(); 140103785Sjeff return (error); 141103785Sjeff} 142103785Sjeff 143103785Sjeff/* 144103785Sjeff * Remove a queue from the global list unless we're shutting down. If so, 145103785Sjeff * the ald will take care of cleaning up it's resources. 146103785Sjeff */ 147103785Sjeffstatic int 148103785Sjeffald_rem(struct alq *alq) 149103785Sjeff{ 150103785Sjeff int error; 151103785Sjeff 152103785Sjeff error = 0; 153103785Sjeff 154103785Sjeff ALD_LOCK(); 155103785Sjeff if (ald_shutingdown) { 156103785Sjeff error = EBUSY; 157103785Sjeff goto done; 158103785Sjeff } 159103785Sjeff LIST_REMOVE(alq, aq_link); 160103785Sjeffdone: 161103785Sjeff ALD_UNLOCK(); 162103785Sjeff return (error); 163103785Sjeff} 164103785Sjeff 165103785Sjeff/* 166103785Sjeff * Put a queue on the active list. This will schedule it for writing. 167103785Sjeff */ 168103785Sjeffstatic void 169103785Sjeffald_activate(struct alq *alq) 170103785Sjeff{ 171103785Sjeff LIST_INSERT_HEAD(&ald_active, alq, aq_act); 172103785Sjeff wakeup(&ald_active); 173103785Sjeff} 174103785Sjeff 175103785Sjeffstatic void 176103785Sjeffald_deactivate(struct alq *alq) 177103785Sjeff{ 178103785Sjeff LIST_REMOVE(alq, aq_act); 179103785Sjeff alq->aq_flags &= ~AQ_ACTIVE; 180103785Sjeff} 181103785Sjeff 182103785Sjeffstatic void 183103785Sjeffald_startup(void *unused) 184103785Sjeff{ 185103785Sjeff mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET); 186103785Sjeff LIST_INIT(&ald_queues); 187103785Sjeff LIST_INIT(&ald_active); 188103785Sjeff} 189103785Sjeff 190103785Sjeffstatic void 191103785Sjeffald_daemon(void) 192103785Sjeff{ 193103785Sjeff int needwakeup; 194103785Sjeff struct alq *alq; 195103785Sjeff 196103995Sjeff ald_thread = FIRST_THREAD_IN_PROC(ald_proc); 197103995Sjeff 198250951Slstewart alq_eventhandler_tag = EVENTHANDLER_REGISTER(shutdown_pre_sync, 199250951Slstewart ald_shutdown, NULL, SHUTDOWN_PRI_FIRST); 200103785Sjeff 201103785Sjeff ALD_LOCK(); 202103785Sjeff 203103785Sjeff for (;;) { 204205959Slstewart while ((alq = LIST_FIRST(&ald_active)) == NULL && 205205959Slstewart !ald_shutingdown) 206206027Slstewart mtx_sleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0); 207103785Sjeff 208205959Slstewart /* Don't shutdown until all active ALQs are flushed. */ 209205959Slstewart if (ald_shutingdown && alq == NULL) { 210205959Slstewart ALD_UNLOCK(); 211205959Slstewart break; 212205959Slstewart } 213205959Slstewart 214103785Sjeff ALQ_LOCK(alq); 215103785Sjeff ald_deactivate(alq); 216103785Sjeff ALD_UNLOCK(); 217103785Sjeff needwakeup = alq_doio(alq); 218103785Sjeff ALQ_UNLOCK(alq); 219103785Sjeff if (needwakeup) 220207223Slstewart wakeup_one(alq); 221103785Sjeff ALD_LOCK(); 222103785Sjeff } 223205959Slstewart 224205959Slstewart kproc_exit(0); 225103785Sjeff} 226103785Sjeff 227103785Sjeffstatic void 228103785Sjeffald_shutdown(void *arg, int howto) 229103785Sjeff{ 230103785Sjeff struct alq *alq; 231103785Sjeff 232103785Sjeff ALD_LOCK(); 233205959Slstewart 234205959Slstewart /* Ensure no new queues can be created. */ 235103785Sjeff ald_shutingdown = 1; 236103785Sjeff 237205959Slstewart /* Shutdown all ALQs prior to terminating the ald_daemon. */ 238103785Sjeff while ((alq = LIST_FIRST(&ald_queues)) != NULL) { 239103785Sjeff LIST_REMOVE(alq, aq_link); 240103785Sjeff ALD_UNLOCK(); 241103785Sjeff alq_shutdown(alq); 242103785Sjeff ALD_LOCK(); 243103785Sjeff } 244205959Slstewart 245205959Slstewart /* At this point, all ALQs are flushed and shutdown. */ 246205959Slstewart 247205959Slstewart /* 248205959Slstewart * Wake ald_daemon so that it exits. It won't be able to do 249206027Slstewart * anything until we mtx_sleep because we hold the ald_mtx. 250205959Slstewart */ 251205959Slstewart wakeup(&ald_active); 252205959Slstewart 253205959Slstewart /* Wait for ald_daemon to exit. */ 254206027Slstewart mtx_sleep(ald_proc, &ald_mtx, PWAIT, "aldslp", 0); 255205959Slstewart 256103785Sjeff ALD_UNLOCK(); 257103785Sjeff} 258103785Sjeff 259103785Sjeffstatic void 260103785Sjeffalq_shutdown(struct alq *alq) 261103785Sjeff{ 262103785Sjeff ALQ_LOCK(alq); 263103785Sjeff 264103785Sjeff /* Stop any new writers. */ 265103785Sjeff alq->aq_flags |= AQ_SHUTDOWN; 266103785Sjeff 267207223Slstewart /* 268207223Slstewart * If the ALQ isn't active but has unwritten data (possible if 269207223Slstewart * the ALQ_NOACTIVATE flag has been used), explicitly activate the 270207223Slstewart * ALQ here so that the pending data gets flushed by the ald_daemon. 271207223Slstewart */ 272207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && HAS_PENDING_DATA(alq)) { 273207223Slstewart alq->aq_flags |= AQ_ACTIVE; 274207223Slstewart ALQ_UNLOCK(alq); 275207223Slstewart ALD_LOCK(); 276207223Slstewart ald_activate(alq); 277207223Slstewart ALD_UNLOCK(); 278207223Slstewart ALQ_LOCK(alq); 279207223Slstewart } 280207223Slstewart 281103785Sjeff /* Drain IO */ 282206028Slstewart while (alq->aq_flags & AQ_ACTIVE) { 283103785Sjeff alq->aq_flags |= AQ_WANTED; 284180196Srdivacky msleep_spin(alq, &alq->aq_mtx, "aldclose", 0); 285103785Sjeff } 286103785Sjeff ALQ_UNLOCK(alq); 287103785Sjeff 288103995Sjeff vn_close(alq->aq_vp, FWRITE, alq->aq_cred, 289103830Sjeff curthread); 290103830Sjeff crfree(alq->aq_cred); 291103785Sjeff} 292103785Sjeff 293206026Slstewartvoid 294206026Slstewartalq_destroy(struct alq *alq) 295206026Slstewart{ 296206026Slstewart /* Drain all pending IO. */ 297206026Slstewart alq_shutdown(alq); 298206026Slstewart 299206026Slstewart mtx_destroy(&alq->aq_mtx); 300206026Slstewart free(alq->aq_entbuf, M_ALD); 301206026Slstewart free(alq, M_ALD); 302206026Slstewart} 303206026Slstewart 304103785Sjeff/* 305103785Sjeff * Flush all pending data to disk. This operation will block. 306103785Sjeff */ 307103785Sjeffstatic int 308103785Sjeffalq_doio(struct alq *alq) 309103785Sjeff{ 310103785Sjeff struct thread *td; 311103785Sjeff struct mount *mp; 312103785Sjeff struct vnode *vp; 313103785Sjeff struct uio auio; 314103785Sjeff struct iovec aiov[2]; 315103785Sjeff int totlen; 316103785Sjeff int iov; 317207223Slstewart int wrapearly; 318103785Sjeff 319207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 320207223Slstewart 321103785Sjeff vp = alq->aq_vp; 322103785Sjeff td = curthread; 323103785Sjeff totlen = 0; 324207223Slstewart iov = 1; 325207223Slstewart wrapearly = alq->aq_wrapearly; 326103785Sjeff 327103785Sjeff bzero(&aiov, sizeof(aiov)); 328103785Sjeff bzero(&auio, sizeof(auio)); 329103785Sjeff 330207223Slstewart /* Start the write from the location of our buffer tail pointer. */ 331207223Slstewart aiov[0].iov_base = alq->aq_entbuf + alq->aq_writetail; 332103785Sjeff 333207223Slstewart if (alq->aq_writetail < alq->aq_writehead) { 334207223Slstewart /* Buffer not wrapped. */ 335207223Slstewart totlen = aiov[0].iov_len = alq->aq_writehead - alq->aq_writetail; 336207223Slstewart } else if (alq->aq_writehead == 0) { 337207223Slstewart /* Buffer not wrapped (special case to avoid an empty iov). */ 338207223Slstewart totlen = aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - 339207223Slstewart wrapearly; 340207223Slstewart } else { 341207223Slstewart /* 342207223Slstewart * Buffer wrapped, requires 2 aiov entries: 343207223Slstewart * - first is from writetail to end of buffer 344207223Slstewart * - second is from start of buffer to writehead 345207223Slstewart */ 346207223Slstewart aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - 347207223Slstewart wrapearly; 348207223Slstewart iov++; 349207223Slstewart aiov[1].iov_base = alq->aq_entbuf; 350207223Slstewart aiov[1].iov_len = alq->aq_writehead; 351207223Slstewart totlen = aiov[0].iov_len + aiov[1].iov_len; 352207223Slstewart } 353207223Slstewart 354103785Sjeff alq->aq_flags |= AQ_FLUSHING; 355103785Sjeff ALQ_UNLOCK(alq); 356103785Sjeff 357103785Sjeff auio.uio_iov = &aiov[0]; 358103785Sjeff auio.uio_offset = 0; 359103785Sjeff auio.uio_segflg = UIO_SYSSPACE; 360103785Sjeff auio.uio_rw = UIO_WRITE; 361207223Slstewart auio.uio_iovcnt = iov; 362103785Sjeff auio.uio_resid = totlen; 363103785Sjeff auio.uio_td = td; 364103785Sjeff 365103785Sjeff /* 366103785Sjeff * Do all of the junk required to write now. 367103785Sjeff */ 368103785Sjeff vn_start_write(vp, &mp, V_WAIT); 369175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 370121508Srwatson /* 371121508Srwatson * XXX: VOP_WRITE error checks are ignored. 372121508Srwatson */ 373121508Srwatson#ifdef MAC 374172930Srwatson if (mac_vnode_check_write(alq->aq_cred, NOCRED, vp) == 0) 375121508Srwatson#endif 376121508Srwatson VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred); 377175294Sattilio VOP_UNLOCK(vp, 0); 378103785Sjeff vn_finished_write(mp); 379103785Sjeff 380103785Sjeff ALQ_LOCK(alq); 381103785Sjeff alq->aq_flags &= ~AQ_FLUSHING; 382103785Sjeff 383207223Slstewart /* Adjust writetail as required, taking into account wrapping. */ 384207223Slstewart alq->aq_writetail = (alq->aq_writetail + totlen + wrapearly) % 385207223Slstewart alq->aq_buflen; 386207223Slstewart alq->aq_freebytes += totlen + wrapearly; 387103785Sjeff 388207223Slstewart /* 389207223Slstewart * If we just flushed part of the buffer which wrapped, reset the 390207223Slstewart * wrapearly indicator. 391207223Slstewart */ 392207223Slstewart if (wrapearly) 393207223Slstewart alq->aq_wrapearly = 0; 394207223Slstewart 395207223Slstewart /* 396207223Slstewart * If we just flushed the buffer completely, reset indexes to 0 to 397207223Slstewart * minimise buffer wraps. 398207223Slstewart * This is also required to ensure alq_getn() can't wedge itself. 399207223Slstewart */ 400207223Slstewart if (!HAS_PENDING_DATA(alq)) 401207223Slstewart alq->aq_writehead = alq->aq_writetail = 0; 402207223Slstewart 403207223Slstewart KASSERT((alq->aq_writetail >= 0 && alq->aq_writetail < alq->aq_buflen), 404207223Slstewart ("%s: aq_writetail < 0 || aq_writetail >= aq_buflen", __func__)); 405207223Slstewart 406103785Sjeff if (alq->aq_flags & AQ_WANTED) { 407103785Sjeff alq->aq_flags &= ~AQ_WANTED; 408103785Sjeff return (1); 409103785Sjeff } 410103785Sjeff 411103785Sjeff return(0); 412103785Sjeff} 413103785Sjeff 414103785Sjeffstatic struct kproc_desc ald_kp = { 415103785Sjeff "ALQ Daemon", 416103785Sjeff ald_daemon, 417103995Sjeff &ald_proc 418103785Sjeff}; 419103785Sjeff 420177253SrwatsonSYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp); 421177253SrwatsonSYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL); 422103785Sjeff 423103785Sjeff 424103785Sjeff/* User visible queue functions */ 425103785Sjeff 426103785Sjeff/* 427103785Sjeff * Create the queue data structure, allocate the buffer, and open the file. 428103785Sjeff */ 429207223Slstewart 430103785Sjeffint 431207223Slstewartalq_open_flags(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 432207223Slstewart int size, int flags) 433103785Sjeff{ 434103785Sjeff struct thread *td; 435103785Sjeff struct nameidata nd; 436103785Sjeff struct alq *alq; 437207223Slstewart int oflags; 438103785Sjeff int error; 439103785Sjeff 440207223Slstewart KASSERT((size > 0), ("%s: size <= 0", __func__)); 441207223Slstewart 442103785Sjeff *alqp = NULL; 443103785Sjeff td = curthread; 444103785Sjeff 445241896Skib NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td); 446207223Slstewart oflags = FWRITE | O_NOFOLLOW | O_CREAT; 447103785Sjeff 448207223Slstewart error = vn_open_cred(&nd, &oflags, cmode, 0, cred, NULL); 449103785Sjeff if (error) 450103785Sjeff return (error); 451154902Spjd 452154903Spjd NDFREE(&nd, NDF_ONLY_PNBUF); 453103785Sjeff /* We just unlock so we hold a reference */ 454175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 455103785Sjeff 456111119Simp alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO); 457103785Sjeff alq->aq_vp = nd.ni_vp; 458116697Srwatson alq->aq_cred = crhold(cred); 459103785Sjeff 460103785Sjeff mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET); 461103785Sjeff 462207223Slstewart alq->aq_buflen = size; 463207223Slstewart alq->aq_entmax = 0; 464207223Slstewart alq->aq_entlen = 0; 465103785Sjeff 466207223Slstewart alq->aq_freebytes = alq->aq_buflen; 467207223Slstewart alq->aq_entbuf = malloc(alq->aq_buflen, M_ALD, M_WAITOK|M_ZERO); 468207223Slstewart alq->aq_writehead = alq->aq_writetail = 0; 469207223Slstewart if (flags & ALQ_ORDERED) 470207223Slstewart alq->aq_flags |= AQ_ORDERED; 471103785Sjeff 472206026Slstewart if ((error = ald_add(alq)) != 0) { 473206026Slstewart alq_destroy(alq); 474103785Sjeff return (error); 475206026Slstewart } 476206026Slstewart 477103785Sjeff *alqp = alq; 478103785Sjeff 479103785Sjeff return (0); 480103785Sjeff} 481103785Sjeff 482207223Slstewartint 483207223Slstewartalq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 484207223Slstewart int size, int count) 485207223Slstewart{ 486207223Slstewart int ret; 487207223Slstewart 488207223Slstewart KASSERT((count >= 0), ("%s: count < 0", __func__)); 489207223Slstewart 490207223Slstewart if (count > 0) { 491264366Sdchagin if ((ret = alq_open_flags(alqp, file, cred, cmode, 492264366Sdchagin size*count, 0)) == 0) { 493264366Sdchagin (*alqp)->aq_flags |= AQ_LEGACY; 494264366Sdchagin (*alqp)->aq_entmax = count; 495264366Sdchagin (*alqp)->aq_entlen = size; 496264366Sdchagin } 497207223Slstewart } else 498207223Slstewart ret = alq_open_flags(alqp, file, cred, cmode, size, 0); 499207223Slstewart 500207223Slstewart return (ret); 501207223Slstewart} 502207223Slstewart 503207223Slstewart 504103785Sjeff/* 505103785Sjeff * Copy a new entry into the queue. If the operation would block either 506103785Sjeff * wait or return an error depending on the value of waitok. 507103785Sjeff */ 508103785Sjeffint 509207223Slstewartalq_writen(struct alq *alq, void *data, int len, int flags) 510103785Sjeff{ 511207223Slstewart int activate, copy, ret; 512207223Slstewart void *waitchan; 513103785Sjeff 514207223Slstewart KASSERT((len > 0 && len <= alq->aq_buflen), 515207223Slstewart ("%s: len <= 0 || len > aq_buflen", __func__)); 516207223Slstewart 517207223Slstewart activate = ret = 0; 518207223Slstewart copy = len; 519207223Slstewart waitchan = NULL; 520207223Slstewart 521207223Slstewart ALQ_LOCK(alq); 522207223Slstewart 523207223Slstewart /* 524207223Slstewart * Fail to perform the write and return EWOULDBLOCK if: 525207223Slstewart * - The message is larger than our underlying buffer. 526207223Slstewart * - The ALQ is being shutdown. 527207223Slstewart * - There is insufficient free space in our underlying buffer 528207223Slstewart * to accept the message and the user can't wait for space. 529207223Slstewart * - There is insufficient free space in our underlying buffer 530207223Slstewart * to accept the message and the alq is inactive due to prior 531207223Slstewart * use of the ALQ_NOACTIVATE flag (which would lead to deadlock). 532207223Slstewart */ 533207223Slstewart if (len > alq->aq_buflen || 534207223Slstewart alq->aq_flags & AQ_SHUTDOWN || 535207223Slstewart (((flags & ALQ_NOWAIT) || (!(alq->aq_flags & AQ_ACTIVE) && 536207223Slstewart HAS_PENDING_DATA(alq))) && alq->aq_freebytes < len)) { 537207223Slstewart ALQ_UNLOCK(alq); 538103785Sjeff return (EWOULDBLOCK); 539207223Slstewart } 540103785Sjeff 541207223Slstewart /* 542207223Slstewart * If we want ordered writes and there is already at least one thread 543207223Slstewart * waiting for resources to become available, sleep until we're woken. 544207223Slstewart */ 545207223Slstewart if (alq->aq_flags & AQ_ORDERED && alq->aq_waiters > 0) { 546207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 547207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 548207223Slstewart alq->aq_waiters++; 549207223Slstewart msleep_spin(&alq->aq_waiters, &alq->aq_mtx, "alqwnord", 0); 550207223Slstewart alq->aq_waiters--; 551207223Slstewart } 552103785Sjeff 553207223Slstewart /* 554207223Slstewart * (ALQ_WAITOK && aq_freebytes < len) or aq_freebytes >= len, either 555207223Slstewart * enter while loop and sleep until we have enough free bytes (former) 556207223Slstewart * or skip (latter). If AQ_ORDERED is set, only 1 thread at a time will 557207223Slstewart * be in this loop. Otherwise, multiple threads may be sleeping here 558207223Slstewart * competing for ALQ resources. 559207223Slstewart */ 560207223Slstewart while (alq->aq_freebytes < len && !(alq->aq_flags & AQ_SHUTDOWN)) { 561207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 562207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 563207223Slstewart alq->aq_flags |= AQ_WANTED; 564207223Slstewart alq->aq_waiters++; 565207223Slstewart if (waitchan) 566207223Slstewart wakeup(waitchan); 567207223Slstewart msleep_spin(alq, &alq->aq_mtx, "alqwnres", 0); 568207223Slstewart alq->aq_waiters--; 569207223Slstewart 570207223Slstewart /* 571207223Slstewart * If we're the first thread to wake after an AQ_WANTED wakeup 572207223Slstewart * but there isn't enough free space for us, we're going to loop 573207223Slstewart * and sleep again. If there are other threads waiting in this 574207223Slstewart * loop, schedule a wakeup so that they can see if the space 575207223Slstewart * they require is available. 576207223Slstewart */ 577207223Slstewart if (alq->aq_waiters > 0 && !(alq->aq_flags & AQ_ORDERED) && 578207223Slstewart alq->aq_freebytes < len && !(alq->aq_flags & AQ_WANTED)) 579207223Slstewart waitchan = alq; 580207223Slstewart else 581207223Slstewart waitchan = NULL; 582207223Slstewart } 583207223Slstewart 584207223Slstewart /* 585207223Slstewart * If there are waiters, we need to signal the waiting threads after we 586207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 587207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 588207223Slstewart * are not allowed to concurrently compete for resources in the above 589207223Slstewart * while loop, so we use a different wait channel in this case. 590207223Slstewart */ 591207223Slstewart if (alq->aq_waiters > 0) { 592207223Slstewart if (alq->aq_flags & AQ_ORDERED) 593207223Slstewart waitchan = &alq->aq_waiters; 594207223Slstewart else 595207223Slstewart waitchan = alq; 596207223Slstewart } else 597207223Slstewart waitchan = NULL; 598207223Slstewart 599207223Slstewart /* Bail if we're shutting down. */ 600207223Slstewart if (alq->aq_flags & AQ_SHUTDOWN) { 601207223Slstewart ret = EWOULDBLOCK; 602207223Slstewart goto unlock; 603207223Slstewart } 604207223Slstewart 605207223Slstewart /* 606207223Slstewart * If we need to wrap the buffer to accommodate the write, 607207223Slstewart * we'll need 2 calls to bcopy. 608207223Slstewart */ 609207223Slstewart if ((alq->aq_buflen - alq->aq_writehead) < len) 610207223Slstewart copy = alq->aq_buflen - alq->aq_writehead; 611207223Slstewart 612207223Slstewart /* Copy message (or part thereof if wrap required) to the buffer. */ 613207223Slstewart bcopy(data, alq->aq_entbuf + alq->aq_writehead, copy); 614207223Slstewart alq->aq_writehead += copy; 615207223Slstewart 616207223Slstewart if (alq->aq_writehead >= alq->aq_buflen) { 617207223Slstewart KASSERT((alq->aq_writehead == alq->aq_buflen), 618207223Slstewart ("%s: alq->aq_writehead (%d) > alq->aq_buflen (%d)", 619207223Slstewart __func__, 620207223Slstewart alq->aq_writehead, 621207223Slstewart alq->aq_buflen)); 622207223Slstewart alq->aq_writehead = 0; 623207223Slstewart } 624207223Slstewart 625207223Slstewart if (copy != len) { 626207223Slstewart /* 627207223Slstewart * Wrap the buffer by copying the remainder of our message 628207223Slstewart * to the start of the buffer and resetting aq_writehead. 629207223Slstewart */ 630207223Slstewart bcopy(((uint8_t *)data)+copy, alq->aq_entbuf, len - copy); 631207223Slstewart alq->aq_writehead = len - copy; 632207223Slstewart } 633207223Slstewart 634207223Slstewart KASSERT((alq->aq_writehead >= 0 && alq->aq_writehead < alq->aq_buflen), 635207223Slstewart ("%s: aq_writehead < 0 || aq_writehead >= aq_buflen", __func__)); 636207223Slstewart 637207223Slstewart alq->aq_freebytes -= len; 638207223Slstewart 639207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && !(flags & ALQ_NOACTIVATE)) { 640207223Slstewart alq->aq_flags |= AQ_ACTIVE; 641207223Slstewart activate = 1; 642207223Slstewart } 643207223Slstewart 644207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 645207223Slstewart 646207223Slstewartunlock: 647207223Slstewart ALQ_UNLOCK(alq); 648207223Slstewart 649207223Slstewart if (activate) { 650207223Slstewart ALD_LOCK(); 651207223Slstewart ald_activate(alq); 652207223Slstewart ALD_UNLOCK(); 653207223Slstewart } 654207223Slstewart 655207223Slstewart /* NB: We rely on wakeup_one waking threads in a FIFO manner. */ 656207223Slstewart if (waitchan != NULL) 657207223Slstewart wakeup_one(waitchan); 658207223Slstewart 659207223Slstewart return (ret); 660103785Sjeff} 661103785Sjeff 662207223Slstewartint 663207223Slstewartalq_write(struct alq *alq, void *data, int flags) 664207223Slstewart{ 665207223Slstewart /* Should only be called in fixed length message (legacy) mode. */ 666207223Slstewart KASSERT((alq->aq_flags & AQ_LEGACY), 667207223Slstewart ("%s: fixed length write on variable length queue", __func__)); 668207223Slstewart return (alq_writen(alq, data, alq->aq_entlen, flags)); 669207223Slstewart} 670207223Slstewart 671207223Slstewart/* 672207223Slstewart * Retrieve a pointer for the ALQ to write directly into, avoiding bcopy. 673207223Slstewart */ 674103785Sjeffstruct ale * 675207223Slstewartalq_getn(struct alq *alq, int len, int flags) 676103785Sjeff{ 677207223Slstewart int contigbytes; 678207223Slstewart void *waitchan; 679103785Sjeff 680207223Slstewart KASSERT((len > 0 && len <= alq->aq_buflen), 681207223Slstewart ("%s: len <= 0 || len > alq->aq_buflen", __func__)); 682103785Sjeff 683207223Slstewart waitchan = NULL; 684207223Slstewart 685103785Sjeff ALQ_LOCK(alq); 686103785Sjeff 687207223Slstewart /* 688207223Slstewart * Determine the number of free contiguous bytes. 689207223Slstewart * We ensure elsewhere that if aq_writehead == aq_writetail because 690207223Slstewart * the buffer is empty, they will both be set to 0 and therefore 691207223Slstewart * aq_freebytes == aq_buflen and is fully contiguous. 692207223Slstewart * If they are equal and the buffer is not empty, aq_freebytes will 693207223Slstewart * be 0 indicating the buffer is full. 694207223Slstewart */ 695207223Slstewart if (alq->aq_writehead <= alq->aq_writetail) 696207223Slstewart contigbytes = alq->aq_freebytes; 697207223Slstewart else { 698207223Slstewart contigbytes = alq->aq_buflen - alq->aq_writehead; 699207223Slstewart 700207223Slstewart if (contigbytes < len) { 701207223Slstewart /* 702207223Slstewart * Insufficient space at end of buffer to handle a 703207223Slstewart * contiguous write. Wrap early if there's space at 704207223Slstewart * the beginning. This will leave a hole at the end 705207223Slstewart * of the buffer which we will have to skip over when 706207223Slstewart * flushing the buffer to disk. 707207223Slstewart */ 708207223Slstewart if (alq->aq_writetail >= len || flags & ALQ_WAITOK) { 709207223Slstewart /* Keep track of # bytes left blank. */ 710207223Slstewart alq->aq_wrapearly = contigbytes; 711207223Slstewart /* Do the wrap and adjust counters. */ 712207223Slstewart contigbytes = alq->aq_freebytes = 713207223Slstewart alq->aq_writetail; 714207223Slstewart alq->aq_writehead = 0; 715207223Slstewart } 716207223Slstewart } 717207223Slstewart } 718207223Slstewart 719207223Slstewart /* 720207223Slstewart * Return a NULL ALE if: 721207223Slstewart * - The message is larger than our underlying buffer. 722207223Slstewart * - The ALQ is being shutdown. 723207223Slstewart * - There is insufficient free space in our underlying buffer 724207223Slstewart * to accept the message and the user can't wait for space. 725207223Slstewart * - There is insufficient free space in our underlying buffer 726207223Slstewart * to accept the message and the alq is inactive due to prior 727207223Slstewart * use of the ALQ_NOACTIVATE flag (which would lead to deadlock). 728207223Slstewart */ 729207223Slstewart if (len > alq->aq_buflen || 730207223Slstewart alq->aq_flags & AQ_SHUTDOWN || 731207223Slstewart (((flags & ALQ_NOWAIT) || (!(alq->aq_flags & AQ_ACTIVE) && 732207223Slstewart HAS_PENDING_DATA(alq))) && contigbytes < len)) { 733207223Slstewart ALQ_UNLOCK(alq); 734207223Slstewart return (NULL); 735207223Slstewart } 736207223Slstewart 737207223Slstewart /* 738207223Slstewart * If we want ordered writes and there is already at least one thread 739207223Slstewart * waiting for resources to become available, sleep until we're woken. 740207223Slstewart */ 741207223Slstewart if (alq->aq_flags & AQ_ORDERED && alq->aq_waiters > 0) { 742207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 743207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 744207223Slstewart alq->aq_waiters++; 745207223Slstewart msleep_spin(&alq->aq_waiters, &alq->aq_mtx, "alqgnord", 0); 746207223Slstewart alq->aq_waiters--; 747207223Slstewart } 748207223Slstewart 749207223Slstewart /* 750207223Slstewart * (ALQ_WAITOK && contigbytes < len) or contigbytes >= len, either enter 751207223Slstewart * while loop and sleep until we have enough contiguous free bytes 752207223Slstewart * (former) or skip (latter). If AQ_ORDERED is set, only 1 thread at a 753207223Slstewart * time will be in this loop. Otherwise, multiple threads may be 754207223Slstewart * sleeping here competing for ALQ resources. 755207223Slstewart */ 756207223Slstewart while (contigbytes < len && !(alq->aq_flags & AQ_SHUTDOWN)) { 757207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 758207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 759103785Sjeff alq->aq_flags |= AQ_WANTED; 760207223Slstewart alq->aq_waiters++; 761207223Slstewart if (waitchan) 762207223Slstewart wakeup(waitchan); 763207223Slstewart msleep_spin(alq, &alq->aq_mtx, "alqgnres", 0); 764207223Slstewart alq->aq_waiters--; 765207223Slstewart 766207223Slstewart if (alq->aq_writehead <= alq->aq_writetail) 767207223Slstewart contigbytes = alq->aq_freebytes; 768207223Slstewart else 769207223Slstewart contigbytes = alq->aq_buflen - alq->aq_writehead; 770207223Slstewart 771207223Slstewart /* 772207223Slstewart * If we're the first thread to wake after an AQ_WANTED wakeup 773207223Slstewart * but there isn't enough free space for us, we're going to loop 774207223Slstewart * and sleep again. If there are other threads waiting in this 775207223Slstewart * loop, schedule a wakeup so that they can see if the space 776207223Slstewart * they require is available. 777207223Slstewart */ 778207223Slstewart if (alq->aq_waiters > 0 && !(alq->aq_flags & AQ_ORDERED) && 779207223Slstewart contigbytes < len && !(alq->aq_flags & AQ_WANTED)) 780207223Slstewart waitchan = alq; 781207223Slstewart else 782207223Slstewart waitchan = NULL; 783103785Sjeff } 784103785Sjeff 785207223Slstewart /* 786207223Slstewart * If there are waiters, we need to signal the waiting threads after we 787207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 788207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 789207223Slstewart * are not allowed to concurrently compete for resources in the above 790207223Slstewart * while loop, so we use a different wait channel in this case. 791207223Slstewart */ 792207223Slstewart if (alq->aq_waiters > 0) { 793207223Slstewart if (alq->aq_flags & AQ_ORDERED) 794207223Slstewart waitchan = &alq->aq_waiters; 795115308Sjeff else 796207223Slstewart waitchan = alq; 797103785Sjeff } else 798207223Slstewart waitchan = NULL; 799207223Slstewart 800207223Slstewart /* Bail if we're shutting down. */ 801207223Slstewart if (alq->aq_flags & AQ_SHUTDOWN) { 802103785Sjeff ALQ_UNLOCK(alq); 803207223Slstewart if (waitchan != NULL) 804207223Slstewart wakeup_one(waitchan); 805207223Slstewart return (NULL); 806207223Slstewart } 807103785Sjeff 808207223Slstewart /* 809207223Slstewart * If we are here, we have a contiguous number of bytes >= len 810207223Slstewart * available in our buffer starting at aq_writehead. 811207223Slstewart */ 812207223Slstewart alq->aq_getpost.ae_data = alq->aq_entbuf + alq->aq_writehead; 813207223Slstewart alq->aq_getpost.ae_bytesused = len; 814103785Sjeff 815207223Slstewart return (&alq->aq_getpost); 816103785Sjeff} 817103785Sjeff 818207223Slstewartstruct ale * 819207223Slstewartalq_get(struct alq *alq, int flags) 820207223Slstewart{ 821207223Slstewart /* Should only be called in fixed length message (legacy) mode. */ 822207223Slstewart KASSERT((alq->aq_flags & AQ_LEGACY), 823207223Slstewart ("%s: fixed length get on variable length queue", __func__)); 824207223Slstewart return (alq_getn(alq, alq->aq_entlen, flags)); 825207223Slstewart} 826207223Slstewart 827103785Sjeffvoid 828207223Slstewartalq_post_flags(struct alq *alq, struct ale *ale, int flags) 829103785Sjeff{ 830103785Sjeff int activate; 831207223Slstewart void *waitchan; 832103785Sjeff 833207223Slstewart activate = 0; 834103785Sjeff 835207223Slstewart if (ale->ae_bytesused > 0) { 836207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && 837207223Slstewart !(flags & ALQ_NOACTIVATE)) { 838207223Slstewart alq->aq_flags |= AQ_ACTIVE; 839207223Slstewart activate = 1; 840207223Slstewart } 841103785Sjeff 842207223Slstewart alq->aq_writehead += ale->ae_bytesused; 843207223Slstewart alq->aq_freebytes -= ale->ae_bytesused; 844207223Slstewart 845207223Slstewart /* Wrap aq_writehead if we filled to the end of the buffer. */ 846207223Slstewart if (alq->aq_writehead == alq->aq_buflen) 847207223Slstewart alq->aq_writehead = 0; 848207223Slstewart 849207223Slstewart KASSERT((alq->aq_writehead >= 0 && 850207223Slstewart alq->aq_writehead < alq->aq_buflen), 851207223Slstewart ("%s: aq_writehead < 0 || aq_writehead >= aq_buflen", 852207223Slstewart __func__)); 853207223Slstewart 854207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 855207223Slstewart } 856207223Slstewart 857207223Slstewart /* 858207223Slstewart * If there are waiters, we need to signal the waiting threads after we 859207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 860207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 861207223Slstewart * are not allowed to concurrently compete for resources in the 862207223Slstewart * alq_getn() while loop, so we use a different wait channel in this case. 863207223Slstewart */ 864207223Slstewart if (alq->aq_waiters > 0) { 865207223Slstewart if (alq->aq_flags & AQ_ORDERED) 866207223Slstewart waitchan = &alq->aq_waiters; 867207223Slstewart else 868207223Slstewart waitchan = alq; 869103785Sjeff } else 870207223Slstewart waitchan = NULL; 871103785Sjeff 872103785Sjeff ALQ_UNLOCK(alq); 873207223Slstewart 874103785Sjeff if (activate) { 875103785Sjeff ALD_LOCK(); 876103785Sjeff ald_activate(alq); 877103785Sjeff ALD_UNLOCK(); 878103785Sjeff } 879207223Slstewart 880207223Slstewart /* NB: We rely on wakeup_one waking threads in a FIFO manner. */ 881207223Slstewart if (waitchan != NULL) 882207223Slstewart wakeup_one(waitchan); 883103785Sjeff} 884103785Sjeff 885103785Sjeffvoid 886103785Sjeffalq_flush(struct alq *alq) 887103785Sjeff{ 888103785Sjeff int needwakeup = 0; 889103785Sjeff 890103785Sjeff ALD_LOCK(); 891103785Sjeff ALQ_LOCK(alq); 892207223Slstewart 893207223Slstewart /* 894207223Slstewart * Pull the lever iff there is data to flush and we're 895207223Slstewart * not already in the middle of a flush operation. 896207223Slstewart */ 897207223Slstewart if (HAS_PENDING_DATA(alq) && !(alq->aq_flags & AQ_FLUSHING)) { 898207223Slstewart if (alq->aq_flags & AQ_ACTIVE) 899207223Slstewart ald_deactivate(alq); 900207223Slstewart 901103785Sjeff ALD_UNLOCK(); 902103785Sjeff needwakeup = alq_doio(alq); 903103785Sjeff } else 904103785Sjeff ALD_UNLOCK(); 905207223Slstewart 906103785Sjeff ALQ_UNLOCK(alq); 907103785Sjeff 908103785Sjeff if (needwakeup) 909207223Slstewart wakeup_one(alq); 910103785Sjeff} 911103785Sjeff 912103785Sjeff/* 913103785Sjeff * Flush remaining data, close the file and free all resources. 914103785Sjeff */ 915103785Sjeffvoid 916103785Sjeffalq_close(struct alq *alq) 917103785Sjeff{ 918206026Slstewart /* Only flush and destroy alq if not already shutting down. */ 919206026Slstewart if (ald_rem(alq) == 0) 920206026Slstewart alq_destroy(alq); 921103785Sjeff} 922205959Slstewart 923205959Slstewartstatic int 924205959Slstewartalq_load_handler(module_t mod, int what, void *arg) 925205959Slstewart{ 926205959Slstewart int ret; 927205959Slstewart 928205959Slstewart ret = 0; 929205959Slstewart 930205959Slstewart switch (what) { 931205959Slstewart case MOD_LOAD: 932205959Slstewart case MOD_SHUTDOWN: 933205959Slstewart break; 934205959Slstewart 935205959Slstewart case MOD_QUIESCE: 936205959Slstewart ALD_LOCK(); 937205959Slstewart /* Only allow unload if there are no open queues. */ 938205959Slstewart if (LIST_FIRST(&ald_queues) == NULL) { 939205959Slstewart ald_shutingdown = 1; 940205959Slstewart ALD_UNLOCK(); 941251838Slstewart EVENTHANDLER_DEREGISTER(shutdown_pre_sync, 942251838Slstewart alq_eventhandler_tag); 943205959Slstewart ald_shutdown(NULL, 0); 944205959Slstewart mtx_destroy(&ald_mtx); 945205959Slstewart } else { 946205959Slstewart ALD_UNLOCK(); 947205959Slstewart ret = EBUSY; 948205959Slstewart } 949205959Slstewart break; 950205959Slstewart 951205959Slstewart case MOD_UNLOAD: 952205959Slstewart /* If MOD_QUIESCE failed we must fail here too. */ 953205959Slstewart if (ald_shutingdown == 0) 954205959Slstewart ret = EBUSY; 955205959Slstewart break; 956205959Slstewart 957205959Slstewart default: 958205959Slstewart ret = EINVAL; 959205959Slstewart break; 960205959Slstewart } 961205959Slstewart 962205959Slstewart return (ret); 963205959Slstewart} 964205959Slstewart 965205959Slstewartstatic moduledata_t alq_mod = 966205959Slstewart{ 967205959Slstewart "alq", 968205959Slstewart alq_load_handler, 969205959Slstewart NULL 970205959Slstewart}; 971205959Slstewart 972205959SlstewartDECLARE_MODULE(alq, alq_mod, SI_SUB_SMP, SI_ORDER_ANY); 973205959SlstewartMODULE_VERSION(alq, 1); 974