kern_alq.c revision 241896
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: head/sys/kern/kern_alq.c 241896 2012-10-22 17:50:54Z kib $"); 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; 102103785Sjeff 103103785Sjeff#define ALD_LOCK() mtx_lock(&ald_mtx) 104103785Sjeff#define ALD_UNLOCK() mtx_unlock(&ald_mtx) 105103785Sjeff 106103785Sjeff/* Daemon functions */ 107103785Sjeffstatic int ald_add(struct alq *); 108103785Sjeffstatic int ald_rem(struct alq *); 109103785Sjeffstatic void ald_startup(void *); 110103785Sjeffstatic void ald_daemon(void); 111103785Sjeffstatic void ald_shutdown(void *, int); 112103785Sjeffstatic void ald_activate(struct alq *); 113103785Sjeffstatic void ald_deactivate(struct alq *); 114103785Sjeff 115103785Sjeff/* Internal queue functions */ 116103785Sjeffstatic void alq_shutdown(struct alq *); 117206026Slstewartstatic void alq_destroy(struct alq *); 118103785Sjeffstatic int alq_doio(struct alq *); 119103785Sjeff 120103785Sjeff 121103785Sjeff/* 122103785Sjeff * Add a new queue to the global list. Fail if we're shutting down. 123103785Sjeff */ 124103785Sjeffstatic int 125103785Sjeffald_add(struct alq *alq) 126103785Sjeff{ 127103785Sjeff int error; 128103785Sjeff 129103785Sjeff error = 0; 130103785Sjeff 131103785Sjeff ALD_LOCK(); 132103785Sjeff if (ald_shutingdown) { 133103785Sjeff error = EBUSY; 134103785Sjeff goto done; 135103785Sjeff } 136103785Sjeff LIST_INSERT_HEAD(&ald_queues, alq, aq_link); 137103785Sjeffdone: 138103785Sjeff ALD_UNLOCK(); 139103785Sjeff return (error); 140103785Sjeff} 141103785Sjeff 142103785Sjeff/* 143103785Sjeff * Remove a queue from the global list unless we're shutting down. If so, 144103785Sjeff * the ald will take care of cleaning up it's resources. 145103785Sjeff */ 146103785Sjeffstatic int 147103785Sjeffald_rem(struct alq *alq) 148103785Sjeff{ 149103785Sjeff int error; 150103785Sjeff 151103785Sjeff error = 0; 152103785Sjeff 153103785Sjeff ALD_LOCK(); 154103785Sjeff if (ald_shutingdown) { 155103785Sjeff error = EBUSY; 156103785Sjeff goto done; 157103785Sjeff } 158103785Sjeff LIST_REMOVE(alq, aq_link); 159103785Sjeffdone: 160103785Sjeff ALD_UNLOCK(); 161103785Sjeff return (error); 162103785Sjeff} 163103785Sjeff 164103785Sjeff/* 165103785Sjeff * Put a queue on the active list. This will schedule it for writing. 166103785Sjeff */ 167103785Sjeffstatic void 168103785Sjeffald_activate(struct alq *alq) 169103785Sjeff{ 170103785Sjeff LIST_INSERT_HEAD(&ald_active, alq, aq_act); 171103785Sjeff wakeup(&ald_active); 172103785Sjeff} 173103785Sjeff 174103785Sjeffstatic void 175103785Sjeffald_deactivate(struct alq *alq) 176103785Sjeff{ 177103785Sjeff LIST_REMOVE(alq, aq_act); 178103785Sjeff alq->aq_flags &= ~AQ_ACTIVE; 179103785Sjeff} 180103785Sjeff 181103785Sjeffstatic void 182103785Sjeffald_startup(void *unused) 183103785Sjeff{ 184103785Sjeff mtx_init(&ald_mtx, "ALDmtx", NULL, MTX_DEF|MTX_QUIET); 185103785Sjeff LIST_INIT(&ald_queues); 186103785Sjeff LIST_INIT(&ald_active); 187103785Sjeff} 188103785Sjeff 189103785Sjeffstatic void 190103785Sjeffald_daemon(void) 191103785Sjeff{ 192103785Sjeff int needwakeup; 193103785Sjeff struct alq *alq; 194103785Sjeff 195103995Sjeff ald_thread = FIRST_THREAD_IN_PROC(ald_proc); 196103995Sjeff 197103785Sjeff EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL, 198103785Sjeff SHUTDOWN_PRI_FIRST); 199103785Sjeff 200103785Sjeff ALD_LOCK(); 201103785Sjeff 202103785Sjeff for (;;) { 203205959Slstewart while ((alq = LIST_FIRST(&ald_active)) == NULL && 204205959Slstewart !ald_shutingdown) 205206027Slstewart mtx_sleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0); 206103785Sjeff 207205959Slstewart /* Don't shutdown until all active ALQs are flushed. */ 208205959Slstewart if (ald_shutingdown && alq == NULL) { 209205959Slstewart ALD_UNLOCK(); 210205959Slstewart break; 211205959Slstewart } 212205959Slstewart 213103785Sjeff ALQ_LOCK(alq); 214103785Sjeff ald_deactivate(alq); 215103785Sjeff ALD_UNLOCK(); 216103785Sjeff needwakeup = alq_doio(alq); 217103785Sjeff ALQ_UNLOCK(alq); 218103785Sjeff if (needwakeup) 219207223Slstewart wakeup_one(alq); 220103785Sjeff ALD_LOCK(); 221103785Sjeff } 222205959Slstewart 223205959Slstewart kproc_exit(0); 224103785Sjeff} 225103785Sjeff 226103785Sjeffstatic void 227103785Sjeffald_shutdown(void *arg, int howto) 228103785Sjeff{ 229103785Sjeff struct alq *alq; 230103785Sjeff 231103785Sjeff ALD_LOCK(); 232205959Slstewart 233205959Slstewart /* Ensure no new queues can be created. */ 234103785Sjeff ald_shutingdown = 1; 235103785Sjeff 236205959Slstewart /* Shutdown all ALQs prior to terminating the ald_daemon. */ 237103785Sjeff while ((alq = LIST_FIRST(&ald_queues)) != NULL) { 238103785Sjeff LIST_REMOVE(alq, aq_link); 239103785Sjeff ALD_UNLOCK(); 240103785Sjeff alq_shutdown(alq); 241103785Sjeff ALD_LOCK(); 242103785Sjeff } 243205959Slstewart 244205959Slstewart /* At this point, all ALQs are flushed and shutdown. */ 245205959Slstewart 246205959Slstewart /* 247205959Slstewart * Wake ald_daemon so that it exits. It won't be able to do 248206027Slstewart * anything until we mtx_sleep because we hold the ald_mtx. 249205959Slstewart */ 250205959Slstewart wakeup(&ald_active); 251205959Slstewart 252205959Slstewart /* Wait for ald_daemon to exit. */ 253206027Slstewart mtx_sleep(ald_proc, &ald_mtx, PWAIT, "aldslp", 0); 254205959Slstewart 255103785Sjeff ALD_UNLOCK(); 256103785Sjeff} 257103785Sjeff 258103785Sjeffstatic void 259103785Sjeffalq_shutdown(struct alq *alq) 260103785Sjeff{ 261103785Sjeff ALQ_LOCK(alq); 262103785Sjeff 263103785Sjeff /* Stop any new writers. */ 264103785Sjeff alq->aq_flags |= AQ_SHUTDOWN; 265103785Sjeff 266207223Slstewart /* 267207223Slstewart * If the ALQ isn't active but has unwritten data (possible if 268207223Slstewart * the ALQ_NOACTIVATE flag has been used), explicitly activate the 269207223Slstewart * ALQ here so that the pending data gets flushed by the ald_daemon. 270207223Slstewart */ 271207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && HAS_PENDING_DATA(alq)) { 272207223Slstewart alq->aq_flags |= AQ_ACTIVE; 273207223Slstewart ALQ_UNLOCK(alq); 274207223Slstewart ALD_LOCK(); 275207223Slstewart ald_activate(alq); 276207223Slstewart ALD_UNLOCK(); 277207223Slstewart ALQ_LOCK(alq); 278207223Slstewart } 279207223Slstewart 280103785Sjeff /* Drain IO */ 281206028Slstewart while (alq->aq_flags & AQ_ACTIVE) { 282103785Sjeff alq->aq_flags |= AQ_WANTED; 283180196Srdivacky msleep_spin(alq, &alq->aq_mtx, "aldclose", 0); 284103785Sjeff } 285103785Sjeff ALQ_UNLOCK(alq); 286103785Sjeff 287103995Sjeff vn_close(alq->aq_vp, FWRITE, alq->aq_cred, 288103830Sjeff curthread); 289103830Sjeff crfree(alq->aq_cred); 290103785Sjeff} 291103785Sjeff 292206026Slstewartvoid 293206026Slstewartalq_destroy(struct alq *alq) 294206026Slstewart{ 295206026Slstewart /* Drain all pending IO. */ 296206026Slstewart alq_shutdown(alq); 297206026Slstewart 298206026Slstewart mtx_destroy(&alq->aq_mtx); 299206026Slstewart free(alq->aq_entbuf, M_ALD); 300206026Slstewart free(alq, M_ALD); 301206026Slstewart} 302206026Slstewart 303103785Sjeff/* 304103785Sjeff * Flush all pending data to disk. This operation will block. 305103785Sjeff */ 306103785Sjeffstatic int 307103785Sjeffalq_doio(struct alq *alq) 308103785Sjeff{ 309103785Sjeff struct thread *td; 310103785Sjeff struct mount *mp; 311103785Sjeff struct vnode *vp; 312103785Sjeff struct uio auio; 313103785Sjeff struct iovec aiov[2]; 314103785Sjeff int totlen; 315103785Sjeff int iov; 316207223Slstewart int wrapearly; 317103785Sjeff 318207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 319207223Slstewart 320103785Sjeff vp = alq->aq_vp; 321103785Sjeff td = curthread; 322103785Sjeff totlen = 0; 323207223Slstewart iov = 1; 324207223Slstewart wrapearly = alq->aq_wrapearly; 325103785Sjeff 326103785Sjeff bzero(&aiov, sizeof(aiov)); 327103785Sjeff bzero(&auio, sizeof(auio)); 328103785Sjeff 329207223Slstewart /* Start the write from the location of our buffer tail pointer. */ 330207223Slstewart aiov[0].iov_base = alq->aq_entbuf + alq->aq_writetail; 331103785Sjeff 332207223Slstewart if (alq->aq_writetail < alq->aq_writehead) { 333207223Slstewart /* Buffer not wrapped. */ 334207223Slstewart totlen = aiov[0].iov_len = alq->aq_writehead - alq->aq_writetail; 335207223Slstewart } else if (alq->aq_writehead == 0) { 336207223Slstewart /* Buffer not wrapped (special case to avoid an empty iov). */ 337207223Slstewart totlen = aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - 338207223Slstewart wrapearly; 339207223Slstewart } else { 340207223Slstewart /* 341207223Slstewart * Buffer wrapped, requires 2 aiov entries: 342207223Slstewart * - first is from writetail to end of buffer 343207223Slstewart * - second is from start of buffer to writehead 344207223Slstewart */ 345207223Slstewart aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - 346207223Slstewart wrapearly; 347207223Slstewart iov++; 348207223Slstewart aiov[1].iov_base = alq->aq_entbuf; 349207223Slstewart aiov[1].iov_len = alq->aq_writehead; 350207223Slstewart totlen = aiov[0].iov_len + aiov[1].iov_len; 351207223Slstewart } 352207223Slstewart 353103785Sjeff alq->aq_flags |= AQ_FLUSHING; 354103785Sjeff ALQ_UNLOCK(alq); 355103785Sjeff 356103785Sjeff auio.uio_iov = &aiov[0]; 357103785Sjeff auio.uio_offset = 0; 358103785Sjeff auio.uio_segflg = UIO_SYSSPACE; 359103785Sjeff auio.uio_rw = UIO_WRITE; 360207223Slstewart auio.uio_iovcnt = iov; 361103785Sjeff auio.uio_resid = totlen; 362103785Sjeff auio.uio_td = td; 363103785Sjeff 364103785Sjeff /* 365103785Sjeff * Do all of the junk required to write now. 366103785Sjeff */ 367103785Sjeff vn_start_write(vp, &mp, V_WAIT); 368175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 369121508Srwatson /* 370121508Srwatson * XXX: VOP_WRITE error checks are ignored. 371121508Srwatson */ 372121508Srwatson#ifdef MAC 373172930Srwatson if (mac_vnode_check_write(alq->aq_cred, NOCRED, vp) == 0) 374121508Srwatson#endif 375121508Srwatson VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred); 376175294Sattilio VOP_UNLOCK(vp, 0); 377103785Sjeff vn_finished_write(mp); 378103785Sjeff 379103785Sjeff ALQ_LOCK(alq); 380103785Sjeff alq->aq_flags &= ~AQ_FLUSHING; 381103785Sjeff 382207223Slstewart /* Adjust writetail as required, taking into account wrapping. */ 383207223Slstewart alq->aq_writetail = (alq->aq_writetail + totlen + wrapearly) % 384207223Slstewart alq->aq_buflen; 385207223Slstewart alq->aq_freebytes += totlen + wrapearly; 386103785Sjeff 387207223Slstewart /* 388207223Slstewart * If we just flushed part of the buffer which wrapped, reset the 389207223Slstewart * wrapearly indicator. 390207223Slstewart */ 391207223Slstewart if (wrapearly) 392207223Slstewart alq->aq_wrapearly = 0; 393207223Slstewart 394207223Slstewart /* 395207223Slstewart * If we just flushed the buffer completely, reset indexes to 0 to 396207223Slstewart * minimise buffer wraps. 397207223Slstewart * This is also required to ensure alq_getn() can't wedge itself. 398207223Slstewart */ 399207223Slstewart if (!HAS_PENDING_DATA(alq)) 400207223Slstewart alq->aq_writehead = alq->aq_writetail = 0; 401207223Slstewart 402207223Slstewart KASSERT((alq->aq_writetail >= 0 && alq->aq_writetail < alq->aq_buflen), 403207223Slstewart ("%s: aq_writetail < 0 || aq_writetail >= aq_buflen", __func__)); 404207223Slstewart 405103785Sjeff if (alq->aq_flags & AQ_WANTED) { 406103785Sjeff alq->aq_flags &= ~AQ_WANTED; 407103785Sjeff return (1); 408103785Sjeff } 409103785Sjeff 410103785Sjeff return(0); 411103785Sjeff} 412103785Sjeff 413103785Sjeffstatic struct kproc_desc ald_kp = { 414103785Sjeff "ALQ Daemon", 415103785Sjeff ald_daemon, 416103995Sjeff &ald_proc 417103785Sjeff}; 418103785Sjeff 419177253SrwatsonSYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp); 420177253SrwatsonSYSINIT(ald, SI_SUB_LOCK, SI_ORDER_ANY, ald_startup, NULL); 421103785Sjeff 422103785Sjeff 423103785Sjeff/* User visible queue functions */ 424103785Sjeff 425103785Sjeff/* 426103785Sjeff * Create the queue data structure, allocate the buffer, and open the file. 427103785Sjeff */ 428207223Slstewart 429103785Sjeffint 430207223Slstewartalq_open_flags(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 431207223Slstewart int size, int flags) 432103785Sjeff{ 433103785Sjeff struct thread *td; 434103785Sjeff struct nameidata nd; 435103785Sjeff struct alq *alq; 436207223Slstewart int oflags; 437103785Sjeff int error; 438103785Sjeff 439207223Slstewart KASSERT((size > 0), ("%s: size <= 0", __func__)); 440207223Slstewart 441103785Sjeff *alqp = NULL; 442103785Sjeff td = curthread; 443103785Sjeff 444241896Skib NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td); 445207223Slstewart oflags = FWRITE | O_NOFOLLOW | O_CREAT; 446103785Sjeff 447207223Slstewart error = vn_open_cred(&nd, &oflags, cmode, 0, cred, NULL); 448103785Sjeff if (error) 449103785Sjeff return (error); 450154902Spjd 451154903Spjd NDFREE(&nd, NDF_ONLY_PNBUF); 452103785Sjeff /* We just unlock so we hold a reference */ 453175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 454103785Sjeff 455111119Simp alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO); 456103785Sjeff alq->aq_vp = nd.ni_vp; 457116697Srwatson alq->aq_cred = crhold(cred); 458103785Sjeff 459103785Sjeff mtx_init(&alq->aq_mtx, "ALD Queue", NULL, MTX_SPIN|MTX_QUIET); 460103785Sjeff 461207223Slstewart alq->aq_buflen = size; 462207223Slstewart alq->aq_entmax = 0; 463207223Slstewart alq->aq_entlen = 0; 464103785Sjeff 465207223Slstewart alq->aq_freebytes = alq->aq_buflen; 466207223Slstewart alq->aq_entbuf = malloc(alq->aq_buflen, M_ALD, M_WAITOK|M_ZERO); 467207223Slstewart alq->aq_writehead = alq->aq_writetail = 0; 468207223Slstewart if (flags & ALQ_ORDERED) 469207223Slstewart alq->aq_flags |= AQ_ORDERED; 470103785Sjeff 471206026Slstewart if ((error = ald_add(alq)) != 0) { 472206026Slstewart alq_destroy(alq); 473103785Sjeff return (error); 474206026Slstewart } 475206026Slstewart 476103785Sjeff *alqp = alq; 477103785Sjeff 478103785Sjeff return (0); 479103785Sjeff} 480103785Sjeff 481207223Slstewartint 482207223Slstewartalq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, 483207223Slstewart int size, int count) 484207223Slstewart{ 485207223Slstewart int ret; 486207223Slstewart 487207223Slstewart KASSERT((count >= 0), ("%s: count < 0", __func__)); 488207223Slstewart 489207223Slstewart if (count > 0) { 490207223Slstewart ret = alq_open_flags(alqp, file, cred, cmode, size*count, 0); 491207223Slstewart (*alqp)->aq_flags |= AQ_LEGACY; 492207223Slstewart (*alqp)->aq_entmax = count; 493207223Slstewart (*alqp)->aq_entlen = size; 494207223Slstewart } else 495207223Slstewart ret = alq_open_flags(alqp, file, cred, cmode, size, 0); 496207223Slstewart 497207223Slstewart return (ret); 498207223Slstewart} 499207223Slstewart 500207223Slstewart 501103785Sjeff/* 502103785Sjeff * Copy a new entry into the queue. If the operation would block either 503103785Sjeff * wait or return an error depending on the value of waitok. 504103785Sjeff */ 505103785Sjeffint 506207223Slstewartalq_writen(struct alq *alq, void *data, int len, int flags) 507103785Sjeff{ 508207223Slstewart int activate, copy, ret; 509207223Slstewart void *waitchan; 510103785Sjeff 511207223Slstewart KASSERT((len > 0 && len <= alq->aq_buflen), 512207223Slstewart ("%s: len <= 0 || len > aq_buflen", __func__)); 513207223Slstewart 514207223Slstewart activate = ret = 0; 515207223Slstewart copy = len; 516207223Slstewart waitchan = NULL; 517207223Slstewart 518207223Slstewart ALQ_LOCK(alq); 519207223Slstewart 520207223Slstewart /* 521207223Slstewart * Fail to perform the write and return EWOULDBLOCK if: 522207223Slstewart * - The message is larger than our underlying buffer. 523207223Slstewart * - The ALQ is being shutdown. 524207223Slstewart * - There is insufficient free space in our underlying buffer 525207223Slstewart * to accept the message and the user can't wait for space. 526207223Slstewart * - There is insufficient free space in our underlying buffer 527207223Slstewart * to accept the message and the alq is inactive due to prior 528207223Slstewart * use of the ALQ_NOACTIVATE flag (which would lead to deadlock). 529207223Slstewart */ 530207223Slstewart if (len > alq->aq_buflen || 531207223Slstewart alq->aq_flags & AQ_SHUTDOWN || 532207223Slstewart (((flags & ALQ_NOWAIT) || (!(alq->aq_flags & AQ_ACTIVE) && 533207223Slstewart HAS_PENDING_DATA(alq))) && alq->aq_freebytes < len)) { 534207223Slstewart ALQ_UNLOCK(alq); 535103785Sjeff return (EWOULDBLOCK); 536207223Slstewart } 537103785Sjeff 538207223Slstewart /* 539207223Slstewart * If we want ordered writes and there is already at least one thread 540207223Slstewart * waiting for resources to become available, sleep until we're woken. 541207223Slstewart */ 542207223Slstewart if (alq->aq_flags & AQ_ORDERED && alq->aq_waiters > 0) { 543207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 544207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 545207223Slstewart alq->aq_waiters++; 546207223Slstewart msleep_spin(&alq->aq_waiters, &alq->aq_mtx, "alqwnord", 0); 547207223Slstewart alq->aq_waiters--; 548207223Slstewart } 549103785Sjeff 550207223Slstewart /* 551207223Slstewart * (ALQ_WAITOK && aq_freebytes < len) or aq_freebytes >= len, either 552207223Slstewart * enter while loop and sleep until we have enough free bytes (former) 553207223Slstewart * or skip (latter). If AQ_ORDERED is set, only 1 thread at a time will 554207223Slstewart * be in this loop. Otherwise, multiple threads may be sleeping here 555207223Slstewart * competing for ALQ resources. 556207223Slstewart */ 557207223Slstewart while (alq->aq_freebytes < len && !(alq->aq_flags & AQ_SHUTDOWN)) { 558207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 559207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 560207223Slstewart alq->aq_flags |= AQ_WANTED; 561207223Slstewart alq->aq_waiters++; 562207223Slstewart if (waitchan) 563207223Slstewart wakeup(waitchan); 564207223Slstewart msleep_spin(alq, &alq->aq_mtx, "alqwnres", 0); 565207223Slstewart alq->aq_waiters--; 566207223Slstewart 567207223Slstewart /* 568207223Slstewart * If we're the first thread to wake after an AQ_WANTED wakeup 569207223Slstewart * but there isn't enough free space for us, we're going to loop 570207223Slstewart * and sleep again. If there are other threads waiting in this 571207223Slstewart * loop, schedule a wakeup so that they can see if the space 572207223Slstewart * they require is available. 573207223Slstewart */ 574207223Slstewart if (alq->aq_waiters > 0 && !(alq->aq_flags & AQ_ORDERED) && 575207223Slstewart alq->aq_freebytes < len && !(alq->aq_flags & AQ_WANTED)) 576207223Slstewart waitchan = alq; 577207223Slstewart else 578207223Slstewart waitchan = NULL; 579207223Slstewart } 580207223Slstewart 581207223Slstewart /* 582207223Slstewart * If there are waiters, we need to signal the waiting threads after we 583207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 584207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 585207223Slstewart * are not allowed to concurrently compete for resources in the above 586207223Slstewart * while loop, so we use a different wait channel in this case. 587207223Slstewart */ 588207223Slstewart if (alq->aq_waiters > 0) { 589207223Slstewart if (alq->aq_flags & AQ_ORDERED) 590207223Slstewart waitchan = &alq->aq_waiters; 591207223Slstewart else 592207223Slstewart waitchan = alq; 593207223Slstewart } else 594207223Slstewart waitchan = NULL; 595207223Slstewart 596207223Slstewart /* Bail if we're shutting down. */ 597207223Slstewart if (alq->aq_flags & AQ_SHUTDOWN) { 598207223Slstewart ret = EWOULDBLOCK; 599207223Slstewart goto unlock; 600207223Slstewart } 601207223Slstewart 602207223Slstewart /* 603207223Slstewart * If we need to wrap the buffer to accommodate the write, 604207223Slstewart * we'll need 2 calls to bcopy. 605207223Slstewart */ 606207223Slstewart if ((alq->aq_buflen - alq->aq_writehead) < len) 607207223Slstewart copy = alq->aq_buflen - alq->aq_writehead; 608207223Slstewart 609207223Slstewart /* Copy message (or part thereof if wrap required) to the buffer. */ 610207223Slstewart bcopy(data, alq->aq_entbuf + alq->aq_writehead, copy); 611207223Slstewart alq->aq_writehead += copy; 612207223Slstewart 613207223Slstewart if (alq->aq_writehead >= alq->aq_buflen) { 614207223Slstewart KASSERT((alq->aq_writehead == alq->aq_buflen), 615207223Slstewart ("%s: alq->aq_writehead (%d) > alq->aq_buflen (%d)", 616207223Slstewart __func__, 617207223Slstewart alq->aq_writehead, 618207223Slstewart alq->aq_buflen)); 619207223Slstewart alq->aq_writehead = 0; 620207223Slstewart } 621207223Slstewart 622207223Slstewart if (copy != len) { 623207223Slstewart /* 624207223Slstewart * Wrap the buffer by copying the remainder of our message 625207223Slstewart * to the start of the buffer and resetting aq_writehead. 626207223Slstewart */ 627207223Slstewart bcopy(((uint8_t *)data)+copy, alq->aq_entbuf, len - copy); 628207223Slstewart alq->aq_writehead = len - copy; 629207223Slstewart } 630207223Slstewart 631207223Slstewart KASSERT((alq->aq_writehead >= 0 && alq->aq_writehead < alq->aq_buflen), 632207223Slstewart ("%s: aq_writehead < 0 || aq_writehead >= aq_buflen", __func__)); 633207223Slstewart 634207223Slstewart alq->aq_freebytes -= len; 635207223Slstewart 636207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && !(flags & ALQ_NOACTIVATE)) { 637207223Slstewart alq->aq_flags |= AQ_ACTIVE; 638207223Slstewart activate = 1; 639207223Slstewart } 640207223Slstewart 641207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 642207223Slstewart 643207223Slstewartunlock: 644207223Slstewart ALQ_UNLOCK(alq); 645207223Slstewart 646207223Slstewart if (activate) { 647207223Slstewart ALD_LOCK(); 648207223Slstewart ald_activate(alq); 649207223Slstewart ALD_UNLOCK(); 650207223Slstewart } 651207223Slstewart 652207223Slstewart /* NB: We rely on wakeup_one waking threads in a FIFO manner. */ 653207223Slstewart if (waitchan != NULL) 654207223Slstewart wakeup_one(waitchan); 655207223Slstewart 656207223Slstewart return (ret); 657103785Sjeff} 658103785Sjeff 659207223Slstewartint 660207223Slstewartalq_write(struct alq *alq, void *data, int flags) 661207223Slstewart{ 662207223Slstewart /* Should only be called in fixed length message (legacy) mode. */ 663207223Slstewart KASSERT((alq->aq_flags & AQ_LEGACY), 664207223Slstewart ("%s: fixed length write on variable length queue", __func__)); 665207223Slstewart return (alq_writen(alq, data, alq->aq_entlen, flags)); 666207223Slstewart} 667207223Slstewart 668207223Slstewart/* 669207223Slstewart * Retrieve a pointer for the ALQ to write directly into, avoiding bcopy. 670207223Slstewart */ 671103785Sjeffstruct ale * 672207223Slstewartalq_getn(struct alq *alq, int len, int flags) 673103785Sjeff{ 674207223Slstewart int contigbytes; 675207223Slstewart void *waitchan; 676103785Sjeff 677207223Slstewart KASSERT((len > 0 && len <= alq->aq_buflen), 678207223Slstewart ("%s: len <= 0 || len > alq->aq_buflen", __func__)); 679103785Sjeff 680207223Slstewart waitchan = NULL; 681207223Slstewart 682103785Sjeff ALQ_LOCK(alq); 683103785Sjeff 684207223Slstewart /* 685207223Slstewart * Determine the number of free contiguous bytes. 686207223Slstewart * We ensure elsewhere that if aq_writehead == aq_writetail because 687207223Slstewart * the buffer is empty, they will both be set to 0 and therefore 688207223Slstewart * aq_freebytes == aq_buflen and is fully contiguous. 689207223Slstewart * If they are equal and the buffer is not empty, aq_freebytes will 690207223Slstewart * be 0 indicating the buffer is full. 691207223Slstewart */ 692207223Slstewart if (alq->aq_writehead <= alq->aq_writetail) 693207223Slstewart contigbytes = alq->aq_freebytes; 694207223Slstewart else { 695207223Slstewart contigbytes = alq->aq_buflen - alq->aq_writehead; 696207223Slstewart 697207223Slstewart if (contigbytes < len) { 698207223Slstewart /* 699207223Slstewart * Insufficient space at end of buffer to handle a 700207223Slstewart * contiguous write. Wrap early if there's space at 701207223Slstewart * the beginning. This will leave a hole at the end 702207223Slstewart * of the buffer which we will have to skip over when 703207223Slstewart * flushing the buffer to disk. 704207223Slstewart */ 705207223Slstewart if (alq->aq_writetail >= len || flags & ALQ_WAITOK) { 706207223Slstewart /* Keep track of # bytes left blank. */ 707207223Slstewart alq->aq_wrapearly = contigbytes; 708207223Slstewart /* Do the wrap and adjust counters. */ 709207223Slstewart contigbytes = alq->aq_freebytes = 710207223Slstewart alq->aq_writetail; 711207223Slstewart alq->aq_writehead = 0; 712207223Slstewart } 713207223Slstewart } 714207223Slstewart } 715207223Slstewart 716207223Slstewart /* 717207223Slstewart * Return a NULL ALE if: 718207223Slstewart * - The message is larger than our underlying buffer. 719207223Slstewart * - The ALQ is being shutdown. 720207223Slstewart * - There is insufficient free space in our underlying buffer 721207223Slstewart * to accept the message and the user can't wait for space. 722207223Slstewart * - There is insufficient free space in our underlying buffer 723207223Slstewart * to accept the message and the alq is inactive due to prior 724207223Slstewart * use of the ALQ_NOACTIVATE flag (which would lead to deadlock). 725207223Slstewart */ 726207223Slstewart if (len > alq->aq_buflen || 727207223Slstewart alq->aq_flags & AQ_SHUTDOWN || 728207223Slstewart (((flags & ALQ_NOWAIT) || (!(alq->aq_flags & AQ_ACTIVE) && 729207223Slstewart HAS_PENDING_DATA(alq))) && contigbytes < len)) { 730207223Slstewart ALQ_UNLOCK(alq); 731207223Slstewart return (NULL); 732207223Slstewart } 733207223Slstewart 734207223Slstewart /* 735207223Slstewart * If we want ordered writes and there is already at least one thread 736207223Slstewart * waiting for resources to become available, sleep until we're woken. 737207223Slstewart */ 738207223Slstewart if (alq->aq_flags & AQ_ORDERED && alq->aq_waiters > 0) { 739207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 740207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 741207223Slstewart alq->aq_waiters++; 742207223Slstewart msleep_spin(&alq->aq_waiters, &alq->aq_mtx, "alqgnord", 0); 743207223Slstewart alq->aq_waiters--; 744207223Slstewart } 745207223Slstewart 746207223Slstewart /* 747207223Slstewart * (ALQ_WAITOK && contigbytes < len) or contigbytes >= len, either enter 748207223Slstewart * while loop and sleep until we have enough contiguous free bytes 749207223Slstewart * (former) or skip (latter). If AQ_ORDERED is set, only 1 thread at a 750207223Slstewart * time will be in this loop. Otherwise, multiple threads may be 751207223Slstewart * sleeping here competing for ALQ resources. 752207223Slstewart */ 753207223Slstewart while (contigbytes < len && !(alq->aq_flags & AQ_SHUTDOWN)) { 754207223Slstewart KASSERT(!(flags & ALQ_NOWAIT), 755207223Slstewart ("%s: ALQ_NOWAIT set but incorrectly ignored!", __func__)); 756103785Sjeff alq->aq_flags |= AQ_WANTED; 757207223Slstewart alq->aq_waiters++; 758207223Slstewart if (waitchan) 759207223Slstewart wakeup(waitchan); 760207223Slstewart msleep_spin(alq, &alq->aq_mtx, "alqgnres", 0); 761207223Slstewart alq->aq_waiters--; 762207223Slstewart 763207223Slstewart if (alq->aq_writehead <= alq->aq_writetail) 764207223Slstewart contigbytes = alq->aq_freebytes; 765207223Slstewart else 766207223Slstewart contigbytes = alq->aq_buflen - alq->aq_writehead; 767207223Slstewart 768207223Slstewart /* 769207223Slstewart * If we're the first thread to wake after an AQ_WANTED wakeup 770207223Slstewart * but there isn't enough free space for us, we're going to loop 771207223Slstewart * and sleep again. If there are other threads waiting in this 772207223Slstewart * loop, schedule a wakeup so that they can see if the space 773207223Slstewart * they require is available. 774207223Slstewart */ 775207223Slstewart if (alq->aq_waiters > 0 && !(alq->aq_flags & AQ_ORDERED) && 776207223Slstewart contigbytes < len && !(alq->aq_flags & AQ_WANTED)) 777207223Slstewart waitchan = alq; 778207223Slstewart else 779207223Slstewart waitchan = NULL; 780103785Sjeff } 781103785Sjeff 782207223Slstewart /* 783207223Slstewart * If there are waiters, we need to signal the waiting threads after we 784207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 785207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 786207223Slstewart * are not allowed to concurrently compete for resources in the above 787207223Slstewart * while loop, so we use a different wait channel in this case. 788207223Slstewart */ 789207223Slstewart if (alq->aq_waiters > 0) { 790207223Slstewart if (alq->aq_flags & AQ_ORDERED) 791207223Slstewart waitchan = &alq->aq_waiters; 792115308Sjeff else 793207223Slstewart waitchan = alq; 794103785Sjeff } else 795207223Slstewart waitchan = NULL; 796207223Slstewart 797207223Slstewart /* Bail if we're shutting down. */ 798207223Slstewart if (alq->aq_flags & AQ_SHUTDOWN) { 799103785Sjeff ALQ_UNLOCK(alq); 800207223Slstewart if (waitchan != NULL) 801207223Slstewart wakeup_one(waitchan); 802207223Slstewart return (NULL); 803207223Slstewart } 804103785Sjeff 805207223Slstewart /* 806207223Slstewart * If we are here, we have a contiguous number of bytes >= len 807207223Slstewart * available in our buffer starting at aq_writehead. 808207223Slstewart */ 809207223Slstewart alq->aq_getpost.ae_data = alq->aq_entbuf + alq->aq_writehead; 810207223Slstewart alq->aq_getpost.ae_bytesused = len; 811103785Sjeff 812207223Slstewart return (&alq->aq_getpost); 813103785Sjeff} 814103785Sjeff 815207223Slstewartstruct ale * 816207223Slstewartalq_get(struct alq *alq, int flags) 817207223Slstewart{ 818207223Slstewart /* Should only be called in fixed length message (legacy) mode. */ 819207223Slstewart KASSERT((alq->aq_flags & AQ_LEGACY), 820207223Slstewart ("%s: fixed length get on variable length queue", __func__)); 821207223Slstewart return (alq_getn(alq, alq->aq_entlen, flags)); 822207223Slstewart} 823207223Slstewart 824103785Sjeffvoid 825207223Slstewartalq_post_flags(struct alq *alq, struct ale *ale, int flags) 826103785Sjeff{ 827103785Sjeff int activate; 828207223Slstewart void *waitchan; 829103785Sjeff 830207223Slstewart activate = 0; 831103785Sjeff 832207223Slstewart if (ale->ae_bytesused > 0) { 833207223Slstewart if (!(alq->aq_flags & AQ_ACTIVE) && 834207223Slstewart !(flags & ALQ_NOACTIVATE)) { 835207223Slstewart alq->aq_flags |= AQ_ACTIVE; 836207223Slstewart activate = 1; 837207223Slstewart } 838103785Sjeff 839207223Slstewart alq->aq_writehead += ale->ae_bytesused; 840207223Slstewart alq->aq_freebytes -= ale->ae_bytesused; 841207223Slstewart 842207223Slstewart /* Wrap aq_writehead if we filled to the end of the buffer. */ 843207223Slstewart if (alq->aq_writehead == alq->aq_buflen) 844207223Slstewart alq->aq_writehead = 0; 845207223Slstewart 846207223Slstewart KASSERT((alq->aq_writehead >= 0 && 847207223Slstewart alq->aq_writehead < alq->aq_buflen), 848207223Slstewart ("%s: aq_writehead < 0 || aq_writehead >= aq_buflen", 849207223Slstewart __func__)); 850207223Slstewart 851207223Slstewart KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); 852207223Slstewart } 853207223Slstewart 854207223Slstewart /* 855207223Slstewart * If there are waiters, we need to signal the waiting threads after we 856207223Slstewart * complete our work. The alq ptr is used as a wait channel for threads 857207223Slstewart * requiring resources to be freed up. In the AQ_ORDERED case, threads 858207223Slstewart * are not allowed to concurrently compete for resources in the 859207223Slstewart * alq_getn() while loop, so we use a different wait channel in this case. 860207223Slstewart */ 861207223Slstewart if (alq->aq_waiters > 0) { 862207223Slstewart if (alq->aq_flags & AQ_ORDERED) 863207223Slstewart waitchan = &alq->aq_waiters; 864207223Slstewart else 865207223Slstewart waitchan = alq; 866103785Sjeff } else 867207223Slstewart waitchan = NULL; 868103785Sjeff 869103785Sjeff ALQ_UNLOCK(alq); 870207223Slstewart 871103785Sjeff if (activate) { 872103785Sjeff ALD_LOCK(); 873103785Sjeff ald_activate(alq); 874103785Sjeff ALD_UNLOCK(); 875103785Sjeff } 876207223Slstewart 877207223Slstewart /* NB: We rely on wakeup_one waking threads in a FIFO manner. */ 878207223Slstewart if (waitchan != NULL) 879207223Slstewart wakeup_one(waitchan); 880103785Sjeff} 881103785Sjeff 882103785Sjeffvoid 883103785Sjeffalq_flush(struct alq *alq) 884103785Sjeff{ 885103785Sjeff int needwakeup = 0; 886103785Sjeff 887103785Sjeff ALD_LOCK(); 888103785Sjeff ALQ_LOCK(alq); 889207223Slstewart 890207223Slstewart /* 891207223Slstewart * Pull the lever iff there is data to flush and we're 892207223Slstewart * not already in the middle of a flush operation. 893207223Slstewart */ 894207223Slstewart if (HAS_PENDING_DATA(alq) && !(alq->aq_flags & AQ_FLUSHING)) { 895207223Slstewart if (alq->aq_flags & AQ_ACTIVE) 896207223Slstewart ald_deactivate(alq); 897207223Slstewart 898103785Sjeff ALD_UNLOCK(); 899103785Sjeff needwakeup = alq_doio(alq); 900103785Sjeff } else 901103785Sjeff ALD_UNLOCK(); 902207223Slstewart 903103785Sjeff ALQ_UNLOCK(alq); 904103785Sjeff 905103785Sjeff if (needwakeup) 906207223Slstewart wakeup_one(alq); 907103785Sjeff} 908103785Sjeff 909103785Sjeff/* 910103785Sjeff * Flush remaining data, close the file and free all resources. 911103785Sjeff */ 912103785Sjeffvoid 913103785Sjeffalq_close(struct alq *alq) 914103785Sjeff{ 915206026Slstewart /* Only flush and destroy alq if not already shutting down. */ 916206026Slstewart if (ald_rem(alq) == 0) 917206026Slstewart alq_destroy(alq); 918103785Sjeff} 919205959Slstewart 920205959Slstewartstatic int 921205959Slstewartalq_load_handler(module_t mod, int what, void *arg) 922205959Slstewart{ 923205959Slstewart int ret; 924205959Slstewart 925205959Slstewart ret = 0; 926205959Slstewart 927205959Slstewart switch (what) { 928205959Slstewart case MOD_LOAD: 929205959Slstewart case MOD_SHUTDOWN: 930205959Slstewart break; 931205959Slstewart 932205959Slstewart case MOD_QUIESCE: 933205959Slstewart ALD_LOCK(); 934205959Slstewart /* Only allow unload if there are no open queues. */ 935205959Slstewart if (LIST_FIRST(&ald_queues) == NULL) { 936205959Slstewart ald_shutingdown = 1; 937205959Slstewart ALD_UNLOCK(); 938205959Slstewart ald_shutdown(NULL, 0); 939205959Slstewart mtx_destroy(&ald_mtx); 940205959Slstewart } else { 941205959Slstewart ALD_UNLOCK(); 942205959Slstewart ret = EBUSY; 943205959Slstewart } 944205959Slstewart break; 945205959Slstewart 946205959Slstewart case MOD_UNLOAD: 947205959Slstewart /* If MOD_QUIESCE failed we must fail here too. */ 948205959Slstewart if (ald_shutingdown == 0) 949205959Slstewart ret = EBUSY; 950205959Slstewart break; 951205959Slstewart 952205959Slstewart default: 953205959Slstewart ret = EINVAL; 954205959Slstewart break; 955205959Slstewart } 956205959Slstewart 957205959Slstewart return (ret); 958205959Slstewart} 959205959Slstewart 960205959Slstewartstatic moduledata_t alq_mod = 961205959Slstewart{ 962205959Slstewart "alq", 963205959Slstewart alq_load_handler, 964205959Slstewart NULL 965205959Slstewart}; 966205959Slstewart 967205959SlstewartDECLARE_MODULE(alq, alq_mod, SI_SUB_SMP, SI_ORDER_ANY); 968205959SlstewartMODULE_VERSION(alq, 1); 969