15e53a4f9SPedro F. Giffuni /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35e53a4f9SPedro F. Giffuni * 44acaec8fSDavid Xu * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 54acaec8fSDavid Xu * All rights reserved. 64acaec8fSDavid Xu * 74acaec8fSDavid Xu * Redistribution and use in source and binary forms, with or without 84acaec8fSDavid Xu * modification, are permitted provided that the following conditions 94acaec8fSDavid Xu * are met: 104acaec8fSDavid Xu * 1. Redistributions of source code must retain the above copyright 114acaec8fSDavid Xu * notice unmodified, this list of conditions, and the following 124acaec8fSDavid Xu * disclaimer. 134acaec8fSDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 144acaec8fSDavid Xu * notice, this list of conditions and the following disclaimer in the 154acaec8fSDavid Xu * documentation and/or other materials provided with the distribution. 164acaec8fSDavid Xu * 174acaec8fSDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 184acaec8fSDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 194acaec8fSDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 204acaec8fSDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 214acaec8fSDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 224acaec8fSDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234acaec8fSDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244acaec8fSDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254acaec8fSDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 264acaec8fSDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274acaec8fSDavid Xu * 284acaec8fSDavid Xu * $FreeBSD$ 294acaec8fSDavid Xu * 304acaec8fSDavid Xu */ 314acaec8fSDavid Xu 324acaec8fSDavid Xu #include <sys/cdefs.h> 334acaec8fSDavid Xu #include <sys/types.h> 344acaec8fSDavid Xu #include <sys/syscall.h> 354acaec8fSDavid Xu #include <sys/aio.h> 364acaec8fSDavid Xu 374acaec8fSDavid Xu #include "namespace.h" 384acaec8fSDavid Xu #include <errno.h> 394acaec8fSDavid Xu #include <stddef.h> 404acaec8fSDavid Xu #include <signal.h> 414acaec8fSDavid Xu #include "sigev_thread.h" 424acaec8fSDavid Xu #include "un-namespace.h" 434acaec8fSDavid Xu 444acaec8fSDavid Xu __weak_reference(__aio_read, aio_read); 45*3904e796SThomas Munro __weak_reference(__aio_readv, aio_readv); 464acaec8fSDavid Xu __weak_reference(__aio_write, aio_write); 47*3904e796SThomas Munro __weak_reference(__aio_writev, aio_writev); 484acaec8fSDavid Xu __weak_reference(__aio_return, aio_return); 494acaec8fSDavid Xu __weak_reference(__aio_waitcomplete, aio_waitcomplete); 503c778728SDavid Xu __weak_reference(__aio_fsync, aio_fsync); 5118ddf67cSAlan Somers __weak_reference(__lio_listio, lio_listio); 524acaec8fSDavid Xu 534acaec8fSDavid Xu typedef void (*aio_func)(union sigval val, struct aiocb *iocb); 544acaec8fSDavid Xu 554acaec8fSDavid Xu extern int __sys_aio_read(struct aiocb *iocb); 56*3904e796SThomas Munro extern int __sys_aio_readv(struct aiocb *iocb); 574acaec8fSDavid Xu extern int __sys_aio_write(struct aiocb *iocb); 58*3904e796SThomas Munro extern int __sys_aio_writev(struct aiocb *iocb); 5976793d4dSJohn Baldwin extern ssize_t __sys_aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout); 6076793d4dSJohn Baldwin extern ssize_t __sys_aio_return(struct aiocb *iocb); 614acaec8fSDavid Xu extern int __sys_aio_error(struct aiocb *iocb); 623c778728SDavid Xu extern int __sys_aio_fsync(int op, struct aiocb *iocb); 6318ddf67cSAlan Somers extern int __sys_lio_listio(int mode, struct aiocb * const list[], int nent, 6418ddf67cSAlan Somers struct sigevent *sig); 654acaec8fSDavid Xu 664acaec8fSDavid Xu static void 676348ace8SDavid Xu aio_dispatch(struct sigev_node *sn) 684acaec8fSDavid Xu { 694acaec8fSDavid Xu aio_func f = sn->sn_func; 704acaec8fSDavid Xu 714acaec8fSDavid Xu f(sn->sn_value, (struct aiocb *)sn->sn_id); 724acaec8fSDavid Xu } 734acaec8fSDavid Xu 744acaec8fSDavid Xu static int 7518ddf67cSAlan Somers aio_sigev_alloc(sigev_id_t id, struct sigevent *sigevent, 7618ddf67cSAlan Somers struct sigev_node **sn, struct sigevent *saved_ev) 773c778728SDavid Xu { 783c778728SDavid Xu if (__sigev_check_init()) { 793c778728SDavid Xu /* This might be that thread library is not enabled. */ 803c778728SDavid Xu errno = EINVAL; 813c778728SDavid Xu return (-1); 823c778728SDavid Xu } 833c778728SDavid Xu 8418ddf67cSAlan Somers *sn = __sigev_alloc(SI_ASYNCIO, sigevent, NULL, 1); 853c778728SDavid Xu if (*sn == NULL) { 863c778728SDavid Xu errno = EAGAIN; 873c778728SDavid Xu return (-1); 883c778728SDavid Xu } 893c778728SDavid Xu 9018ddf67cSAlan Somers *saved_ev = *sigevent; 9118ddf67cSAlan Somers (*sn)->sn_id = id; 9218ddf67cSAlan Somers __sigev_get_sigevent(*sn, sigevent, (*sn)->sn_id); 933c778728SDavid Xu (*sn)->sn_dispatch = aio_dispatch; 943c778728SDavid Xu 953c778728SDavid Xu __sigev_list_lock(); 963c778728SDavid Xu __sigev_register(*sn); 973c778728SDavid Xu __sigev_list_unlock(); 983c778728SDavid Xu 993c778728SDavid Xu return (0); 1003c778728SDavid Xu } 1013c778728SDavid Xu 1023c778728SDavid Xu static int 1034acaec8fSDavid Xu aio_io(struct aiocb *iocb, int (*sysfunc)(struct aiocb *iocb)) 1044acaec8fSDavid Xu { 1054acaec8fSDavid Xu struct sigev_node *sn; 1064acaec8fSDavid Xu struct sigevent saved_ev; 1071b4610feSDavid Xu int ret, err; 1084acaec8fSDavid Xu 1094acaec8fSDavid Xu if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD) { 1104acaec8fSDavid Xu ret = sysfunc(iocb); 1114acaec8fSDavid Xu return (ret); 1124acaec8fSDavid Xu } 1134acaec8fSDavid Xu 11418ddf67cSAlan Somers ret = aio_sigev_alloc((sigev_id_t)iocb, &iocb->aio_sigevent, &sn, 11518ddf67cSAlan Somers &saved_ev); 1163c778728SDavid Xu if (ret) 1173c778728SDavid Xu return (ret); 1184acaec8fSDavid Xu ret = sysfunc(iocb); 1194acaec8fSDavid Xu iocb->aio_sigevent = saved_ev; 1204acaec8fSDavid Xu if (ret != 0) { 1211b4610feSDavid Xu err = errno; 1224acaec8fSDavid Xu __sigev_list_lock(); 1234acaec8fSDavid Xu __sigev_delete_node(sn); 1244acaec8fSDavid Xu __sigev_list_unlock(); 1251b4610feSDavid Xu errno = err; 1264acaec8fSDavid Xu } 1274acaec8fSDavid Xu return (ret); 1284acaec8fSDavid Xu } 1294acaec8fSDavid Xu 1304acaec8fSDavid Xu int 1314acaec8fSDavid Xu __aio_read(struct aiocb *iocb) 1324acaec8fSDavid Xu { 1331b4610feSDavid Xu 1344acaec8fSDavid Xu return aio_io(iocb, &__sys_aio_read); 1354acaec8fSDavid Xu } 1364acaec8fSDavid Xu 1374acaec8fSDavid Xu int 138*3904e796SThomas Munro __aio_readv(struct aiocb *iocb) 139*3904e796SThomas Munro { 140*3904e796SThomas Munro 141*3904e796SThomas Munro return aio_io(iocb, &__sys_aio_readv); 142*3904e796SThomas Munro } 143*3904e796SThomas Munro 144*3904e796SThomas Munro int 1454acaec8fSDavid Xu __aio_write(struct aiocb *iocb) 1464acaec8fSDavid Xu { 1471b4610feSDavid Xu 1484acaec8fSDavid Xu return aio_io(iocb, &__sys_aio_write); 1494acaec8fSDavid Xu } 1504acaec8fSDavid Xu 151*3904e796SThomas Munro int 152*3904e796SThomas Munro __aio_writev(struct aiocb *iocb) 153*3904e796SThomas Munro { 154*3904e796SThomas Munro 155*3904e796SThomas Munro return aio_io(iocb, &__sys_aio_writev); 156*3904e796SThomas Munro } 157*3904e796SThomas Munro 15876793d4dSJohn Baldwin ssize_t 1594acaec8fSDavid Xu __aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout) 1604acaec8fSDavid Xu { 16176793d4dSJohn Baldwin ssize_t ret; 1621b4610feSDavid Xu int err; 1634acaec8fSDavid Xu 16476793d4dSJohn Baldwin ret = __sys_aio_waitcomplete(iocbp, timeout); 1654acaec8fSDavid Xu if (*iocbp) { 1664acaec8fSDavid Xu if ((*iocbp)->aio_sigevent.sigev_notify == SIGEV_THREAD) { 1671b4610feSDavid Xu err = errno; 1684acaec8fSDavid Xu __sigev_list_lock(); 1694acaec8fSDavid Xu __sigev_delete(SI_ASYNCIO, (sigev_id_t)(*iocbp)); 1704acaec8fSDavid Xu __sigev_list_unlock(); 1711b4610feSDavid Xu errno = err; 1724acaec8fSDavid Xu } 1734acaec8fSDavid Xu } 1744acaec8fSDavid Xu 1754acaec8fSDavid Xu return (ret); 1764acaec8fSDavid Xu } 1774acaec8fSDavid Xu 17876793d4dSJohn Baldwin ssize_t 1794acaec8fSDavid Xu __aio_return(struct aiocb *iocb) 1804acaec8fSDavid Xu { 1814acaec8fSDavid Xu 1821b4610feSDavid Xu if (iocb->aio_sigevent.sigev_notify == SIGEV_THREAD) { 18376793d4dSJohn Baldwin if (__sys_aio_error(iocb) == EINPROGRESS) { 18476793d4dSJohn Baldwin /* 18576793d4dSJohn Baldwin * Fail with EINVAL to match the semantics of 18676793d4dSJohn Baldwin * __sys_aio_return() for an in-progress 18776793d4dSJohn Baldwin * request. 18876793d4dSJohn Baldwin */ 18976793d4dSJohn Baldwin errno = EINVAL; 19076793d4dSJohn Baldwin return (-1); 19176793d4dSJohn Baldwin } 1924acaec8fSDavid Xu __sigev_list_lock(); 1934acaec8fSDavid Xu __sigev_delete(SI_ASYNCIO, (sigev_id_t)iocb); 1944acaec8fSDavid Xu __sigev_list_unlock(); 1954acaec8fSDavid Xu } 1964acaec8fSDavid Xu 1971b4610feSDavid Xu return __sys_aio_return(iocb); 1984acaec8fSDavid Xu } 1993c778728SDavid Xu 2003c778728SDavid Xu int 2013c778728SDavid Xu __aio_fsync(int op, struct aiocb *iocb) 2023c778728SDavid Xu { 2033c778728SDavid Xu struct sigev_node *sn; 2043c778728SDavid Xu struct sigevent saved_ev; 2053c778728SDavid Xu int ret, err; 2063c778728SDavid Xu 2073c778728SDavid Xu if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD) 2083c778728SDavid Xu return __sys_aio_fsync(op, iocb); 2093c778728SDavid Xu 21018ddf67cSAlan Somers ret = aio_sigev_alloc((sigev_id_t)iocb, &iocb->aio_sigevent, &sn, 21118ddf67cSAlan Somers &saved_ev); 2123c778728SDavid Xu if (ret) 2133c778728SDavid Xu return (ret); 2143c778728SDavid Xu ret = __sys_aio_fsync(op, iocb); 2153c778728SDavid Xu iocb->aio_sigevent = saved_ev; 2163c778728SDavid Xu if (ret != 0) { 2173c778728SDavid Xu err = errno; 2183c778728SDavid Xu __sigev_list_lock(); 2193c778728SDavid Xu __sigev_delete_node(sn); 2203c778728SDavid Xu __sigev_list_unlock(); 2213c778728SDavid Xu errno = err; 2223c778728SDavid Xu } 2233c778728SDavid Xu return (ret); 2243c778728SDavid Xu } 22518ddf67cSAlan Somers 22618ddf67cSAlan Somers int 22718ddf67cSAlan Somers __lio_listio(int mode, struct aiocb * const list[], int nent, 22818ddf67cSAlan Somers struct sigevent *sig) 22918ddf67cSAlan Somers { 23018ddf67cSAlan Somers struct sigev_node *sn; 23118ddf67cSAlan Somers struct sigevent saved_ev; 23218ddf67cSAlan Somers int ret, err; 23318ddf67cSAlan Somers 23418ddf67cSAlan Somers if (sig == NULL || sig->sigev_notify != SIGEV_THREAD) 23518ddf67cSAlan Somers return (__sys_lio_listio(mode, list, nent, sig)); 23618ddf67cSAlan Somers 23718ddf67cSAlan Somers ret = aio_sigev_alloc((sigev_id_t)list, sig, &sn, &saved_ev); 23818ddf67cSAlan Somers if (ret) 23918ddf67cSAlan Somers return (ret); 24018ddf67cSAlan Somers ret = __sys_lio_listio(mode, list, nent, sig); 24118ddf67cSAlan Somers *sig = saved_ev; 24218ddf67cSAlan Somers if (ret != 0) { 24318ddf67cSAlan Somers err = errno; 24418ddf67cSAlan Somers __sigev_list_lock(); 24518ddf67cSAlan Somers __sigev_delete_node(sn); 24618ddf67cSAlan Somers __sigev_list_unlock(); 24718ddf67cSAlan Somers errno = err; 24818ddf67cSAlan Somers } 24918ddf67cSAlan Somers return (ret); 25018ddf67cSAlan Somers } 251