17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 534709573Sraf * Common Development and Distribution License (the "License"). 634709573Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2134709573Sraf 227c478bd9Sstevel@tonic-gate /* 23dd1e66b6SVamsi Nagineni * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Kernel asynchronous I/O. 297c478bd9Sstevel@tonic-gate * This is only for raw devices now (as of Nov. 1993). 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/file.h> 367c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 377c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 397c478bd9Sstevel@tonic-gate #include <vm/as.h> 407c478bd9Sstevel@tonic-gate #include <vm/faultcode.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 437c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 447c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 457c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 477c478bd9Sstevel@tonic-gate #include <sys/aio_impl.h> 487c478bd9Sstevel@tonic-gate #include <sys/debug.h> 497c478bd9Sstevel@tonic-gate #include <sys/param.h> 507c478bd9Sstevel@tonic-gate #include <sys/systm.h> 517c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 527c478bd9Sstevel@tonic-gate #include <sys/fs/pxfs_ki.h> 537c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * external entry point. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate #ifdef _LP64 597c478bd9Sstevel@tonic-gate static int64_t kaioc(long, long, long, long, long, long); 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate static int kaio(ulong_t *, rval_t *); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #define AIO_64 0 657c478bd9Sstevel@tonic-gate #define AIO_32 1 667c478bd9Sstevel@tonic-gate #define AIO_LARGEFILE 2 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* 697c478bd9Sstevel@tonic-gate * implementation specific functions (private) 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate #ifdef _LP64 7234709573Sraf static int alio(int, aiocb_t **, int, struct sigevent *); 737c478bd9Sstevel@tonic-gate #endif 747c478bd9Sstevel@tonic-gate static int aionotify(void); 757c478bd9Sstevel@tonic-gate static int aioinit(void); 767c478bd9Sstevel@tonic-gate static int aiostart(void); 777c478bd9Sstevel@tonic-gate static void alio_cleanup(aio_t *, aiocb_t **, int, int); 787c478bd9Sstevel@tonic-gate static int (*check_vp(struct vnode *, int))(vnode_t *, struct aio_req *, 797c478bd9Sstevel@tonic-gate cred_t *); 8034b3058fSpraks static void lio_set_error(aio_req_t *, int portused); 817c478bd9Sstevel@tonic-gate static aio_t *aio_aiop_alloc(); 827c478bd9Sstevel@tonic-gate static int aio_req_alloc(aio_req_t **, aio_result_t *); 837c478bd9Sstevel@tonic-gate static int aio_lio_alloc(aio_lio_t **); 847c478bd9Sstevel@tonic-gate static aio_req_t *aio_req_done(void *); 857c478bd9Sstevel@tonic-gate static aio_req_t *aio_req_remove(aio_req_t *); 867c478bd9Sstevel@tonic-gate static int aio_req_find(aio_result_t *, aio_req_t **); 877c478bd9Sstevel@tonic-gate static int aio_hash_insert(struct aio_req_t *, aio_t *); 887c478bd9Sstevel@tonic-gate static int aio_req_setup(aio_req_t **, aio_t *, aiocb_t *, 89*d2749ac6SRoger A. Faulkner aio_result_t *, vnode_t *, int); 907c478bd9Sstevel@tonic-gate static int aio_cleanup_thread(aio_t *); 917c478bd9Sstevel@tonic-gate static aio_lio_t *aio_list_get(aio_result_t *); 927c478bd9Sstevel@tonic-gate static void lio_set_uerror(void *, int); 937c478bd9Sstevel@tonic-gate extern void aio_zerolen(aio_req_t *); 947c478bd9Sstevel@tonic-gate static int aiowait(struct timeval *, int, long *); 957c478bd9Sstevel@tonic-gate static int aiowaitn(void *, uint_t, uint_t *, timespec_t *); 967c478bd9Sstevel@tonic-gate static int aio_unlock_requests(caddr_t iocblist, int iocb_index, 977c478bd9Sstevel@tonic-gate aio_req_t *reqlist, aio_t *aiop, model_t model); 987c478bd9Sstevel@tonic-gate static int aio_reqlist_concat(aio_t *aiop, aio_req_t **reqlist, int max); 997c478bd9Sstevel@tonic-gate static int aiosuspend(void *, int, struct timespec *, int, 1007c478bd9Sstevel@tonic-gate long *, int); 1017c478bd9Sstevel@tonic-gate static int aliowait(int, void *, int, void *, int); 1027c478bd9Sstevel@tonic-gate static int aioerror(void *, int); 1037c478bd9Sstevel@tonic-gate static int aio_cancel(int, void *, long *, int); 1047c478bd9Sstevel@tonic-gate static int arw(int, int, char *, int, offset_t, aio_result_t *, int); 1057c478bd9Sstevel@tonic-gate static int aiorw(int, void *, int, int); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate static int alioLF(int, void *, int, void *); 10834709573Sraf static int aio_req_setupLF(aio_req_t **, aio_t *, aiocb64_32_t *, 109*d2749ac6SRoger A. Faulkner aio_result_t *, vnode_t *, int); 1107c478bd9Sstevel@tonic-gate static int alio32(int, void *, int, void *); 1117c478bd9Sstevel@tonic-gate static int driver_aio_write(vnode_t *vp, struct aio_req *aio, cred_t *cred_p); 1127c478bd9Sstevel@tonic-gate static int driver_aio_read(vnode_t *vp, struct aio_req *aio, cred_t *cred_p); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1157c478bd9Sstevel@tonic-gate static void aiocb_LFton(aiocb64_32_t *, aiocb_t *); 1167c478bd9Sstevel@tonic-gate void aiocb_32ton(aiocb32_t *, aiocb_t *); 1177c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * implementation specific functions (external) 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate void aio_req_free(aio_t *, aio_req_t *); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * Event Port framework 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate void aio_req_free_port(aio_t *, aio_req_t *); 1297c478bd9Sstevel@tonic-gate static int aio_port_callback(void *, int *, pid_t, int, void *); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1357c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #ifdef _LP64 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent = { 1407c478bd9Sstevel@tonic-gate 6, 1417c478bd9Sstevel@tonic-gate SE_NOUNLOAD | SE_64RVAL | SE_ARGC, 1427c478bd9Sstevel@tonic-gate (int (*)())kaioc 1437c478bd9Sstevel@tonic-gate }; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1467c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent32 = { 1477c478bd9Sstevel@tonic-gate 7, 1487c478bd9Sstevel@tonic-gate SE_NOUNLOAD | SE_64RVAL, 1497c478bd9Sstevel@tonic-gate kaio 1507c478bd9Sstevel@tonic-gate }; 1517c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate #else /* _LP64 */ 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent = { 1567c478bd9Sstevel@tonic-gate 7, 1577c478bd9Sstevel@tonic-gate SE_NOUNLOAD | SE_32RVAL1, 1587c478bd9Sstevel@tonic-gate kaio 1597c478bd9Sstevel@tonic-gate }; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate static struct modlsys modlsys = { 1687c478bd9Sstevel@tonic-gate &mod_syscallops, 1697c478bd9Sstevel@tonic-gate "kernel Async I/O", 1707c478bd9Sstevel@tonic-gate &kaio_sysent 1717c478bd9Sstevel@tonic-gate }; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1747c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = { 1757c478bd9Sstevel@tonic-gate &mod_syscallops32, 1767c478bd9Sstevel@tonic-gate "kernel Async I/O for 32 bit compatibility", 1777c478bd9Sstevel@tonic-gate &kaio_sysent32 1787c478bd9Sstevel@tonic-gate }; 1797c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1837c478bd9Sstevel@tonic-gate MODREV_1, 1847c478bd9Sstevel@tonic-gate &modlsys, 1857c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1867c478bd9Sstevel@tonic-gate &modlsys32, 1877c478bd9Sstevel@tonic-gate #endif 1887c478bd9Sstevel@tonic-gate NULL 1897c478bd9Sstevel@tonic-gate }; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate int 1927c478bd9Sstevel@tonic-gate _init(void) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate int retval; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if ((retval = mod_install(&modlinkage)) != 0) 1977c478bd9Sstevel@tonic-gate return (retval); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate int 2037c478bd9Sstevel@tonic-gate _fini(void) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate int retval; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate retval = mod_remove(&modlinkage); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate return (retval); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate int 2137c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate #ifdef _LP64 2197c478bd9Sstevel@tonic-gate static int64_t 2207c478bd9Sstevel@tonic-gate kaioc( 2217c478bd9Sstevel@tonic-gate long a0, 2227c478bd9Sstevel@tonic-gate long a1, 2237c478bd9Sstevel@tonic-gate long a2, 2247c478bd9Sstevel@tonic-gate long a3, 2257c478bd9Sstevel@tonic-gate long a4, 2267c478bd9Sstevel@tonic-gate long a5) 2277c478bd9Sstevel@tonic-gate { 2287c478bd9Sstevel@tonic-gate int error; 2297c478bd9Sstevel@tonic-gate long rval = 0; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate switch ((int)a0 & ~AIO_POLL_BIT) { 2327c478bd9Sstevel@tonic-gate case AIOREAD: 2337c478bd9Sstevel@tonic-gate error = arw((int)a0, (int)a1, (char *)a2, (int)a3, 2347c478bd9Sstevel@tonic-gate (offset_t)a4, (aio_result_t *)a5, FREAD); 2357c478bd9Sstevel@tonic-gate break; 2367c478bd9Sstevel@tonic-gate case AIOWRITE: 2377c478bd9Sstevel@tonic-gate error = arw((int)a0, (int)a1, (char *)a2, (int)a3, 2387c478bd9Sstevel@tonic-gate (offset_t)a4, (aio_result_t *)a5, FWRITE); 2397c478bd9Sstevel@tonic-gate break; 2407c478bd9Sstevel@tonic-gate case AIOWAIT: 2417c478bd9Sstevel@tonic-gate error = aiowait((struct timeval *)a1, (int)a2, &rval); 2427c478bd9Sstevel@tonic-gate break; 2437c478bd9Sstevel@tonic-gate case AIOWAITN: 2447c478bd9Sstevel@tonic-gate error = aiowaitn((void *)a1, (uint_t)a2, (uint_t *)a3, 2457c478bd9Sstevel@tonic-gate (timespec_t *)a4); 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate case AIONOTIFY: 2487c478bd9Sstevel@tonic-gate error = aionotify(); 2497c478bd9Sstevel@tonic-gate break; 2507c478bd9Sstevel@tonic-gate case AIOINIT: 2517c478bd9Sstevel@tonic-gate error = aioinit(); 2527c478bd9Sstevel@tonic-gate break; 2537c478bd9Sstevel@tonic-gate case AIOSTART: 2547c478bd9Sstevel@tonic-gate error = aiostart(); 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate case AIOLIO: 25734709573Sraf error = alio((int)a1, (aiocb_t **)a2, (int)a3, 2587c478bd9Sstevel@tonic-gate (struct sigevent *)a4); 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate case AIOLIOWAIT: 2617c478bd9Sstevel@tonic-gate error = aliowait((int)a1, (void *)a2, (int)a3, 2627c478bd9Sstevel@tonic-gate (struct sigevent *)a4, AIO_64); 2637c478bd9Sstevel@tonic-gate break; 2647c478bd9Sstevel@tonic-gate case AIOSUSPEND: 2657c478bd9Sstevel@tonic-gate error = aiosuspend((void *)a1, (int)a2, (timespec_t *)a3, 2667c478bd9Sstevel@tonic-gate (int)a4, &rval, AIO_64); 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate case AIOERROR: 2697c478bd9Sstevel@tonic-gate error = aioerror((void *)a1, AIO_64); 2707c478bd9Sstevel@tonic-gate break; 2717c478bd9Sstevel@tonic-gate case AIOAREAD: 2727c478bd9Sstevel@tonic-gate error = aiorw((int)a0, (void *)a1, FREAD, AIO_64); 2737c478bd9Sstevel@tonic-gate break; 2747c478bd9Sstevel@tonic-gate case AIOAWRITE: 2757c478bd9Sstevel@tonic-gate error = aiorw((int)a0, (void *)a1, FWRITE, AIO_64); 2767c478bd9Sstevel@tonic-gate break; 2777c478bd9Sstevel@tonic-gate case AIOCANCEL: 2787c478bd9Sstevel@tonic-gate error = aio_cancel((int)a1, (void *)a2, &rval, AIO_64); 2797c478bd9Sstevel@tonic-gate break; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * The large file related stuff is valid only for 2837c478bd9Sstevel@tonic-gate * 32 bit kernel and not for 64 bit kernel 2847c478bd9Sstevel@tonic-gate * On 64 bit kernel we convert large file calls 2857c478bd9Sstevel@tonic-gate * to regular 64bit calls. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate default: 2897c478bd9Sstevel@tonic-gate error = EINVAL; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate if (error) 2927c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 2937c478bd9Sstevel@tonic-gate return (rval); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate #endif 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate static int 2987c478bd9Sstevel@tonic-gate kaio( 2997c478bd9Sstevel@tonic-gate ulong_t *uap, 3007c478bd9Sstevel@tonic-gate rval_t *rvp) 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate long rval = 0; 3037c478bd9Sstevel@tonic-gate int error = 0; 3047c478bd9Sstevel@tonic-gate offset_t off; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate rvp->r_vals = 0; 3087c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 3097c478bd9Sstevel@tonic-gate off = ((u_offset_t)uap[5] << 32) | (u_offset_t)uap[4]; 3107c478bd9Sstevel@tonic-gate #else 3117c478bd9Sstevel@tonic-gate off = ((u_offset_t)uap[4] << 32) | (u_offset_t)uap[5]; 3127c478bd9Sstevel@tonic-gate #endif 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate switch (uap[0] & ~AIO_POLL_BIT) { 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * It must be the 32 bit system call on 64 bit kernel 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate case AIOREAD: 3197c478bd9Sstevel@tonic-gate return (arw((int)uap[0], (int)uap[1], (char *)uap[2], 3207c478bd9Sstevel@tonic-gate (int)uap[3], off, (aio_result_t *)uap[6], FREAD)); 3217c478bd9Sstevel@tonic-gate case AIOWRITE: 3227c478bd9Sstevel@tonic-gate return (arw((int)uap[0], (int)uap[1], (char *)uap[2], 3237c478bd9Sstevel@tonic-gate (int)uap[3], off, (aio_result_t *)uap[6], FWRITE)); 3247c478bd9Sstevel@tonic-gate case AIOWAIT: 3257c478bd9Sstevel@tonic-gate error = aiowait((struct timeval *)uap[1], (int)uap[2], 3267c478bd9Sstevel@tonic-gate &rval); 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate case AIOWAITN: 3297c478bd9Sstevel@tonic-gate error = aiowaitn((void *)uap[1], (uint_t)uap[2], 3307c478bd9Sstevel@tonic-gate (uint_t *)uap[3], (timespec_t *)uap[4]); 3317c478bd9Sstevel@tonic-gate break; 3327c478bd9Sstevel@tonic-gate case AIONOTIFY: 3337c478bd9Sstevel@tonic-gate return (aionotify()); 3347c478bd9Sstevel@tonic-gate case AIOINIT: 3357c478bd9Sstevel@tonic-gate return (aioinit()); 3367c478bd9Sstevel@tonic-gate case AIOSTART: 3377c478bd9Sstevel@tonic-gate return (aiostart()); 3387c478bd9Sstevel@tonic-gate case AIOLIO: 3397c478bd9Sstevel@tonic-gate return (alio32((int)uap[1], (void *)uap[2], (int)uap[3], 3407c478bd9Sstevel@tonic-gate (void *)uap[4])); 3417c478bd9Sstevel@tonic-gate case AIOLIOWAIT: 3427c478bd9Sstevel@tonic-gate return (aliowait((int)uap[1], (void *)uap[2], 3437c478bd9Sstevel@tonic-gate (int)uap[3], (struct sigevent *)uap[4], AIO_32)); 3447c478bd9Sstevel@tonic-gate case AIOSUSPEND: 3457c478bd9Sstevel@tonic-gate error = aiosuspend((void *)uap[1], (int)uap[2], 3467c478bd9Sstevel@tonic-gate (timespec_t *)uap[3], (int)uap[4], 3477c478bd9Sstevel@tonic-gate &rval, AIO_32); 3487c478bd9Sstevel@tonic-gate break; 3497c478bd9Sstevel@tonic-gate case AIOERROR: 3507c478bd9Sstevel@tonic-gate return (aioerror((void *)uap[1], AIO_32)); 3517c478bd9Sstevel@tonic-gate case AIOAREAD: 3527c478bd9Sstevel@tonic-gate return (aiorw((int)uap[0], (void *)uap[1], 3537c478bd9Sstevel@tonic-gate FREAD, AIO_32)); 3547c478bd9Sstevel@tonic-gate case AIOAWRITE: 3557c478bd9Sstevel@tonic-gate return (aiorw((int)uap[0], (void *)uap[1], 3567c478bd9Sstevel@tonic-gate FWRITE, AIO_32)); 3577c478bd9Sstevel@tonic-gate case AIOCANCEL: 3587c478bd9Sstevel@tonic-gate error = (aio_cancel((int)uap[1], (void *)uap[2], &rval, 3597c478bd9Sstevel@tonic-gate AIO_32)); 3607c478bd9Sstevel@tonic-gate break; 3617c478bd9Sstevel@tonic-gate case AIOLIO64: 3627c478bd9Sstevel@tonic-gate return (alioLF((int)uap[1], (void *)uap[2], 3637c478bd9Sstevel@tonic-gate (int)uap[3], (void *)uap[4])); 3647c478bd9Sstevel@tonic-gate case AIOLIOWAIT64: 3657c478bd9Sstevel@tonic-gate return (aliowait(uap[1], (void *)uap[2], 3667c478bd9Sstevel@tonic-gate (int)uap[3], (void *)uap[4], AIO_LARGEFILE)); 3677c478bd9Sstevel@tonic-gate case AIOSUSPEND64: 3687c478bd9Sstevel@tonic-gate error = aiosuspend((void *)uap[1], (int)uap[2], 3697c478bd9Sstevel@tonic-gate (timespec_t *)uap[3], (int)uap[4], &rval, 3707c478bd9Sstevel@tonic-gate AIO_LARGEFILE); 3717c478bd9Sstevel@tonic-gate break; 3727c478bd9Sstevel@tonic-gate case AIOERROR64: 3737c478bd9Sstevel@tonic-gate return (aioerror((void *)uap[1], AIO_LARGEFILE)); 3747c478bd9Sstevel@tonic-gate case AIOAREAD64: 3757c478bd9Sstevel@tonic-gate return (aiorw((int)uap[0], (void *)uap[1], FREAD, 3767c478bd9Sstevel@tonic-gate AIO_LARGEFILE)); 3777c478bd9Sstevel@tonic-gate case AIOAWRITE64: 3787c478bd9Sstevel@tonic-gate return (aiorw((int)uap[0], (void *)uap[1], FWRITE, 3797c478bd9Sstevel@tonic-gate AIO_LARGEFILE)); 3807c478bd9Sstevel@tonic-gate case AIOCANCEL64: 3817c478bd9Sstevel@tonic-gate error = (aio_cancel((int)uap[1], (void *)uap[2], 3827c478bd9Sstevel@tonic-gate &rval, AIO_LARGEFILE)); 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate default: 3857c478bd9Sstevel@tonic-gate return (EINVAL); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate rvp->r_val1 = rval; 3897c478bd9Sstevel@tonic-gate return (error); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * wake up LWPs in this process that are sleeping in 3947c478bd9Sstevel@tonic-gate * aiowait(). 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate static int 3977c478bd9Sstevel@tonic-gate aionotify(void) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate aio_t *aiop; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 4027c478bd9Sstevel@tonic-gate if (aiop == NULL) 4037c478bd9Sstevel@tonic-gate return (0); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 4067c478bd9Sstevel@tonic-gate aiop->aio_notifycnt++; 4077c478bd9Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv); 4087c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate return (0); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate static int 4147c478bd9Sstevel@tonic-gate timeval2reltime(struct timeval *timout, timestruc_t *rqtime, 4157c478bd9Sstevel@tonic-gate timestruc_t **rqtp, int *blocking) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4187c478bd9Sstevel@tonic-gate struct timeval32 wait_time_32; 4197c478bd9Sstevel@tonic-gate #endif 4207c478bd9Sstevel@tonic-gate struct timeval wait_time; 4217c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate *rqtp = NULL; 4247c478bd9Sstevel@tonic-gate if (timout == NULL) { /* wait indefinitely */ 4257c478bd9Sstevel@tonic-gate *blocking = 1; 4267c478bd9Sstevel@tonic-gate return (0); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Need to correctly compare with the -1 passed in for a user 4317c478bd9Sstevel@tonic-gate * address pointer, with both 32 bit and 64 bit apps. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 4347c478bd9Sstevel@tonic-gate if ((intptr_t)timout == (intptr_t)-1) { /* don't wait */ 4357c478bd9Sstevel@tonic-gate *blocking = 0; 4367c478bd9Sstevel@tonic-gate return (0); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if (copyin(timout, &wait_time, sizeof (wait_time))) 4407c478bd9Sstevel@tonic-gate return (EFAULT); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4437c478bd9Sstevel@tonic-gate else { 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * -1 from a 32bit app. It will not get sign extended. 4467c478bd9Sstevel@tonic-gate * don't wait if -1. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate if ((intptr_t)timout == (intptr_t)((uint32_t)-1)) { 4497c478bd9Sstevel@tonic-gate *blocking = 0; 4507c478bd9Sstevel@tonic-gate return (0); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (copyin(timout, &wait_time_32, sizeof (wait_time_32))) 4547c478bd9Sstevel@tonic-gate return (EFAULT); 4557c478bd9Sstevel@tonic-gate TIMEVAL32_TO_TIMEVAL(&wait_time, &wait_time_32); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (wait_time.tv_sec == 0 && wait_time.tv_usec == 0) { /* don't wait */ 4607c478bd9Sstevel@tonic-gate *blocking = 0; 4617c478bd9Sstevel@tonic-gate return (0); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate if (wait_time.tv_sec < 0 || 4657c478bd9Sstevel@tonic-gate wait_time.tv_usec < 0 || wait_time.tv_usec >= MICROSEC) 4667c478bd9Sstevel@tonic-gate return (EINVAL); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate rqtime->tv_sec = wait_time.tv_sec; 4697c478bd9Sstevel@tonic-gate rqtime->tv_nsec = wait_time.tv_usec * 1000; 4707c478bd9Sstevel@tonic-gate *rqtp = rqtime; 4717c478bd9Sstevel@tonic-gate *blocking = 1; 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate return (0); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate static int 4777c478bd9Sstevel@tonic-gate timespec2reltime(timespec_t *timout, timestruc_t *rqtime, 4787c478bd9Sstevel@tonic-gate timestruc_t **rqtp, int *blocking) 4797c478bd9Sstevel@tonic-gate { 4807c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4817c478bd9Sstevel@tonic-gate timespec32_t wait_time_32; 4827c478bd9Sstevel@tonic-gate #endif 4837c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate *rqtp = NULL; 4867c478bd9Sstevel@tonic-gate if (timout == NULL) { 4877c478bd9Sstevel@tonic-gate *blocking = 1; 4887c478bd9Sstevel@tonic-gate return (0); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 4927c478bd9Sstevel@tonic-gate if (copyin(timout, rqtime, sizeof (*rqtime))) 4937c478bd9Sstevel@tonic-gate return (EFAULT); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4967c478bd9Sstevel@tonic-gate else { 4977c478bd9Sstevel@tonic-gate if (copyin(timout, &wait_time_32, sizeof (wait_time_32))) 4987c478bd9Sstevel@tonic-gate return (EFAULT); 4997c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(rqtime, &wait_time_32); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate if (rqtime->tv_sec == 0 && rqtime->tv_nsec == 0) { 5047c478bd9Sstevel@tonic-gate *blocking = 0; 5057c478bd9Sstevel@tonic-gate return (0); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if (rqtime->tv_sec < 0 || 5097c478bd9Sstevel@tonic-gate rqtime->tv_nsec < 0 || rqtime->tv_nsec >= NANOSEC) 5107c478bd9Sstevel@tonic-gate return (EINVAL); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate *rqtp = rqtime; 5137c478bd9Sstevel@tonic-gate *blocking = 1; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate return (0); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5197c478bd9Sstevel@tonic-gate static int 5207c478bd9Sstevel@tonic-gate aiowait( 5217c478bd9Sstevel@tonic-gate struct timeval *timout, 5227c478bd9Sstevel@tonic-gate int dontblockflg, 5237c478bd9Sstevel@tonic-gate long *rval) 5247c478bd9Sstevel@tonic-gate { 5257c478bd9Sstevel@tonic-gate int error; 5267c478bd9Sstevel@tonic-gate aio_t *aiop; 5277c478bd9Sstevel@tonic-gate aio_req_t *reqp; 5287c478bd9Sstevel@tonic-gate clock_t status; 5297c478bd9Sstevel@tonic-gate int blocking; 5303348528fSdm120769 int timecheck; 5317c478bd9Sstevel@tonic-gate timestruc_t rqtime; 5327c478bd9Sstevel@tonic-gate timestruc_t *rqtp; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 5357c478bd9Sstevel@tonic-gate if (aiop == NULL) 5367c478bd9Sstevel@tonic-gate return (EINVAL); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * Establish the absolute future time for the timeout. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate error = timeval2reltime(timout, &rqtime, &rqtp, &blocking); 5427c478bd9Sstevel@tonic-gate if (error) 5437c478bd9Sstevel@tonic-gate return (error); 5447c478bd9Sstevel@tonic-gate if (rqtp) { 5457c478bd9Sstevel@tonic-gate timestruc_t now; 5463348528fSdm120769 timecheck = timechanged; 5477c478bd9Sstevel@tonic-gate gethrestime(&now); 5487c478bd9Sstevel@tonic-gate timespecadd(rqtp, &now); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 5527c478bd9Sstevel@tonic-gate for (;;) { 5537c478bd9Sstevel@tonic-gate /* process requests on poll queue */ 5547c478bd9Sstevel@tonic-gate if (aiop->aio_pollq) { 5557c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 5567c478bd9Sstevel@tonic-gate aio_cleanup(0); 5577c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate if ((reqp = aio_req_remove(NULL)) != NULL) { 5607c478bd9Sstevel@tonic-gate *rval = (long)reqp->aio_req_resultp; 5617c478bd9Sstevel@tonic-gate break; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate /* user-level done queue might not be empty */ 5647c478bd9Sstevel@tonic-gate if (aiop->aio_notifycnt > 0) { 5657c478bd9Sstevel@tonic-gate aiop->aio_notifycnt--; 5667c478bd9Sstevel@tonic-gate *rval = 1; 5677c478bd9Sstevel@tonic-gate break; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate /* don't block if no outstanding aio */ 5707c478bd9Sstevel@tonic-gate if (aiop->aio_outstanding == 0 && dontblockflg) { 5717c478bd9Sstevel@tonic-gate error = EINVAL; 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate if (blocking) { 5757c478bd9Sstevel@tonic-gate status = cv_waituntil_sig(&aiop->aio_waitcv, 5763348528fSdm120769 &aiop->aio_mutex, rqtp, timecheck); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (status > 0) /* check done queue again */ 5797c478bd9Sstevel@tonic-gate continue; 5807c478bd9Sstevel@tonic-gate if (status == 0) { /* interrupted by a signal */ 5817c478bd9Sstevel@tonic-gate error = EINTR; 5827c478bd9Sstevel@tonic-gate *rval = -1; 5837c478bd9Sstevel@tonic-gate } else { /* timer expired */ 5847c478bd9Sstevel@tonic-gate error = ETIME; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 5907c478bd9Sstevel@tonic-gate if (reqp) { 5917c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 5927c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 5937c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 5947c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 5957c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate return (error); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * aiowaitn can be used to reap completed asynchronous requests submitted with 6027c478bd9Sstevel@tonic-gate * lio_listio, aio_read or aio_write. 6037c478bd9Sstevel@tonic-gate * This function only reaps asynchronous raw I/Os. 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6077c478bd9Sstevel@tonic-gate static int 6087c478bd9Sstevel@tonic-gate aiowaitn(void *uiocb, uint_t nent, uint_t *nwait, timespec_t *timout) 6097c478bd9Sstevel@tonic-gate { 6107c478bd9Sstevel@tonic-gate int error = 0; 6117c478bd9Sstevel@tonic-gate aio_t *aiop; 6127c478bd9Sstevel@tonic-gate aio_req_t *reqlist = NULL; 6137c478bd9Sstevel@tonic-gate caddr_t iocblist = NULL; /* array of iocb ptr's */ 6147c478bd9Sstevel@tonic-gate uint_t waitcnt, cnt = 0; /* iocb cnt */ 6157c478bd9Sstevel@tonic-gate size_t iocbsz; /* users iocb size */ 6167c478bd9Sstevel@tonic-gate size_t riocbsz; /* returned iocb size */ 6177c478bd9Sstevel@tonic-gate int iocb_index = 0; 6187c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 6197c478bd9Sstevel@tonic-gate int blocking = 1; 6203348528fSdm120769 int timecheck; 6217c478bd9Sstevel@tonic-gate timestruc_t rqtime; 6227c478bd9Sstevel@tonic-gate timestruc_t *rqtp; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 625dd1e66b6SVamsi Nagineni if (aiop == NULL || nent == 0 || nent > _AIO_LISTIO_MAX) 626dd1e66b6SVamsi Nagineni return (EINVAL); 6277c478bd9Sstevel@tonic-gate 628dd1e66b6SVamsi Nagineni if (aiop->aio_outstanding == 0) 6297c478bd9Sstevel@tonic-gate return (EAGAIN); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (copyin(nwait, &waitcnt, sizeof (uint_t))) 6327c478bd9Sstevel@tonic-gate return (EFAULT); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* set *nwait to zero, if we must return prematurely */ 6357c478bd9Sstevel@tonic-gate if (copyout(&cnt, nwait, sizeof (uint_t))) 6367c478bd9Sstevel@tonic-gate return (EFAULT); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate if (waitcnt == 0) { 6397c478bd9Sstevel@tonic-gate blocking = 0; 6407c478bd9Sstevel@tonic-gate rqtp = NULL; 6417c478bd9Sstevel@tonic-gate waitcnt = nent; 6427c478bd9Sstevel@tonic-gate } else { 6437c478bd9Sstevel@tonic-gate error = timespec2reltime(timout, &rqtime, &rqtp, &blocking); 6447c478bd9Sstevel@tonic-gate if (error) 6457c478bd9Sstevel@tonic-gate return (error); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 6497c478bd9Sstevel@tonic-gate iocbsz = (sizeof (aiocb_t *) * nent); 6507c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 6517c478bd9Sstevel@tonic-gate else 6527c478bd9Sstevel@tonic-gate iocbsz = (sizeof (caddr32_t) * nent); 6537c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * Only one aio_waitn call is allowed at a time. 6577c478bd9Sstevel@tonic-gate * The active aio_waitn will collect all requests 6587c478bd9Sstevel@tonic-gate * out of the "done" list and if necessary it will wait 6597c478bd9Sstevel@tonic-gate * for some/all pending requests to fulfill the nwait 6607c478bd9Sstevel@tonic-gate * parameter. 6617c478bd9Sstevel@tonic-gate * A second or further aio_waitn calls will sleep here 6627c478bd9Sstevel@tonic-gate * until the active aio_waitn finishes and leaves the kernel 6637c478bd9Sstevel@tonic-gate * If the second call does not block (poll), then return 6647c478bd9Sstevel@tonic-gate * immediately with the error code : EAGAIN. 6657c478bd9Sstevel@tonic-gate * If the second call should block, then sleep here, but 6667c478bd9Sstevel@tonic-gate * do not touch the timeout. The timeout starts when this 6677c478bd9Sstevel@tonic-gate * aio_waitn-call becomes active. 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate while (aiop->aio_flags & AIO_WAITN) { 6737c478bd9Sstevel@tonic-gate if (blocking == 0) { 6747c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 6757c478bd9Sstevel@tonic-gate return (EAGAIN); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* block, no timeout */ 6797c478bd9Sstevel@tonic-gate aiop->aio_flags |= AIO_WAITN_PENDING; 6807c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&aiop->aio_waitncv, &aiop->aio_mutex)) { 6817c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 6827c478bd9Sstevel@tonic-gate return (EINTR); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * Establish the absolute future time for the timeout. 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate if (rqtp) { 6907c478bd9Sstevel@tonic-gate timestruc_t now; 6913348528fSdm120769 timecheck = timechanged; 6927c478bd9Sstevel@tonic-gate gethrestime(&now); 6937c478bd9Sstevel@tonic-gate timespecadd(rqtp, &now); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate if (iocbsz > aiop->aio_iocbsz && aiop->aio_iocb != NULL) { 6977c478bd9Sstevel@tonic-gate kmem_free(aiop->aio_iocb, aiop->aio_iocbsz); 6987c478bd9Sstevel@tonic-gate aiop->aio_iocb = NULL; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (aiop->aio_iocb == NULL) { 7027c478bd9Sstevel@tonic-gate iocblist = kmem_zalloc(iocbsz, KM_NOSLEEP); 7037c478bd9Sstevel@tonic-gate if (iocblist == NULL) { 7047c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 7057c478bd9Sstevel@tonic-gate return (ENOMEM); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate aiop->aio_iocb = (aiocb_t **)iocblist; 7087c478bd9Sstevel@tonic-gate aiop->aio_iocbsz = iocbsz; 7097c478bd9Sstevel@tonic-gate } else { 7107c478bd9Sstevel@tonic-gate iocblist = (char *)aiop->aio_iocb; 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate aiop->aio_waitncnt = waitcnt; 7147c478bd9Sstevel@tonic-gate aiop->aio_flags |= AIO_WAITN; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate for (;;) { 7177c478bd9Sstevel@tonic-gate /* push requests on poll queue to done queue */ 7187c478bd9Sstevel@tonic-gate if (aiop->aio_pollq) { 7197c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 7207c478bd9Sstevel@tonic-gate aio_cleanup(0); 7217c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* check for requests on done queue */ 7257c478bd9Sstevel@tonic-gate if (aiop->aio_doneq) { 7267c478bd9Sstevel@tonic-gate cnt += aio_reqlist_concat(aiop, &reqlist, nent - cnt); 7277c478bd9Sstevel@tonic-gate aiop->aio_waitncnt = waitcnt - cnt; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* user-level done queue might not be empty */ 7317c478bd9Sstevel@tonic-gate if (aiop->aio_notifycnt > 0) { 7327c478bd9Sstevel@tonic-gate aiop->aio_notifycnt--; 7337c478bd9Sstevel@tonic-gate error = 0; 7347c478bd9Sstevel@tonic-gate break; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * if we are here second time as a result of timer 7397c478bd9Sstevel@tonic-gate * expiration, we reset error if there are enough 7407c478bd9Sstevel@tonic-gate * aiocb's to satisfy request. 7417c478bd9Sstevel@tonic-gate * We return also if all requests are already done 7427c478bd9Sstevel@tonic-gate * and we picked up the whole done queue. 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if ((cnt >= waitcnt) || (cnt > 0 && aiop->aio_pending == 0 && 7467c478bd9Sstevel@tonic-gate aiop->aio_doneq == NULL)) { 7477c478bd9Sstevel@tonic-gate error = 0; 7487c478bd9Sstevel@tonic-gate break; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate if ((cnt < waitcnt) && blocking) { 7527c478bd9Sstevel@tonic-gate int rval = cv_waituntil_sig(&aiop->aio_waitcv, 7533348528fSdm120769 &aiop->aio_mutex, rqtp, timecheck); 7547c478bd9Sstevel@tonic-gate if (rval > 0) 7557c478bd9Sstevel@tonic-gate continue; 7567c478bd9Sstevel@tonic-gate if (rval < 0) { 7577c478bd9Sstevel@tonic-gate error = ETIME; 7587c478bd9Sstevel@tonic-gate blocking = 0; 7597c478bd9Sstevel@tonic-gate continue; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate error = EINTR; 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if (cnt > 0) { 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate iocb_index = aio_unlock_requests(iocblist, iocb_index, reqlist, 7717c478bd9Sstevel@tonic-gate aiop, model); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 7747c478bd9Sstevel@tonic-gate riocbsz = (sizeof (aiocb_t *) * cnt); 7757c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 7767c478bd9Sstevel@tonic-gate else 7777c478bd9Sstevel@tonic-gate riocbsz = (sizeof (caddr32_t) * cnt); 7787c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate if (copyout(iocblist, uiocb, riocbsz) || 7817c478bd9Sstevel@tonic-gate copyout(&cnt, nwait, sizeof (uint_t))) 7827c478bd9Sstevel@tonic-gate error = EFAULT; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* check if there is another thread waiting for execution */ 7867c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 7877c478bd9Sstevel@tonic-gate aiop->aio_flags &= ~AIO_WAITN; 7887c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_WAITN_PENDING) { 7897c478bd9Sstevel@tonic-gate aiop->aio_flags &= ~AIO_WAITN_PENDING; 7907c478bd9Sstevel@tonic-gate cv_signal(&aiop->aio_waitncv); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate return (error); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7987c478bd9Sstevel@tonic-gate * aio_unlock_requests 7997c478bd9Sstevel@tonic-gate * copyouts the result of the request as well as the return value. 8007c478bd9Sstevel@tonic-gate * It builds the list of completed asynchronous requests, 8017c478bd9Sstevel@tonic-gate * unlocks the allocated memory ranges and 8027c478bd9Sstevel@tonic-gate * put the aio request structure back into the free list. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate static int 8067c478bd9Sstevel@tonic-gate aio_unlock_requests( 8077c478bd9Sstevel@tonic-gate caddr_t iocblist, 8087c478bd9Sstevel@tonic-gate int iocb_index, 8097c478bd9Sstevel@tonic-gate aio_req_t *reqlist, 8107c478bd9Sstevel@tonic-gate aio_t *aiop, 8117c478bd9Sstevel@tonic-gate model_t model) 8127c478bd9Sstevel@tonic-gate { 8137c478bd9Sstevel@tonic-gate aio_req_t *reqp, *nreqp; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 8167c478bd9Sstevel@tonic-gate for (reqp = reqlist; reqp != NULL; reqp = nreqp) { 8177c478bd9Sstevel@tonic-gate (((caddr_t *)iocblist)[iocb_index++]) = 8187c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb; 8197c478bd9Sstevel@tonic-gate nreqp = reqp->aio_req_next; 8207c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 8217c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 8227c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 8237c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 8247c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 8287c478bd9Sstevel@tonic-gate else { 8297c478bd9Sstevel@tonic-gate for (reqp = reqlist; reqp != NULL; reqp = nreqp) { 8307c478bd9Sstevel@tonic-gate ((caddr32_t *)iocblist)[iocb_index++] = 8317c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb32; 8327c478bd9Sstevel@tonic-gate nreqp = reqp->aio_req_next; 8337c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 8347c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 8357c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 8367c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 8377c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 8417c478bd9Sstevel@tonic-gate return (iocb_index); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * aio_reqlist_concat 8467c478bd9Sstevel@tonic-gate * moves "max" elements from the done queue to the reqlist queue and removes 8477c478bd9Sstevel@tonic-gate * the AIO_DONEQ flag. 8487c478bd9Sstevel@tonic-gate * - reqlist queue is a simple linked list 8497c478bd9Sstevel@tonic-gate * - done queue is a double linked list 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate static int 8537c478bd9Sstevel@tonic-gate aio_reqlist_concat(aio_t *aiop, aio_req_t **reqlist, int max) 8547c478bd9Sstevel@tonic-gate { 8557c478bd9Sstevel@tonic-gate aio_req_t *q2, *q2work, *list; 8567c478bd9Sstevel@tonic-gate int count = 0; 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate list = *reqlist; 8597c478bd9Sstevel@tonic-gate q2 = aiop->aio_doneq; 8607c478bd9Sstevel@tonic-gate q2work = q2; 8617c478bd9Sstevel@tonic-gate while (max-- > 0) { 8627c478bd9Sstevel@tonic-gate q2work->aio_req_flags &= ~AIO_DONEQ; 8637c478bd9Sstevel@tonic-gate q2work = q2work->aio_req_next; 8647c478bd9Sstevel@tonic-gate count++; 8657c478bd9Sstevel@tonic-gate if (q2work == q2) 8667c478bd9Sstevel@tonic-gate break; 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (q2work == q2) { 8707c478bd9Sstevel@tonic-gate /* all elements revised */ 8717c478bd9Sstevel@tonic-gate q2->aio_req_prev->aio_req_next = list; 8727c478bd9Sstevel@tonic-gate list = q2; 8737c478bd9Sstevel@tonic-gate aiop->aio_doneq = NULL; 8747c478bd9Sstevel@tonic-gate } else { 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * max < elements in the doneq 8777c478bd9Sstevel@tonic-gate * detach only the required amount of elements 8787c478bd9Sstevel@tonic-gate * out of the doneq 8797c478bd9Sstevel@tonic-gate */ 8807c478bd9Sstevel@tonic-gate q2work->aio_req_prev->aio_req_next = list; 8817c478bd9Sstevel@tonic-gate list = q2; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate aiop->aio_doneq = q2work; 8847c478bd9Sstevel@tonic-gate q2work->aio_req_prev = q2->aio_req_prev; 8857c478bd9Sstevel@tonic-gate q2->aio_req_prev->aio_req_next = q2work; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate *reqlist = list; 8887c478bd9Sstevel@tonic-gate return (count); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8927c478bd9Sstevel@tonic-gate static int 8937c478bd9Sstevel@tonic-gate aiosuspend( 8947c478bd9Sstevel@tonic-gate void *aiocb, 8957c478bd9Sstevel@tonic-gate int nent, 8967c478bd9Sstevel@tonic-gate struct timespec *timout, 8977c478bd9Sstevel@tonic-gate int flag, 8987c478bd9Sstevel@tonic-gate long *rval, 8997c478bd9Sstevel@tonic-gate int run_mode) 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate int error; 9027c478bd9Sstevel@tonic-gate aio_t *aiop; 9037c478bd9Sstevel@tonic-gate aio_req_t *reqp, *found, *next; 9047c478bd9Sstevel@tonic-gate caddr_t cbplist = NULL; 9057c478bd9Sstevel@tonic-gate aiocb_t *cbp, **ucbp; 9067c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 9077c478bd9Sstevel@tonic-gate aiocb32_t *cbp32; 9087c478bd9Sstevel@tonic-gate caddr32_t *ucbp32; 9097c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9107c478bd9Sstevel@tonic-gate aiocb64_32_t *cbp64; 9117c478bd9Sstevel@tonic-gate int rv; 9127c478bd9Sstevel@tonic-gate int i; 9137c478bd9Sstevel@tonic-gate size_t ssize; 9147c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 9157c478bd9Sstevel@tonic-gate int blocking; 9163348528fSdm120769 int timecheck; 9177c478bd9Sstevel@tonic-gate timestruc_t rqtime; 9187c478bd9Sstevel@tonic-gate timestruc_t *rqtp; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 921dd1e66b6SVamsi Nagineni if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX) 9227c478bd9Sstevel@tonic-gate return (EINVAL); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * Establish the absolute future time for the timeout. 9267c478bd9Sstevel@tonic-gate */ 9277c478bd9Sstevel@tonic-gate error = timespec2reltime(timout, &rqtime, &rqtp, &blocking); 9287c478bd9Sstevel@tonic-gate if (error) 9297c478bd9Sstevel@tonic-gate return (error); 9307c478bd9Sstevel@tonic-gate if (rqtp) { 9317c478bd9Sstevel@tonic-gate timestruc_t now; 9323348528fSdm120769 timecheck = timechanged; 9337c478bd9Sstevel@tonic-gate gethrestime(&now); 9347c478bd9Sstevel@tonic-gate timespecadd(rqtp, &now); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * If we are not blocking and there's no IO complete 9397c478bd9Sstevel@tonic-gate * skip aiocb copyin. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate if (!blocking && (aiop->aio_pollq == NULL) && 9427c478bd9Sstevel@tonic-gate (aiop->aio_doneq == NULL)) { 9437c478bd9Sstevel@tonic-gate return (EAGAIN); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 9477c478bd9Sstevel@tonic-gate ssize = (sizeof (aiocb_t *) * nent); 9487c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 9497c478bd9Sstevel@tonic-gate else 9507c478bd9Sstevel@tonic-gate ssize = (sizeof (caddr32_t) * nent); 9517c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate cbplist = kmem_alloc(ssize, KM_NOSLEEP); 9547c478bd9Sstevel@tonic-gate if (cbplist == NULL) 9557c478bd9Sstevel@tonic-gate return (ENOMEM); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (copyin(aiocb, cbplist, ssize)) { 9587c478bd9Sstevel@tonic-gate error = EFAULT; 9597c478bd9Sstevel@tonic-gate goto done; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate found = NULL; 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * we need to get the aio_cleanupq_mutex since we call 9657c478bd9Sstevel@tonic-gate * aio_req_done(). 9667c478bd9Sstevel@tonic-gate */ 9677c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex); 9687c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 9697c478bd9Sstevel@tonic-gate for (;;) { 9707c478bd9Sstevel@tonic-gate /* push requests on poll queue to done queue */ 9717c478bd9Sstevel@tonic-gate if (aiop->aio_pollq) { 9727c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 9737c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex); 9747c478bd9Sstevel@tonic-gate aio_cleanup(0); 9757c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex); 9767c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate /* check for requests on done queue */ 9797c478bd9Sstevel@tonic-gate if (aiop->aio_doneq) { 9807c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 9817c478bd9Sstevel@tonic-gate ucbp = (aiocb_t **)cbplist; 9827c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 9837c478bd9Sstevel@tonic-gate else 9847c478bd9Sstevel@tonic-gate ucbp32 = (caddr32_t *)cbplist; 9857c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9867c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++) { 9877c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 9887c478bd9Sstevel@tonic-gate if ((cbp = *ucbp++) == NULL) 9897c478bd9Sstevel@tonic-gate continue; 9907c478bd9Sstevel@tonic-gate if (run_mode != AIO_LARGEFILE) 9917c478bd9Sstevel@tonic-gate reqp = aio_req_done( 9927c478bd9Sstevel@tonic-gate &cbp->aio_resultp); 9937c478bd9Sstevel@tonic-gate else { 9947c478bd9Sstevel@tonic-gate cbp64 = (aiocb64_32_t *)cbp; 9957c478bd9Sstevel@tonic-gate reqp = aio_req_done( 9967c478bd9Sstevel@tonic-gate &cbp64->aio_resultp); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 10007c478bd9Sstevel@tonic-gate else { 10017c478bd9Sstevel@tonic-gate if (run_mode == AIO_32) { 10027c478bd9Sstevel@tonic-gate if ((cbp32 = 10037c478bd9Sstevel@tonic-gate (aiocb32_t *)(uintptr_t) 10047c478bd9Sstevel@tonic-gate *ucbp32++) == NULL) 10057c478bd9Sstevel@tonic-gate continue; 10067c478bd9Sstevel@tonic-gate reqp = aio_req_done( 10077c478bd9Sstevel@tonic-gate &cbp32->aio_resultp); 10087c478bd9Sstevel@tonic-gate } else if (run_mode == AIO_LARGEFILE) { 10097c478bd9Sstevel@tonic-gate if ((cbp64 = 10107c478bd9Sstevel@tonic-gate (aiocb64_32_t *)(uintptr_t) 10117c478bd9Sstevel@tonic-gate *ucbp32++) == NULL) 10127c478bd9Sstevel@tonic-gate continue; 10137c478bd9Sstevel@tonic-gate reqp = aio_req_done( 10147c478bd9Sstevel@tonic-gate &cbp64->aio_resultp); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 10197c478bd9Sstevel@tonic-gate if (reqp) { 10207c478bd9Sstevel@tonic-gate reqp->aio_req_next = found; 10217c478bd9Sstevel@tonic-gate found = reqp; 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate if (aiop->aio_doneq == NULL) 10247c478bd9Sstevel@tonic-gate break; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate if (found) 10277c478bd9Sstevel@tonic-gate break; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate if (aiop->aio_notifycnt > 0) { 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * nothing on the kernel's queue. the user 10327c478bd9Sstevel@tonic-gate * has notified the kernel that it has items 10337c478bd9Sstevel@tonic-gate * on a user-level queue. 10347c478bd9Sstevel@tonic-gate */ 10357c478bd9Sstevel@tonic-gate aiop->aio_notifycnt--; 10367c478bd9Sstevel@tonic-gate *rval = 1; 10377c478bd9Sstevel@tonic-gate error = 0; 10387c478bd9Sstevel@tonic-gate break; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate /* don't block if nothing is outstanding */ 10417c478bd9Sstevel@tonic-gate if (aiop->aio_outstanding == 0) { 10427c478bd9Sstevel@tonic-gate error = EAGAIN; 10437c478bd9Sstevel@tonic-gate break; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (blocking) { 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * drop the aio_cleanupq_mutex as we are 10487c478bd9Sstevel@tonic-gate * going to block. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex); 10517c478bd9Sstevel@tonic-gate rv = cv_waituntil_sig(&aiop->aio_waitcv, 10523348528fSdm120769 &aiop->aio_mutex, rqtp, timecheck); 10537c478bd9Sstevel@tonic-gate /* 10547c478bd9Sstevel@tonic-gate * we have to drop aio_mutex and 10557c478bd9Sstevel@tonic-gate * grab it in the right order. 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 10587c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex); 10597c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 10607c478bd9Sstevel@tonic-gate if (rv > 0) /* check done queue again */ 10617c478bd9Sstevel@tonic-gate continue; 10627c478bd9Sstevel@tonic-gate if (rv == 0) /* interrupted by a signal */ 10637c478bd9Sstevel@tonic-gate error = EINTR; 10647c478bd9Sstevel@tonic-gate else /* timer expired */ 10657c478bd9Sstevel@tonic-gate error = ETIME; 10667c478bd9Sstevel@tonic-gate } else { 10677c478bd9Sstevel@tonic-gate error = EAGAIN; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate break; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 10727c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex); 10737c478bd9Sstevel@tonic-gate for (reqp = found; reqp != NULL; reqp = next) { 10747c478bd9Sstevel@tonic-gate next = reqp->aio_req_next; 10757c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 10767c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 10777c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 10787c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 10797c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate done: 10827c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 10837c478bd9Sstevel@tonic-gate return (error); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate /* 10877c478bd9Sstevel@tonic-gate * initialize aio by allocating an aio_t struct for this 10887c478bd9Sstevel@tonic-gate * process. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate static int 10917c478bd9Sstevel@tonic-gate aioinit(void) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate proc_t *p = curproc; 10947c478bd9Sstevel@tonic-gate aio_t *aiop; 10957c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 10967c478bd9Sstevel@tonic-gate if ((aiop = p->p_aio) == NULL) { 10977c478bd9Sstevel@tonic-gate aiop = aio_aiop_alloc(); 10987c478bd9Sstevel@tonic-gate p->p_aio = aiop; 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11017c478bd9Sstevel@tonic-gate if (aiop == NULL) 11027c478bd9Sstevel@tonic-gate return (ENOMEM); 11037c478bd9Sstevel@tonic-gate return (0); 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * start a special thread that will cleanup after aio requests 11087c478bd9Sstevel@tonic-gate * that are preventing a segment from being unmapped. as_unmap() 11097c478bd9Sstevel@tonic-gate * blocks until all phsyio to this segment is completed. this 11107c478bd9Sstevel@tonic-gate * doesn't happen until all the pages in this segment are not 11117c478bd9Sstevel@tonic-gate * SOFTLOCKed. Some pages will be SOFTLOCKed when there are aio 11127c478bd9Sstevel@tonic-gate * requests still outstanding. this special thread will make sure 11137c478bd9Sstevel@tonic-gate * that these SOFTLOCKed pages will eventually be SOFTUNLOCKed. 11147c478bd9Sstevel@tonic-gate * 11157c478bd9Sstevel@tonic-gate * this function will return an error if the process has only 11167c478bd9Sstevel@tonic-gate * one LWP. the assumption is that the caller is a separate LWP 11177c478bd9Sstevel@tonic-gate * that remains blocked in the kernel for the life of this process. 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate static int 11207c478bd9Sstevel@tonic-gate aiostart(void) 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate proc_t *p = curproc; 11237c478bd9Sstevel@tonic-gate aio_t *aiop; 11247c478bd9Sstevel@tonic-gate int first, error = 0; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate if (p->p_lwpcnt == 1) 11277c478bd9Sstevel@tonic-gate return (EDEADLK); 11287c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 11297c478bd9Sstevel@tonic-gate if ((aiop = p->p_aio) == NULL) 11307c478bd9Sstevel@tonic-gate error = EINVAL; 11317c478bd9Sstevel@tonic-gate else { 11327c478bd9Sstevel@tonic-gate first = aiop->aio_ok; 11337c478bd9Sstevel@tonic-gate if (aiop->aio_ok == 0) 11347c478bd9Sstevel@tonic-gate aiop->aio_ok = 1; 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11377c478bd9Sstevel@tonic-gate if (error == 0 && first == 0) { 11387c478bd9Sstevel@tonic-gate return (aio_cleanup_thread(aiop)); 11397c478bd9Sstevel@tonic-gate /* should return only to exit */ 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate return (error); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * Associate an aiocb with a port. 11467c478bd9Sstevel@tonic-gate * This function is used by aiorw() to associate a transaction with a port. 11477c478bd9Sstevel@tonic-gate * Allocate an event port structure (port_alloc_event()) and store the 11487c478bd9Sstevel@tonic-gate * delivered user pointer (portnfy_user) in the portkev_user field of the 11497c478bd9Sstevel@tonic-gate * port_kevent_t structure.. 11507c478bd9Sstevel@tonic-gate * The aio_req_portkev pointer in the aio_req_t structure was added to identify 11517c478bd9Sstevel@tonic-gate * the port association. 11527c478bd9Sstevel@tonic-gate */ 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate static int 115534709573Sraf aio_req_assoc_port_rw(port_notify_t *pntfy, aiocb_t *cbp, 115634709573Sraf aio_req_t *reqp, int event) 11577c478bd9Sstevel@tonic-gate { 11587c478bd9Sstevel@tonic-gate port_kevent_t *pkevp = NULL; 11597c478bd9Sstevel@tonic-gate int error; 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate error = port_alloc_event(pntfy->portnfy_port, PORT_ALLOC_DEFAULT, 11627c478bd9Sstevel@tonic-gate PORT_SOURCE_AIO, &pkevp); 11637c478bd9Sstevel@tonic-gate if (error) { 11647c478bd9Sstevel@tonic-gate if ((error == ENOMEM) || (error == EAGAIN)) 11657c478bd9Sstevel@tonic-gate error = EAGAIN; 11667c478bd9Sstevel@tonic-gate else 11677c478bd9Sstevel@tonic-gate error = EINVAL; 11687c478bd9Sstevel@tonic-gate } else { 11697c478bd9Sstevel@tonic-gate port_init_event(pkevp, (uintptr_t)cbp, pntfy->portnfy_user, 11707c478bd9Sstevel@tonic-gate aio_port_callback, reqp); 117134709573Sraf pkevp->portkev_events = event; 11727c478bd9Sstevel@tonic-gate reqp->aio_req_portkev = pkevp; 11737c478bd9Sstevel@tonic-gate reqp->aio_req_port = pntfy->portnfy_port; 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate return (error); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate #ifdef _LP64 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate /* 11817c478bd9Sstevel@tonic-gate * Asynchronous list IO. A chain of aiocb's are copied in 11827c478bd9Sstevel@tonic-gate * one at a time. If the aiocb is invalid, it is skipped. 11837c478bd9Sstevel@tonic-gate * For each aiocb, the appropriate driver entry point is 11847c478bd9Sstevel@tonic-gate * called. Optimize for the common case where the list 11857c478bd9Sstevel@tonic-gate * of requests is to the same file descriptor. 11867c478bd9Sstevel@tonic-gate * 11877c478bd9Sstevel@tonic-gate * One possible optimization is to define a new driver entry 11887c478bd9Sstevel@tonic-gate * point that supports a list of IO requests. Whether this 11897c478bd9Sstevel@tonic-gate * improves performance depends somewhat on the driver's 11907c478bd9Sstevel@tonic-gate * locking strategy. Processing a list could adversely impact 11917c478bd9Sstevel@tonic-gate * the driver's interrupt latency. 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate static int 11947c478bd9Sstevel@tonic-gate alio( 11957c478bd9Sstevel@tonic-gate int mode_arg, 11967c478bd9Sstevel@tonic-gate aiocb_t **aiocb_arg, 11977c478bd9Sstevel@tonic-gate int nent, 11987c478bd9Sstevel@tonic-gate struct sigevent *sigev) 11997c478bd9Sstevel@tonic-gate { 12007c478bd9Sstevel@tonic-gate file_t *fp; 12017c478bd9Sstevel@tonic-gate file_t *prev_fp = NULL; 12027c478bd9Sstevel@tonic-gate int prev_mode = -1; 12037c478bd9Sstevel@tonic-gate struct vnode *vp; 12047c478bd9Sstevel@tonic-gate aio_lio_t *head; 12057c478bd9Sstevel@tonic-gate aio_req_t *reqp; 12067c478bd9Sstevel@tonic-gate aio_t *aiop; 12077c478bd9Sstevel@tonic-gate caddr_t cbplist; 12087c478bd9Sstevel@tonic-gate aiocb_t cb; 12097c478bd9Sstevel@tonic-gate aiocb_t *aiocb = &cb; 121034709573Sraf aiocb_t *cbp; 121134709573Sraf aiocb_t **ucbp; 12127c478bd9Sstevel@tonic-gate struct sigevent sigevk; 12137c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 12147c478bd9Sstevel@tonic-gate int (*aio_func)(); 12157c478bd9Sstevel@tonic-gate int mode; 12167c478bd9Sstevel@tonic-gate int error = 0; 12177c478bd9Sstevel@tonic-gate int aio_errors = 0; 12187c478bd9Sstevel@tonic-gate int i; 12197c478bd9Sstevel@tonic-gate size_t ssize; 12207c478bd9Sstevel@tonic-gate int deadhead = 0; 12217c478bd9Sstevel@tonic-gate int aio_notsupported = 0; 122234709573Sraf int lio_head_port; 122334709573Sraf int aio_port; 122434709573Sraf int aio_thread; 12257c478bd9Sstevel@tonic-gate port_kevent_t *pkevtp = NULL; 122634b3058fSpraks int portused = 0; 12277c478bd9Sstevel@tonic-gate port_notify_t pnotify; 122834709573Sraf int event; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 12317c478bd9Sstevel@tonic-gate if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX) 12327c478bd9Sstevel@tonic-gate return (EINVAL); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate ssize = (sizeof (aiocb_t *) * nent); 12357c478bd9Sstevel@tonic-gate cbplist = kmem_alloc(ssize, KM_SLEEP); 12367c478bd9Sstevel@tonic-gate ucbp = (aiocb_t **)cbplist; 12377c478bd9Sstevel@tonic-gate 123834709573Sraf if (copyin(aiocb_arg, cbplist, ssize) || 123934709573Sraf (sigev && copyin(sigev, &sigevk, sizeof (struct sigevent)))) { 12407c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 12417c478bd9Sstevel@tonic-gate return (EFAULT); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 124434709573Sraf /* Event Ports */ 124534709573Sraf if (sigev && 124634709573Sraf (sigevk.sigev_notify == SIGEV_THREAD || 124734709573Sraf sigevk.sigev_notify == SIGEV_PORT)) { 124834709573Sraf if (sigevk.sigev_notify == SIGEV_THREAD) { 124934709573Sraf pnotify.portnfy_port = sigevk.sigev_signo; 125034709573Sraf pnotify.portnfy_user = sigevk.sigev_value.sival_ptr; 125134709573Sraf } else if (copyin(sigevk.sigev_value.sival_ptr, 125234709573Sraf &pnotify, sizeof (pnotify))) { 12537c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 12547c478bd9Sstevel@tonic-gate return (EFAULT); 12557c478bd9Sstevel@tonic-gate } 125634709573Sraf error = port_alloc_event(pnotify.portnfy_port, 125734709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp); 125834709573Sraf if (error) { 125934709573Sraf if (error == ENOMEM || error == EAGAIN) 126034709573Sraf error = EAGAIN; 126134709573Sraf else 126234709573Sraf error = EINVAL; 126334709573Sraf kmem_free(cbplist, ssize); 126434709573Sraf return (error); 126534709573Sraf } 126634709573Sraf lio_head_port = pnotify.portnfy_port; 126734b3058fSpraks portused = 1; 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * a list head should be allocated if notification is 12727c478bd9Sstevel@tonic-gate * enabled for this list. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate head = NULL; 12757c478bd9Sstevel@tonic-gate 127634709573Sraf if (mode_arg == LIO_WAIT || sigev) { 12777c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 12787c478bd9Sstevel@tonic-gate error = aio_lio_alloc(&head); 12797c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 12807c478bd9Sstevel@tonic-gate if (error) 12817c478bd9Sstevel@tonic-gate goto done; 12827c478bd9Sstevel@tonic-gate deadhead = 1; 12837c478bd9Sstevel@tonic-gate head->lio_nent = nent; 12847c478bd9Sstevel@tonic-gate head->lio_refcnt = nent; 128534709573Sraf head->lio_port = -1; 128634709573Sraf head->lio_portkev = NULL; 128734709573Sraf if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL && 128834709573Sraf sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) { 12897c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP); 12907c478bd9Sstevel@tonic-gate if (sqp == NULL) { 12917c478bd9Sstevel@tonic-gate error = EAGAIN; 12927c478bd9Sstevel@tonic-gate goto done; 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate sqp->sq_func = NULL; 12957c478bd9Sstevel@tonic-gate sqp->sq_next = NULL; 12967c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_ASYNCIO; 12977c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = curproc->p_pid; 12987c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(curproc); 12997c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 13007c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetuid(curproc->p_cred); 13017c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sigevk.sigev_signo; 13027c478bd9Sstevel@tonic-gate sqp->sq_info.si_value = sigevk.sigev_value; 13037c478bd9Sstevel@tonic-gate head->lio_sigqp = sqp; 13047c478bd9Sstevel@tonic-gate } else { 13057c478bd9Sstevel@tonic-gate head->lio_sigqp = NULL; 13067c478bd9Sstevel@tonic-gate } 130734709573Sraf if (pkevtp) { 130834709573Sraf /* 130934709573Sraf * Prepare data to send when list of aiocb's 131034709573Sraf * has completed. 131134709573Sraf */ 131234709573Sraf port_init_event(pkevtp, (uintptr_t)sigev, 131334709573Sraf (void *)(uintptr_t)pnotify.portnfy_user, 131434709573Sraf NULL, head); 131534709573Sraf pkevtp->portkev_events = AIOLIO; 131634709573Sraf head->lio_portkev = pkevtp; 131734709573Sraf head->lio_port = pnotify.portnfy_port; 131834709573Sraf } 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++, ucbp++) { 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate cbp = *ucbp; 13247c478bd9Sstevel@tonic-gate /* skip entry if it can't be copied. */ 132534709573Sraf if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb))) { 13267c478bd9Sstevel@tonic-gate if (head) { 13277c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 13287c478bd9Sstevel@tonic-gate head->lio_nent--; 13297c478bd9Sstevel@tonic-gate head->lio_refcnt--; 13307c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate continue; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* skip if opcode for aiocb is LIO_NOP */ 13367c478bd9Sstevel@tonic-gate mode = aiocb->aio_lio_opcode; 13377c478bd9Sstevel@tonic-gate if (mode == LIO_NOP) { 13387c478bd9Sstevel@tonic-gate cbp = NULL; 13397c478bd9Sstevel@tonic-gate if (head) { 13407c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 13417c478bd9Sstevel@tonic-gate head->lio_nent--; 13427c478bd9Sstevel@tonic-gate head->lio_refcnt--; 13437c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate continue; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* increment file descriptor's ref count. */ 13497c478bd9Sstevel@tonic-gate if ((fp = getf(aiocb->aio_fildes)) == NULL) { 13507c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 13517c478bd9Sstevel@tonic-gate if (head) { 13527c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 13537c478bd9Sstevel@tonic-gate head->lio_nent--; 13547c478bd9Sstevel@tonic-gate head->lio_refcnt--; 13557c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate aio_errors++; 13587c478bd9Sstevel@tonic-gate continue; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * check the permission of the partition 13637c478bd9Sstevel@tonic-gate */ 13647c478bd9Sstevel@tonic-gate if ((fp->f_flag & mode) == 0) { 13657c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 13667c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 13677c478bd9Sstevel@tonic-gate if (head) { 13687c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 13697c478bd9Sstevel@tonic-gate head->lio_nent--; 13707c478bd9Sstevel@tonic-gate head->lio_refcnt--; 13717c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate aio_errors++; 13747c478bd9Sstevel@tonic-gate continue; 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 137834709573Sraf * common case where requests are to the same fd 137934709573Sraf * for the same r/w operation. 13807c478bd9Sstevel@tonic-gate * for UFS, need to set EBADFD 13817c478bd9Sstevel@tonic-gate */ 138234709573Sraf vp = fp->f_vnode; 138334709573Sraf if (fp != prev_fp || mode != prev_mode) { 13847c478bd9Sstevel@tonic-gate aio_func = check_vp(vp, mode); 13857c478bd9Sstevel@tonic-gate if (aio_func == NULL) { 13867c478bd9Sstevel@tonic-gate prev_fp = NULL; 13877c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 13887c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADFD); 13897c478bd9Sstevel@tonic-gate aio_notsupported++; 13907c478bd9Sstevel@tonic-gate if (head) { 13917c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 13927c478bd9Sstevel@tonic-gate head->lio_nent--; 13937c478bd9Sstevel@tonic-gate head->lio_refcnt--; 13947c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate continue; 13977c478bd9Sstevel@tonic-gate } else { 13987c478bd9Sstevel@tonic-gate prev_fp = fp; 13997c478bd9Sstevel@tonic-gate prev_mode = mode; 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 140334709573Sraf error = aio_req_setup(&reqp, aiop, aiocb, 1404*d2749ac6SRoger A. Faulkner &cbp->aio_resultp, vp, 0); 140534709573Sraf if (error) { 14067c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 14077c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, error); 14087c478bd9Sstevel@tonic-gate if (head) { 14097c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 14107c478bd9Sstevel@tonic-gate head->lio_nent--; 14117c478bd9Sstevel@tonic-gate head->lio_refcnt--; 14127c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate aio_errors++; 14157c478bd9Sstevel@tonic-gate continue; 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate reqp->aio_req_lio = head; 14197c478bd9Sstevel@tonic-gate deadhead = 0; 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate /* 14227c478bd9Sstevel@tonic-gate * Set the errno field now before sending the request to 14237c478bd9Sstevel@tonic-gate * the driver to avoid a race condition 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate (void) suword32(&cbp->aio_resultp.aio_errno, 14267c478bd9Sstevel@tonic-gate EINPROGRESS); 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb = (caddr_t)cbp; 14297c478bd9Sstevel@tonic-gate 143034709573Sraf event = (mode == LIO_READ)? AIOAREAD : AIOAWRITE; 143134709573Sraf aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT); 143234709573Sraf aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD); 143334709573Sraf if (aio_port | aio_thread) { 143434709573Sraf port_kevent_t *lpkevp; 143534709573Sraf /* 143634709573Sraf * Prepare data to send with each aiocb completed. 143734709573Sraf */ 143834709573Sraf if (aio_port) { 143934709573Sraf void *paddr = 144034709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 144134709573Sraf if (copyin(paddr, &pnotify, sizeof (pnotify))) 144234709573Sraf error = EFAULT; 144334709573Sraf } else { /* aio_thread */ 144434709573Sraf pnotify.portnfy_port = 144534709573Sraf aiocb->aio_sigevent.sigev_signo; 144634709573Sraf pnotify.portnfy_user = 144734709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 144834709573Sraf } 144934709573Sraf if (error) 145034709573Sraf /* EMPTY */; 145134709573Sraf else if (pkevtp != NULL && 145234709573Sraf pnotify.portnfy_port == lio_head_port) 145334709573Sraf error = port_dup_event(pkevtp, &lpkevp, 145434709573Sraf PORT_ALLOC_DEFAULT); 145534709573Sraf else 145634709573Sraf error = port_alloc_event(pnotify.portnfy_port, 145734709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, 145834709573Sraf &lpkevp); 145934709573Sraf if (error == 0) { 146034709573Sraf port_init_event(lpkevp, (uintptr_t)cbp, 146134709573Sraf (void *)(uintptr_t)pnotify.portnfy_user, 146234709573Sraf aio_port_callback, reqp); 146334709573Sraf lpkevp->portkev_events = event; 146434709573Sraf reqp->aio_req_portkev = lpkevp; 14657c478bd9Sstevel@tonic-gate reqp->aio_req_port = pnotify.portnfy_port; 146634709573Sraf } 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* 14707c478bd9Sstevel@tonic-gate * send the request to driver. 14717c478bd9Sstevel@tonic-gate */ 14727c478bd9Sstevel@tonic-gate if (error == 0) { 14737c478bd9Sstevel@tonic-gate if (aiocb->aio_nbytes == 0) { 14747c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 14757c478bd9Sstevel@tonic-gate aio_zerolen(reqp); 14767c478bd9Sstevel@tonic-gate continue; 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, 14797c478bd9Sstevel@tonic-gate CRED()); 14807c478bd9Sstevel@tonic-gate } 148134709573Sraf 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * the fd's ref count is not decremented until the IO has 14847c478bd9Sstevel@tonic-gate * completed unless there was an error. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate if (error) { 14877c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 14887c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, error); 14897c478bd9Sstevel@tonic-gate if (head) { 14907c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 14917c478bd9Sstevel@tonic-gate head->lio_nent--; 14927c478bd9Sstevel@tonic-gate head->lio_refcnt--; 14937c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate if (error == ENOTSUP) 14967c478bd9Sstevel@tonic-gate aio_notsupported++; 14977c478bd9Sstevel@tonic-gate else 14987c478bd9Sstevel@tonic-gate aio_errors++; 149934b3058fSpraks lio_set_error(reqp, portused); 15007c478bd9Sstevel@tonic-gate } else { 15017c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate if (aio_notsupported) { 15067c478bd9Sstevel@tonic-gate error = ENOTSUP; 15077c478bd9Sstevel@tonic-gate } else if (aio_errors) { 15087c478bd9Sstevel@tonic-gate /* 15097c478bd9Sstevel@tonic-gate * return EIO if any request failed 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate error = EIO; 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate if (mode_arg == LIO_WAIT) { 15157c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 15167c478bd9Sstevel@tonic-gate while (head->lio_refcnt > 0) { 15177c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) { 15187c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 15197c478bd9Sstevel@tonic-gate error = EINTR; 15207c478bd9Sstevel@tonic-gate goto done; 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 15247c478bd9Sstevel@tonic-gate alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_64); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate done: 15287c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 15297c478bd9Sstevel@tonic-gate if (deadhead) { 15307c478bd9Sstevel@tonic-gate if (head->lio_sigqp) 15317c478bd9Sstevel@tonic-gate kmem_free(head->lio_sigqp, sizeof (sigqueue_t)); 153234709573Sraf if (head->lio_portkev) 153334709573Sraf port_free_event(head->lio_portkev); 15347c478bd9Sstevel@tonic-gate kmem_free(head, sizeof (aio_lio_t)); 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate return (error); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* 15427c478bd9Sstevel@tonic-gate * Asynchronous list IO. 15437c478bd9Sstevel@tonic-gate * If list I/O is called with LIO_WAIT it can still return 15447c478bd9Sstevel@tonic-gate * before all the I/O's are completed if a signal is caught 15457c478bd9Sstevel@tonic-gate * or if the list include UFS I/O requests. If this happens, 15467c478bd9Sstevel@tonic-gate * libaio will call aliowait() to wait for the I/O's to 15477c478bd9Sstevel@tonic-gate * complete 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15507c478bd9Sstevel@tonic-gate static int 15517c478bd9Sstevel@tonic-gate aliowait( 15527c478bd9Sstevel@tonic-gate int mode, 15537c478bd9Sstevel@tonic-gate void *aiocb, 15547c478bd9Sstevel@tonic-gate int nent, 15557c478bd9Sstevel@tonic-gate void *sigev, 15567c478bd9Sstevel@tonic-gate int run_mode) 15577c478bd9Sstevel@tonic-gate { 15587c478bd9Sstevel@tonic-gate aio_lio_t *head; 15597c478bd9Sstevel@tonic-gate aio_t *aiop; 15607c478bd9Sstevel@tonic-gate caddr_t cbplist; 15617c478bd9Sstevel@tonic-gate aiocb_t *cbp, **ucbp; 15627c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 15637c478bd9Sstevel@tonic-gate aiocb32_t *cbp32; 15647c478bd9Sstevel@tonic-gate caddr32_t *ucbp32; 15657c478bd9Sstevel@tonic-gate aiocb64_32_t *cbp64; 15667c478bd9Sstevel@tonic-gate #endif 15677c478bd9Sstevel@tonic-gate int error = 0; 15687c478bd9Sstevel@tonic-gate int i; 15697c478bd9Sstevel@tonic-gate size_t ssize = 0; 15707c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 15737c478bd9Sstevel@tonic-gate if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX) 15747c478bd9Sstevel@tonic-gate return (EINVAL); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 15777c478bd9Sstevel@tonic-gate ssize = (sizeof (aiocb_t *) * nent); 15787c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 15797c478bd9Sstevel@tonic-gate else 15807c478bd9Sstevel@tonic-gate ssize = (sizeof (caddr32_t) * nent); 15817c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate if (ssize == 0) 15847c478bd9Sstevel@tonic-gate return (EINVAL); 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate cbplist = kmem_alloc(ssize, KM_SLEEP); 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 15897c478bd9Sstevel@tonic-gate ucbp = (aiocb_t **)cbplist; 15907c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 15917c478bd9Sstevel@tonic-gate else 15927c478bd9Sstevel@tonic-gate ucbp32 = (caddr32_t *)cbplist; 15937c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate if (copyin(aiocb, cbplist, ssize)) { 15967c478bd9Sstevel@tonic-gate error = EFAULT; 15977c478bd9Sstevel@tonic-gate goto done; 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * To find the list head, we go through the 16027c478bd9Sstevel@tonic-gate * list of aiocb structs, find the request 16037c478bd9Sstevel@tonic-gate * its for, then get the list head that reqp 16047c478bd9Sstevel@tonic-gate * points to 16057c478bd9Sstevel@tonic-gate */ 16067c478bd9Sstevel@tonic-gate head = NULL; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++) { 16097c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 16107c478bd9Sstevel@tonic-gate /* 16117c478bd9Sstevel@tonic-gate * Since we are only checking for a NULL pointer 16127c478bd9Sstevel@tonic-gate * Following should work on both native data sizes 16137c478bd9Sstevel@tonic-gate * as well as for largefile aiocb. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate if ((cbp = *ucbp++) == NULL) 16167c478bd9Sstevel@tonic-gate continue; 16177c478bd9Sstevel@tonic-gate if (run_mode != AIO_LARGEFILE) 16187c478bd9Sstevel@tonic-gate if (head = aio_list_get(&cbp->aio_resultp)) 16197c478bd9Sstevel@tonic-gate break; 16207c478bd9Sstevel@tonic-gate else { 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * This is a case when largefile call is 16237c478bd9Sstevel@tonic-gate * made on 32 bit kernel. 16247c478bd9Sstevel@tonic-gate * Treat each pointer as pointer to 16257c478bd9Sstevel@tonic-gate * aiocb64_32 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate if (head = aio_list_get((aio_result_t *) 16287c478bd9Sstevel@tonic-gate &(((aiocb64_32_t *)cbp)->aio_resultp))) 16297c478bd9Sstevel@tonic-gate break; 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 16337c478bd9Sstevel@tonic-gate else { 16347c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) { 16357c478bd9Sstevel@tonic-gate if ((cbp64 = (aiocb64_32_t *) 16367c478bd9Sstevel@tonic-gate (uintptr_t)*ucbp32++) == NULL) 16377c478bd9Sstevel@tonic-gate continue; 16387c478bd9Sstevel@tonic-gate if (head = aio_list_get((aio_result_t *) 16397c478bd9Sstevel@tonic-gate &cbp64->aio_resultp)) 16407c478bd9Sstevel@tonic-gate break; 16417c478bd9Sstevel@tonic-gate } else if (run_mode == AIO_32) { 16427c478bd9Sstevel@tonic-gate if ((cbp32 = (aiocb32_t *) 16437c478bd9Sstevel@tonic-gate (uintptr_t)*ucbp32++) == NULL) 16447c478bd9Sstevel@tonic-gate continue; 16457c478bd9Sstevel@tonic-gate if (head = aio_list_get((aio_result_t *) 16467c478bd9Sstevel@tonic-gate &cbp32->aio_resultp)) 16477c478bd9Sstevel@tonic-gate break; 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if (head == NULL) { 16547c478bd9Sstevel@tonic-gate error = EINVAL; 16557c478bd9Sstevel@tonic-gate goto done; 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 16597c478bd9Sstevel@tonic-gate while (head->lio_refcnt > 0) { 16607c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) { 16617c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 16627c478bd9Sstevel@tonic-gate error = EINTR; 16637c478bd9Sstevel@tonic-gate goto done; 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 16677c478bd9Sstevel@tonic-gate alio_cleanup(aiop, (aiocb_t **)cbplist, nent, run_mode); 16687c478bd9Sstevel@tonic-gate done: 16697c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 16707c478bd9Sstevel@tonic-gate return (error); 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate aio_lio_t * 16747c478bd9Sstevel@tonic-gate aio_list_get(aio_result_t *resultp) 16757c478bd9Sstevel@tonic-gate { 16767c478bd9Sstevel@tonic-gate aio_lio_t *head = NULL; 16777c478bd9Sstevel@tonic-gate aio_t *aiop; 16787c478bd9Sstevel@tonic-gate aio_req_t **bucket; 16797c478bd9Sstevel@tonic-gate aio_req_t *reqp; 16807c478bd9Sstevel@tonic-gate long index; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 16837c478bd9Sstevel@tonic-gate if (aiop == NULL) 16847c478bd9Sstevel@tonic-gate return (NULL); 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate if (resultp) { 16877c478bd9Sstevel@tonic-gate index = AIO_HASH(resultp); 16887c478bd9Sstevel@tonic-gate bucket = &aiop->aio_hash[index]; 16897c478bd9Sstevel@tonic-gate for (reqp = *bucket; reqp != NULL; 16907c478bd9Sstevel@tonic-gate reqp = reqp->aio_hash_next) { 16917c478bd9Sstevel@tonic-gate if (reqp->aio_req_resultp == resultp) { 16927c478bd9Sstevel@tonic-gate head = reqp->aio_req_lio; 16937c478bd9Sstevel@tonic-gate return (head); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate return (NULL); 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate static void 17027c478bd9Sstevel@tonic-gate lio_set_uerror(void *resultp, int error) 17037c478bd9Sstevel@tonic-gate { 17047c478bd9Sstevel@tonic-gate /* 17057c478bd9Sstevel@tonic-gate * the resultp field is a pointer to where the 17067c478bd9Sstevel@tonic-gate * error should be written out to the user's 17077c478bd9Sstevel@tonic-gate * aiocb. 17087c478bd9Sstevel@tonic-gate * 17097c478bd9Sstevel@tonic-gate */ 17107c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 17117c478bd9Sstevel@tonic-gate (void) sulword(&((aio_result_t *)resultp)->aio_return, 17127c478bd9Sstevel@tonic-gate (ssize_t)-1); 17137c478bd9Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_errno, error); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 17167c478bd9Sstevel@tonic-gate else { 17177c478bd9Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_return, 17187c478bd9Sstevel@tonic-gate (uint_t)-1); 17197c478bd9Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_errno, error); 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate /* 17257c478bd9Sstevel@tonic-gate * do cleanup completion for all requests in list. memory for 17267c478bd9Sstevel@tonic-gate * each request is also freed. 17277c478bd9Sstevel@tonic-gate */ 17287c478bd9Sstevel@tonic-gate static void 17297c478bd9Sstevel@tonic-gate alio_cleanup(aio_t *aiop, aiocb_t **cbp, int nent, int run_mode) 17307c478bd9Sstevel@tonic-gate { 17317c478bd9Sstevel@tonic-gate int i; 17327c478bd9Sstevel@tonic-gate aio_req_t *reqp; 17337c478bd9Sstevel@tonic-gate aio_result_t *resultp; 17347c478bd9Sstevel@tonic-gate aiocb64_32_t *aiocb_64; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++) { 17377c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 17387c478bd9Sstevel@tonic-gate if (cbp[i] == NULL) 17397c478bd9Sstevel@tonic-gate continue; 17407c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) { 17417c478bd9Sstevel@tonic-gate aiocb_64 = (aiocb64_32_t *)cbp[i]; 174234709573Sraf resultp = (aio_result_t *) 174334709573Sraf &aiocb_64->aio_resultp; 17447c478bd9Sstevel@tonic-gate } else 17457c478bd9Sstevel@tonic-gate resultp = &cbp[i]->aio_resultp; 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 17487c478bd9Sstevel@tonic-gate else { 17497c478bd9Sstevel@tonic-gate aiocb32_t *aiocb_32; 17507c478bd9Sstevel@tonic-gate caddr32_t *cbp32; 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate cbp32 = (caddr32_t *)cbp; 17537c478bd9Sstevel@tonic-gate if (cbp32[i] == NULL) 17547c478bd9Sstevel@tonic-gate continue; 17557c478bd9Sstevel@tonic-gate if (run_mode == AIO_32) { 17567c478bd9Sstevel@tonic-gate aiocb_32 = (aiocb32_t *)(uintptr_t)cbp32[i]; 17577c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&aiocb_32-> 17587c478bd9Sstevel@tonic-gate aio_resultp; 17597c478bd9Sstevel@tonic-gate } else if (run_mode == AIO_LARGEFILE) { 17607c478bd9Sstevel@tonic-gate aiocb_64 = (aiocb64_32_t *)(uintptr_t)cbp32[i]; 17617c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&aiocb_64-> 17627c478bd9Sstevel@tonic-gate aio_resultp; 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 17667c478bd9Sstevel@tonic-gate /* 17677c478bd9Sstevel@tonic-gate * we need to get the aio_cleanupq_mutex since we call 17687c478bd9Sstevel@tonic-gate * aio_req_done(). 17697c478bd9Sstevel@tonic-gate */ 17707c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex); 17717c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 17727c478bd9Sstevel@tonic-gate reqp = aio_req_done(resultp); 17737c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 17747c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex); 17757c478bd9Sstevel@tonic-gate if (reqp != NULL) { 17767c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 17777c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 17787c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 17797c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 17807c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate } 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* 178634709573Sraf * Write out the results for an aio request that is done. 17877c478bd9Sstevel@tonic-gate */ 17887c478bd9Sstevel@tonic-gate static int 17897c478bd9Sstevel@tonic-gate aioerror(void *cb, int run_mode) 17907c478bd9Sstevel@tonic-gate { 17917c478bd9Sstevel@tonic-gate aio_result_t *resultp; 17927c478bd9Sstevel@tonic-gate aio_t *aiop; 17937c478bd9Sstevel@tonic-gate aio_req_t *reqp; 17947c478bd9Sstevel@tonic-gate int retval; 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 17977c478bd9Sstevel@tonic-gate if (aiop == NULL || cb == NULL) 17987c478bd9Sstevel@tonic-gate return (EINVAL); 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 18017c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) 18027c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb64_32_t *)cb)-> 18037c478bd9Sstevel@tonic-gate aio_resultp; 18047c478bd9Sstevel@tonic-gate else 18057c478bd9Sstevel@tonic-gate resultp = &((aiocb_t *)cb)->aio_resultp; 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 18087c478bd9Sstevel@tonic-gate else { 18097c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) 18107c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb64_32_t *)cb)-> 18117c478bd9Sstevel@tonic-gate aio_resultp; 18127c478bd9Sstevel@tonic-gate else if (run_mode == AIO_32) 18137c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb32_t *)cb)-> 18147c478bd9Sstevel@tonic-gate aio_resultp; 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 18177c478bd9Sstevel@tonic-gate /* 18187c478bd9Sstevel@tonic-gate * we need to get the aio_cleanupq_mutex since we call 18197c478bd9Sstevel@tonic-gate * aio_req_find(). 18207c478bd9Sstevel@tonic-gate */ 18217c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex); 18227c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 18237c478bd9Sstevel@tonic-gate retval = aio_req_find(resultp, &reqp); 18247c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 18257c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex); 18267c478bd9Sstevel@tonic-gate if (retval == 0) { 18277c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); 18287c478bd9Sstevel@tonic-gate aio_copyout_result(reqp); 18297c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 18307c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 18317c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 18327c478bd9Sstevel@tonic-gate return (0); 18337c478bd9Sstevel@tonic-gate } else if (retval == 1) 18347c478bd9Sstevel@tonic-gate return (EINPROGRESS); 18357c478bd9Sstevel@tonic-gate else if (retval == 2) 18367c478bd9Sstevel@tonic-gate return (EINVAL); 18377c478bd9Sstevel@tonic-gate return (0); 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate /* 18417c478bd9Sstevel@tonic-gate * aio_cancel - if no requests outstanding, 18427c478bd9Sstevel@tonic-gate * return AIO_ALLDONE 18437c478bd9Sstevel@tonic-gate * else 18447c478bd9Sstevel@tonic-gate * return AIO_NOTCANCELED 18457c478bd9Sstevel@tonic-gate */ 18467c478bd9Sstevel@tonic-gate static int 18477c478bd9Sstevel@tonic-gate aio_cancel( 18487c478bd9Sstevel@tonic-gate int fildes, 18497c478bd9Sstevel@tonic-gate void *cb, 18507c478bd9Sstevel@tonic-gate long *rval, 18517c478bd9Sstevel@tonic-gate int run_mode) 18527c478bd9Sstevel@tonic-gate { 18537c478bd9Sstevel@tonic-gate aio_t *aiop; 18547c478bd9Sstevel@tonic-gate void *resultp; 18557c478bd9Sstevel@tonic-gate int index; 18567c478bd9Sstevel@tonic-gate aio_req_t **bucket; 18577c478bd9Sstevel@tonic-gate aio_req_t *ent; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate /* 18617c478bd9Sstevel@tonic-gate * Verify valid file descriptor 18627c478bd9Sstevel@tonic-gate */ 18637c478bd9Sstevel@tonic-gate if ((getf(fildes)) == NULL) { 18647c478bd9Sstevel@tonic-gate return (EBADF); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate releasef(fildes); 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 18697c478bd9Sstevel@tonic-gate if (aiop == NULL) 18707c478bd9Sstevel@tonic-gate return (EINVAL); 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (aiop->aio_outstanding == 0) { 18737c478bd9Sstevel@tonic-gate *rval = AIO_ALLDONE; 18747c478bd9Sstevel@tonic-gate return (0); 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 18787c478bd9Sstevel@tonic-gate if (cb != NULL) { 18797c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 18807c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) 18817c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb64_32_t *)cb) 18827c478bd9Sstevel@tonic-gate ->aio_resultp; 18837c478bd9Sstevel@tonic-gate else 18847c478bd9Sstevel@tonic-gate resultp = &((aiocb_t *)cb)->aio_resultp; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 18877c478bd9Sstevel@tonic-gate else { 18887c478bd9Sstevel@tonic-gate if (run_mode == AIO_LARGEFILE) 18897c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb64_32_t *)cb) 18907c478bd9Sstevel@tonic-gate ->aio_resultp; 18917c478bd9Sstevel@tonic-gate else if (run_mode == AIO_32) 18927c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&((aiocb32_t *)cb) 18937c478bd9Sstevel@tonic-gate ->aio_resultp; 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 18967c478bd9Sstevel@tonic-gate index = AIO_HASH(resultp); 18977c478bd9Sstevel@tonic-gate bucket = &aiop->aio_hash[index]; 18987c478bd9Sstevel@tonic-gate for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) { 18997c478bd9Sstevel@tonic-gate if (ent->aio_req_resultp == resultp) { 19007c478bd9Sstevel@tonic-gate if ((ent->aio_req_flags & AIO_PENDING) == 0) { 19017c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 19027c478bd9Sstevel@tonic-gate *rval = AIO_ALLDONE; 19037c478bd9Sstevel@tonic-gate return (0); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 19067c478bd9Sstevel@tonic-gate *rval = AIO_NOTCANCELED; 19077c478bd9Sstevel@tonic-gate return (0); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate } 19107c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 19117c478bd9Sstevel@tonic-gate *rval = AIO_ALLDONE; 19127c478bd9Sstevel@tonic-gate return (0); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate for (index = 0; index < AIO_HASHSZ; index++) { 19167c478bd9Sstevel@tonic-gate bucket = &aiop->aio_hash[index]; 19177c478bd9Sstevel@tonic-gate for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) { 19187c478bd9Sstevel@tonic-gate if (ent->aio_req_fd == fildes) { 19197c478bd9Sstevel@tonic-gate if ((ent->aio_req_flags & AIO_PENDING) != 0) { 19207c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 19217c478bd9Sstevel@tonic-gate *rval = AIO_NOTCANCELED; 19227c478bd9Sstevel@tonic-gate return (0); 19237c478bd9Sstevel@tonic-gate } 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 19287c478bd9Sstevel@tonic-gate *rval = AIO_ALLDONE; 19297c478bd9Sstevel@tonic-gate return (0); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate /* 19337c478bd9Sstevel@tonic-gate * solaris version of asynchronous read and write 19347c478bd9Sstevel@tonic-gate */ 19357c478bd9Sstevel@tonic-gate static int 19367c478bd9Sstevel@tonic-gate arw( 19377c478bd9Sstevel@tonic-gate int opcode, 19387c478bd9Sstevel@tonic-gate int fdes, 19397c478bd9Sstevel@tonic-gate char *bufp, 19407c478bd9Sstevel@tonic-gate int bufsize, 19417c478bd9Sstevel@tonic-gate offset_t offset, 19427c478bd9Sstevel@tonic-gate aio_result_t *resultp, 19437c478bd9Sstevel@tonic-gate int mode) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate file_t *fp; 19467c478bd9Sstevel@tonic-gate int error; 19477c478bd9Sstevel@tonic-gate struct vnode *vp; 19487c478bd9Sstevel@tonic-gate aio_req_t *reqp; 19497c478bd9Sstevel@tonic-gate aio_t *aiop; 19507c478bd9Sstevel@tonic-gate int (*aio_func)(); 19517c478bd9Sstevel@tonic-gate #ifdef _LP64 19527c478bd9Sstevel@tonic-gate aiocb_t aiocb; 19537c478bd9Sstevel@tonic-gate #else 19547c478bd9Sstevel@tonic-gate aiocb64_32_t aiocb64; 19557c478bd9Sstevel@tonic-gate #endif 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 19587c478bd9Sstevel@tonic-gate if (aiop == NULL) 19597c478bd9Sstevel@tonic-gate return (EINVAL); 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) { 19627c478bd9Sstevel@tonic-gate return (EBADF); 19637c478bd9Sstevel@tonic-gate } 19647c478bd9Sstevel@tonic-gate 19657c478bd9Sstevel@tonic-gate /* 19667c478bd9Sstevel@tonic-gate * check the permission of the partition 19677c478bd9Sstevel@tonic-gate */ 19687c478bd9Sstevel@tonic-gate if ((fp->f_flag & mode) == 0) { 19697c478bd9Sstevel@tonic-gate releasef(fdes); 19707c478bd9Sstevel@tonic-gate return (EBADF); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 19747c478bd9Sstevel@tonic-gate aio_func = check_vp(vp, mode); 19757c478bd9Sstevel@tonic-gate if (aio_func == NULL) { 19767c478bd9Sstevel@tonic-gate releasef(fdes); 19777c478bd9Sstevel@tonic-gate return (EBADFD); 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate #ifdef _LP64 19807c478bd9Sstevel@tonic-gate aiocb.aio_fildes = fdes; 19817c478bd9Sstevel@tonic-gate aiocb.aio_buf = bufp; 19827c478bd9Sstevel@tonic-gate aiocb.aio_nbytes = bufsize; 19837c478bd9Sstevel@tonic-gate aiocb.aio_offset = offset; 19847c478bd9Sstevel@tonic-gate aiocb.aio_sigevent.sigev_notify = 0; 1985*d2749ac6SRoger A. Faulkner error = aio_req_setup(&reqp, aiop, &aiocb, resultp, vp, 1); 19867c478bd9Sstevel@tonic-gate #else 19877c478bd9Sstevel@tonic-gate aiocb64.aio_fildes = fdes; 19887c478bd9Sstevel@tonic-gate aiocb64.aio_buf = (caddr32_t)bufp; 19897c478bd9Sstevel@tonic-gate aiocb64.aio_nbytes = bufsize; 19907c478bd9Sstevel@tonic-gate aiocb64.aio_offset = offset; 19917c478bd9Sstevel@tonic-gate aiocb64.aio_sigevent.sigev_notify = 0; 1992*d2749ac6SRoger A. Faulkner error = aio_req_setupLF(&reqp, aiop, &aiocb64, resultp, vp, 1); 19937c478bd9Sstevel@tonic-gate #endif 19947c478bd9Sstevel@tonic-gate if (error) { 19957c478bd9Sstevel@tonic-gate releasef(fdes); 19967c478bd9Sstevel@tonic-gate return (error); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate /* 20007c478bd9Sstevel@tonic-gate * enable polling on this request if the opcode has 20017c478bd9Sstevel@tonic-gate * the AIO poll bit set 20027c478bd9Sstevel@tonic-gate */ 20037c478bd9Sstevel@tonic-gate if (opcode & AIO_POLL_BIT) 20047c478bd9Sstevel@tonic-gate reqp->aio_req_flags |= AIO_POLL; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate if (bufsize == 0) { 20077c478bd9Sstevel@tonic-gate clear_active_fd(fdes); 20087c478bd9Sstevel@tonic-gate aio_zerolen(reqp); 20097c478bd9Sstevel@tonic-gate return (0); 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * send the request to driver. 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, CRED()); 20157c478bd9Sstevel@tonic-gate /* 20167c478bd9Sstevel@tonic-gate * the fd is stored in the aio_req_t by aio_req_setup(), and 20177c478bd9Sstevel@tonic-gate * is released by the aio_cleanup_thread() when the IO has 20187c478bd9Sstevel@tonic-gate * completed. 20197c478bd9Sstevel@tonic-gate */ 20207c478bd9Sstevel@tonic-gate if (error) { 20217c478bd9Sstevel@tonic-gate releasef(fdes); 20227c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 20237c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 20247c478bd9Sstevel@tonic-gate aiop->aio_pending--; 20257c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_REQ_BLOCK) 20267c478bd9Sstevel@tonic-gate cv_signal(&aiop->aio_cleanupcv); 20277c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 20287c478bd9Sstevel@tonic-gate return (error); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate clear_active_fd(fdes); 20317c478bd9Sstevel@tonic-gate return (0); 20327c478bd9Sstevel@tonic-gate } 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate /* 20357c478bd9Sstevel@tonic-gate * posix version of asynchronous read and write 20367c478bd9Sstevel@tonic-gate */ 20377c478bd9Sstevel@tonic-gate static int 20387c478bd9Sstevel@tonic-gate aiorw( 20397c478bd9Sstevel@tonic-gate int opcode, 20407c478bd9Sstevel@tonic-gate void *aiocb_arg, 20417c478bd9Sstevel@tonic-gate int mode, 20427c478bd9Sstevel@tonic-gate int run_mode) 20437c478bd9Sstevel@tonic-gate { 20447c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 20457c478bd9Sstevel@tonic-gate aiocb32_t aiocb32; 20467c478bd9Sstevel@tonic-gate struct sigevent32 *sigev32; 20477c478bd9Sstevel@tonic-gate port_notify32_t pntfy32; 20487c478bd9Sstevel@tonic-gate #endif 20497c478bd9Sstevel@tonic-gate aiocb64_32_t aiocb64; 20507c478bd9Sstevel@tonic-gate aiocb_t aiocb; 20517c478bd9Sstevel@tonic-gate file_t *fp; 20527c478bd9Sstevel@tonic-gate int error, fd; 20537c478bd9Sstevel@tonic-gate size_t bufsize; 20547c478bd9Sstevel@tonic-gate struct vnode *vp; 20557c478bd9Sstevel@tonic-gate aio_req_t *reqp; 20567c478bd9Sstevel@tonic-gate aio_t *aiop; 20577c478bd9Sstevel@tonic-gate int (*aio_func)(); 20587c478bd9Sstevel@tonic-gate aio_result_t *resultp; 20597c478bd9Sstevel@tonic-gate struct sigevent *sigev; 20607c478bd9Sstevel@tonic-gate model_t model; 20617c478bd9Sstevel@tonic-gate int aio_use_port = 0; 20627c478bd9Sstevel@tonic-gate port_notify_t pntfy; 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate model = get_udatamodel(); 20657c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 20667c478bd9Sstevel@tonic-gate if (aiop == NULL) 20677c478bd9Sstevel@tonic-gate return (EINVAL); 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 20707c478bd9Sstevel@tonic-gate if (run_mode != AIO_LARGEFILE) { 20717c478bd9Sstevel@tonic-gate if (copyin(aiocb_arg, &aiocb, sizeof (aiocb_t))) 20727c478bd9Sstevel@tonic-gate return (EFAULT); 20737c478bd9Sstevel@tonic-gate bufsize = aiocb.aio_nbytes; 20747c478bd9Sstevel@tonic-gate resultp = &(((aiocb_t *)aiocb_arg)->aio_resultp); 20757c478bd9Sstevel@tonic-gate if ((fp = getf(fd = aiocb.aio_fildes)) == NULL) { 20767c478bd9Sstevel@tonic-gate return (EBADF); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate sigev = &aiocb.aio_sigevent; 20797c478bd9Sstevel@tonic-gate } else { 20807c478bd9Sstevel@tonic-gate /* 20817c478bd9Sstevel@tonic-gate * We come here only when we make largefile 20827c478bd9Sstevel@tonic-gate * call on 32 bit kernel using 32 bit library. 20837c478bd9Sstevel@tonic-gate */ 20847c478bd9Sstevel@tonic-gate if (copyin(aiocb_arg, &aiocb64, sizeof (aiocb64_32_t))) 20857c478bd9Sstevel@tonic-gate return (EFAULT); 20867c478bd9Sstevel@tonic-gate bufsize = aiocb64.aio_nbytes; 20877c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&(((aiocb64_32_t *)aiocb_arg) 20887c478bd9Sstevel@tonic-gate ->aio_resultp); 208934709573Sraf if ((fp = getf(fd = aiocb64.aio_fildes)) == NULL) 20907c478bd9Sstevel@tonic-gate return (EBADF); 20917c478bd9Sstevel@tonic-gate sigev = (struct sigevent *)&aiocb64.aio_sigevent; 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate if (sigev->sigev_notify == SIGEV_PORT) { 20957c478bd9Sstevel@tonic-gate if (copyin((void *)sigev->sigev_value.sival_ptr, 20967c478bd9Sstevel@tonic-gate &pntfy, sizeof (port_notify_t))) { 20977c478bd9Sstevel@tonic-gate releasef(fd); 20987c478bd9Sstevel@tonic-gate return (EFAULT); 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate aio_use_port = 1; 210134709573Sraf } else if (sigev->sigev_notify == SIGEV_THREAD) { 210234709573Sraf pntfy.portnfy_port = aiocb.aio_sigevent.sigev_signo; 210334709573Sraf pntfy.portnfy_user = 210434709573Sraf aiocb.aio_sigevent.sigev_value.sival_ptr; 210534709573Sraf aio_use_port = 1; 21067c478bd9Sstevel@tonic-gate } 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 21097c478bd9Sstevel@tonic-gate else { 21107c478bd9Sstevel@tonic-gate if (run_mode == AIO_32) { 21117c478bd9Sstevel@tonic-gate /* 32 bit system call is being made on 64 bit kernel */ 21127c478bd9Sstevel@tonic-gate if (copyin(aiocb_arg, &aiocb32, sizeof (aiocb32_t))) 21137c478bd9Sstevel@tonic-gate return (EFAULT); 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate bufsize = aiocb32.aio_nbytes; 21167c478bd9Sstevel@tonic-gate aiocb_32ton(&aiocb32, &aiocb); 21177c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&(((aiocb32_t *)aiocb_arg)-> 21187c478bd9Sstevel@tonic-gate aio_resultp); 21197c478bd9Sstevel@tonic-gate if ((fp = getf(fd = aiocb32.aio_fildes)) == NULL) { 21207c478bd9Sstevel@tonic-gate return (EBADF); 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate sigev32 = &aiocb32.aio_sigevent; 21237c478bd9Sstevel@tonic-gate } else if (run_mode == AIO_LARGEFILE) { 21247c478bd9Sstevel@tonic-gate /* 21257c478bd9Sstevel@tonic-gate * We come here only when we make largefile 21267c478bd9Sstevel@tonic-gate * call on 64 bit kernel using 32 bit library. 21277c478bd9Sstevel@tonic-gate */ 21287c478bd9Sstevel@tonic-gate if (copyin(aiocb_arg, &aiocb64, sizeof (aiocb64_32_t))) 21297c478bd9Sstevel@tonic-gate return (EFAULT); 21307c478bd9Sstevel@tonic-gate bufsize = aiocb64.aio_nbytes; 21317c478bd9Sstevel@tonic-gate aiocb_LFton(&aiocb64, &aiocb); 21327c478bd9Sstevel@tonic-gate resultp = (aio_result_t *)&(((aiocb64_32_t *)aiocb_arg) 21337c478bd9Sstevel@tonic-gate ->aio_resultp); 21347c478bd9Sstevel@tonic-gate if ((fp = getf(fd = aiocb64.aio_fildes)) == NULL) 21357c478bd9Sstevel@tonic-gate return (EBADF); 21367c478bd9Sstevel@tonic-gate sigev32 = &aiocb64.aio_sigevent; 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate if (sigev32->sigev_notify == SIGEV_PORT) { 21407c478bd9Sstevel@tonic-gate if (copyin( 21417c478bd9Sstevel@tonic-gate (void *)(uintptr_t)sigev32->sigev_value.sival_ptr, 21427c478bd9Sstevel@tonic-gate &pntfy32, sizeof (port_notify32_t))) { 21437c478bd9Sstevel@tonic-gate releasef(fd); 21447c478bd9Sstevel@tonic-gate return (EFAULT); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate pntfy.portnfy_port = pntfy32.portnfy_port; 214734709573Sraf pntfy.portnfy_user = (void *)(uintptr_t) 214834709573Sraf pntfy32.portnfy_user; 214934709573Sraf aio_use_port = 1; 215034709573Sraf } else if (sigev32->sigev_notify == SIGEV_THREAD) { 215134709573Sraf pntfy.portnfy_port = sigev32->sigev_signo; 215234709573Sraf pntfy.portnfy_user = (void *)(uintptr_t) 215334709573Sraf sigev32->sigev_value.sival_ptr; 21547c478bd9Sstevel@tonic-gate aio_use_port = 1; 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate /* 21607c478bd9Sstevel@tonic-gate * check the permission of the partition 21617c478bd9Sstevel@tonic-gate */ 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate if ((fp->f_flag & mode) == 0) { 21647c478bd9Sstevel@tonic-gate releasef(fd); 21657c478bd9Sstevel@tonic-gate return (EBADF); 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 21697c478bd9Sstevel@tonic-gate aio_func = check_vp(vp, mode); 21707c478bd9Sstevel@tonic-gate if (aio_func == NULL) { 21717c478bd9Sstevel@tonic-gate releasef(fd); 21727c478bd9Sstevel@tonic-gate return (EBADFD); 21737c478bd9Sstevel@tonic-gate } 217434709573Sraf if (run_mode == AIO_LARGEFILE) 2175*d2749ac6SRoger A. Faulkner error = aio_req_setupLF(&reqp, aiop, &aiocb64, resultp, vp, 0); 21767c478bd9Sstevel@tonic-gate else 2177*d2749ac6SRoger A. Faulkner error = aio_req_setup(&reqp, aiop, &aiocb, resultp, vp, 0); 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate if (error) { 21807c478bd9Sstevel@tonic-gate releasef(fd); 21817c478bd9Sstevel@tonic-gate return (error); 21827c478bd9Sstevel@tonic-gate } 21837c478bd9Sstevel@tonic-gate /* 21847c478bd9Sstevel@tonic-gate * enable polling on this request if the opcode has 21857c478bd9Sstevel@tonic-gate * the AIO poll bit set 21867c478bd9Sstevel@tonic-gate */ 21877c478bd9Sstevel@tonic-gate if (opcode & AIO_POLL_BIT) 21887c478bd9Sstevel@tonic-gate reqp->aio_req_flags |= AIO_POLL; 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) 21917c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb = aiocb_arg; 21927c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 21937c478bd9Sstevel@tonic-gate else 21947c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb32 = (caddr32_t)(uintptr_t)aiocb_arg; 21957c478bd9Sstevel@tonic-gate #endif 21967c478bd9Sstevel@tonic-gate 219734709573Sraf if (aio_use_port) { 219834709573Sraf int event = (run_mode == AIO_LARGEFILE)? 219934709573Sraf ((mode == FREAD)? AIOAREAD64 : AIOAWRITE64) : 220034709573Sraf ((mode == FREAD)? AIOAREAD : AIOAWRITE); 220134709573Sraf error = aio_req_assoc_port_rw(&pntfy, aiocb_arg, reqp, event); 220234709573Sraf } 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * send the request to driver. 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate if (error == 0) { 22087c478bd9Sstevel@tonic-gate if (bufsize == 0) { 22097c478bd9Sstevel@tonic-gate clear_active_fd(fd); 22107c478bd9Sstevel@tonic-gate aio_zerolen(reqp); 22117c478bd9Sstevel@tonic-gate return (0); 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, CRED()); 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate /* 22177c478bd9Sstevel@tonic-gate * the fd is stored in the aio_req_t by aio_req_setup(), and 22187c478bd9Sstevel@tonic-gate * is released by the aio_cleanup_thread() when the IO has 22197c478bd9Sstevel@tonic-gate * completed. 22207c478bd9Sstevel@tonic-gate */ 22217c478bd9Sstevel@tonic-gate if (error) { 22227c478bd9Sstevel@tonic-gate releasef(fd); 22237c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 222434b3058fSpraks if (aio_use_port) 222534709573Sraf aio_deq(&aiop->aio_portpending, reqp); 22267c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 22277c478bd9Sstevel@tonic-gate aiop->aio_pending--; 22287c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_REQ_BLOCK) 22297c478bd9Sstevel@tonic-gate cv_signal(&aiop->aio_cleanupcv); 22307c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 22317c478bd9Sstevel@tonic-gate return (error); 22327c478bd9Sstevel@tonic-gate } 22337c478bd9Sstevel@tonic-gate clear_active_fd(fd); 22347c478bd9Sstevel@tonic-gate return (0); 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* 22397c478bd9Sstevel@tonic-gate * set error for a list IO entry that failed. 22407c478bd9Sstevel@tonic-gate */ 22417c478bd9Sstevel@tonic-gate static void 224234b3058fSpraks lio_set_error(aio_req_t *reqp, int portused) 22437c478bd9Sstevel@tonic-gate { 22447c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate if (aiop == NULL) 22477c478bd9Sstevel@tonic-gate return; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 225034b3058fSpraks if (portused) 225134709573Sraf aio_deq(&aiop->aio_portpending, reqp); 22527c478bd9Sstevel@tonic-gate aiop->aio_pending--; 22537c478bd9Sstevel@tonic-gate /* request failed, AIO_PHYSIODONE set to aviod physio cleanup. */ 22547c478bd9Sstevel@tonic-gate reqp->aio_req_flags |= AIO_PHYSIODONE; 22557c478bd9Sstevel@tonic-gate /* 22567c478bd9Sstevel@tonic-gate * Need to free the request now as its never 22577c478bd9Sstevel@tonic-gate * going to get on the done queue 22587c478bd9Sstevel@tonic-gate * 22597c478bd9Sstevel@tonic-gate * Note: aio_outstanding is decremented in 22607c478bd9Sstevel@tonic-gate * aio_req_free() 22617c478bd9Sstevel@tonic-gate */ 22627c478bd9Sstevel@tonic-gate aio_req_free(aiop, reqp); 22637c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_REQ_BLOCK) 22647c478bd9Sstevel@tonic-gate cv_signal(&aiop->aio_cleanupcv); 22657c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate 22687c478bd9Sstevel@tonic-gate /* 22697c478bd9Sstevel@tonic-gate * check if a specified request is done, and remove it from 22707c478bd9Sstevel@tonic-gate * the done queue. otherwise remove anybody from the done queue 22717c478bd9Sstevel@tonic-gate * if NULL is specified. 22727c478bd9Sstevel@tonic-gate */ 22737c478bd9Sstevel@tonic-gate static aio_req_t * 22747c478bd9Sstevel@tonic-gate aio_req_done(void *resultp) 22757c478bd9Sstevel@tonic-gate { 22767c478bd9Sstevel@tonic-gate aio_req_t **bucket; 22777c478bd9Sstevel@tonic-gate aio_req_t *ent; 22787c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 22797c478bd9Sstevel@tonic-gate long index; 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex)); 22827c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex)); 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate if (resultp) { 22857c478bd9Sstevel@tonic-gate index = AIO_HASH(resultp); 22867c478bd9Sstevel@tonic-gate bucket = &aiop->aio_hash[index]; 22877c478bd9Sstevel@tonic-gate for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) { 22887c478bd9Sstevel@tonic-gate if (ent->aio_req_resultp == (aio_result_t *)resultp) { 22897c478bd9Sstevel@tonic-gate if (ent->aio_req_flags & AIO_DONEQ) { 22907c478bd9Sstevel@tonic-gate return (aio_req_remove(ent)); 22917c478bd9Sstevel@tonic-gate } 22927c478bd9Sstevel@tonic-gate return (NULL); 22937c478bd9Sstevel@tonic-gate } 22947c478bd9Sstevel@tonic-gate } 22957c478bd9Sstevel@tonic-gate /* no match, resultp is invalid */ 22967c478bd9Sstevel@tonic-gate return (NULL); 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate return (aio_req_remove(NULL)); 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate /* 23027c478bd9Sstevel@tonic-gate * determine if a user-level resultp pointer is associated with an 23037c478bd9Sstevel@tonic-gate * active IO request. Zero is returned when the request is done, 23047c478bd9Sstevel@tonic-gate * and the request is removed from the done queue. Only when the 23057c478bd9Sstevel@tonic-gate * return value is zero, is the "reqp" pointer valid. One is returned 23067c478bd9Sstevel@tonic-gate * when the request is inprogress. Two is returned when the request 23077c478bd9Sstevel@tonic-gate * is invalid. 23087c478bd9Sstevel@tonic-gate */ 23097c478bd9Sstevel@tonic-gate static int 23107c478bd9Sstevel@tonic-gate aio_req_find(aio_result_t *resultp, aio_req_t **reqp) 23117c478bd9Sstevel@tonic-gate { 23127c478bd9Sstevel@tonic-gate aio_req_t **bucket; 23137c478bd9Sstevel@tonic-gate aio_req_t *ent; 23147c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 23157c478bd9Sstevel@tonic-gate long index; 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex)); 23187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex)); 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate index = AIO_HASH(resultp); 23217c478bd9Sstevel@tonic-gate bucket = &aiop->aio_hash[index]; 23227c478bd9Sstevel@tonic-gate for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) { 23237c478bd9Sstevel@tonic-gate if (ent->aio_req_resultp == resultp) { 23247c478bd9Sstevel@tonic-gate if (ent->aio_req_flags & AIO_DONEQ) { 23257c478bd9Sstevel@tonic-gate *reqp = aio_req_remove(ent); 23267c478bd9Sstevel@tonic-gate return (0); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate return (1); 23297c478bd9Sstevel@tonic-gate } 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate /* no match, resultp is invalid */ 23327c478bd9Sstevel@tonic-gate return (2); 23337c478bd9Sstevel@tonic-gate } 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate /* 23367c478bd9Sstevel@tonic-gate * remove a request from the done queue. 23377c478bd9Sstevel@tonic-gate */ 23387c478bd9Sstevel@tonic-gate static aio_req_t * 23397c478bd9Sstevel@tonic-gate aio_req_remove(aio_req_t *reqp) 23407c478bd9Sstevel@tonic-gate { 23417c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex)); 23447c478bd9Sstevel@tonic-gate 234534709573Sraf if (reqp != NULL) { 23467c478bd9Sstevel@tonic-gate ASSERT(reqp->aio_req_flags & AIO_DONEQ); 23477c478bd9Sstevel@tonic-gate if (reqp->aio_req_next == reqp) { 23487c478bd9Sstevel@tonic-gate /* only one request on queue */ 23497c478bd9Sstevel@tonic-gate if (reqp == aiop->aio_doneq) { 23507c478bd9Sstevel@tonic-gate aiop->aio_doneq = NULL; 23517c478bd9Sstevel@tonic-gate } else { 23527c478bd9Sstevel@tonic-gate ASSERT(reqp == aiop->aio_cleanupq); 23537c478bd9Sstevel@tonic-gate aiop->aio_cleanupq = NULL; 23547c478bd9Sstevel@tonic-gate } 23557c478bd9Sstevel@tonic-gate } else { 23567c478bd9Sstevel@tonic-gate reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev; 23577c478bd9Sstevel@tonic-gate reqp->aio_req_prev->aio_req_next = reqp->aio_req_next; 23587c478bd9Sstevel@tonic-gate /* 23597c478bd9Sstevel@tonic-gate * The request can be either on the aio_doneq or the 23607c478bd9Sstevel@tonic-gate * aio_cleanupq 23617c478bd9Sstevel@tonic-gate */ 23627c478bd9Sstevel@tonic-gate if (reqp == aiop->aio_doneq) 23637c478bd9Sstevel@tonic-gate aiop->aio_doneq = reqp->aio_req_next; 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate if (reqp == aiop->aio_cleanupq) 23667c478bd9Sstevel@tonic-gate aiop->aio_cleanupq = reqp->aio_req_next; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate reqp->aio_req_flags &= ~AIO_DONEQ; 236934709573Sraf reqp->aio_req_next = NULL; 237034709573Sraf reqp->aio_req_prev = NULL; 237134709573Sraf } else if ((reqp = aiop->aio_doneq) != NULL) { 237234709573Sraf ASSERT(reqp->aio_req_flags & AIO_DONEQ); 237334709573Sraf if (reqp == reqp->aio_req_next) { 23747c478bd9Sstevel@tonic-gate /* only one request on queue */ 23757c478bd9Sstevel@tonic-gate aiop->aio_doneq = NULL; 23767c478bd9Sstevel@tonic-gate } else { 237734709573Sraf reqp->aio_req_prev->aio_req_next = reqp->aio_req_next; 237834709573Sraf reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev; 237934709573Sraf aiop->aio_doneq = reqp->aio_req_next; 23807c478bd9Sstevel@tonic-gate } 238134709573Sraf reqp->aio_req_flags &= ~AIO_DONEQ; 238234709573Sraf reqp->aio_req_next = NULL; 238334709573Sraf reqp->aio_req_prev = NULL; 23847c478bd9Sstevel@tonic-gate } 238534709573Sraf if (aiop->aio_doneq == NULL && (aiop->aio_flags & AIO_WAITN)) 238634709573Sraf cv_broadcast(&aiop->aio_waitcv); 238734709573Sraf return (reqp); 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate static int 23917c478bd9Sstevel@tonic-gate aio_req_setup( 23927c478bd9Sstevel@tonic-gate aio_req_t **reqpp, 23937c478bd9Sstevel@tonic-gate aio_t *aiop, 23947c478bd9Sstevel@tonic-gate aiocb_t *arg, 23957c478bd9Sstevel@tonic-gate aio_result_t *resultp, 2396*d2749ac6SRoger A. Faulkner vnode_t *vp, 2397*d2749ac6SRoger A. Faulkner int old_solaris_req) 23987c478bd9Sstevel@tonic-gate { 239934709573Sraf sigqueue_t *sqp = NULL; 24007c478bd9Sstevel@tonic-gate aio_req_t *reqp; 24017c478bd9Sstevel@tonic-gate struct uio *uio; 24027c478bd9Sstevel@tonic-gate struct sigevent *sigev; 24037c478bd9Sstevel@tonic-gate int error; 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate sigev = &arg->aio_sigevent; 240634709573Sraf if (sigev->sigev_notify == SIGEV_SIGNAL && 240734709573Sraf sigev->sigev_signo > 0 && sigev->sigev_signo < NSIG) { 24087c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP); 24097c478bd9Sstevel@tonic-gate if (sqp == NULL) 24107c478bd9Sstevel@tonic-gate return (EAGAIN); 24117c478bd9Sstevel@tonic-gate sqp->sq_func = NULL; 24127c478bd9Sstevel@tonic-gate sqp->sq_next = NULL; 24137c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_ASYNCIO; 24147c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = curproc->p_pid; 24157c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(curproc); 24167c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 24177c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetuid(curproc->p_cred); 24187c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sigev->sigev_signo; 24197c478bd9Sstevel@tonic-gate sqp->sq_info.si_value = sigev->sigev_value; 242034709573Sraf } 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_REQ_BLOCK) { 24257c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 24267c478bd9Sstevel@tonic-gate if (sqp) 24277c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 24287c478bd9Sstevel@tonic-gate return (EIO); 24297c478bd9Sstevel@tonic-gate } 24307c478bd9Sstevel@tonic-gate /* 24317c478bd9Sstevel@tonic-gate * get an aio_reqp from the free list or allocate one 24327c478bd9Sstevel@tonic-gate * from dynamic memory. 24337c478bd9Sstevel@tonic-gate */ 24347c478bd9Sstevel@tonic-gate if (error = aio_req_alloc(&reqp, resultp)) { 24357c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 24367c478bd9Sstevel@tonic-gate if (sqp) 24377c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 24387c478bd9Sstevel@tonic-gate return (error); 24397c478bd9Sstevel@tonic-gate } 24407c478bd9Sstevel@tonic-gate aiop->aio_pending++; 24417c478bd9Sstevel@tonic-gate aiop->aio_outstanding++; 24427c478bd9Sstevel@tonic-gate reqp->aio_req_flags = AIO_PENDING; 2443*d2749ac6SRoger A. Faulkner if (old_solaris_req) { 2444*d2749ac6SRoger A. Faulkner /* this is an old solaris aio request */ 2445*d2749ac6SRoger A. Faulkner reqp->aio_req_flags |= AIO_SOLARIS; 2446*d2749ac6SRoger A. Faulkner aiop->aio_flags |= AIO_SOLARIS_REQ; 2447*d2749ac6SRoger A. Faulkner } 244834709573Sraf if (sigev->sigev_notify == SIGEV_THREAD || 244934709573Sraf sigev->sigev_notify == SIGEV_PORT) 245034709573Sraf aio_enq(&aiop->aio_portpending, reqp, 0); 24517c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 24527c478bd9Sstevel@tonic-gate /* 24537c478bd9Sstevel@tonic-gate * initialize aio request. 24547c478bd9Sstevel@tonic-gate */ 24557c478bd9Sstevel@tonic-gate reqp->aio_req_fd = arg->aio_fildes; 24567c478bd9Sstevel@tonic-gate reqp->aio_req_sigqp = sqp; 24577c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb = NULL; 245834709573Sraf reqp->aio_req_lio = NULL; 24597c478bd9Sstevel@tonic-gate reqp->aio_req_buf.b_file = vp; 24607c478bd9Sstevel@tonic-gate uio = reqp->aio_req.aio_uio; 24617c478bd9Sstevel@tonic-gate uio->uio_iovcnt = 1; 24627c478bd9Sstevel@tonic-gate uio->uio_iov->iov_base = (caddr_t)arg->aio_buf; 24637c478bd9Sstevel@tonic-gate uio->uio_iov->iov_len = arg->aio_nbytes; 24647c478bd9Sstevel@tonic-gate uio->uio_loffset = arg->aio_offset; 24657c478bd9Sstevel@tonic-gate *reqpp = reqp; 24667c478bd9Sstevel@tonic-gate return (0); 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * Allocate p_aio struct. 24717c478bd9Sstevel@tonic-gate */ 24727c478bd9Sstevel@tonic-gate static aio_t * 24737c478bd9Sstevel@tonic-gate aio_aiop_alloc(void) 24747c478bd9Sstevel@tonic-gate { 24757c478bd9Sstevel@tonic-gate aio_t *aiop; 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&curproc->p_lock)); 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate aiop = kmem_zalloc(sizeof (struct aio), KM_NOSLEEP); 24807c478bd9Sstevel@tonic-gate if (aiop) { 24817c478bd9Sstevel@tonic-gate mutex_init(&aiop->aio_mutex, NULL, MUTEX_DEFAULT, NULL); 24827c478bd9Sstevel@tonic-gate mutex_init(&aiop->aio_cleanupq_mutex, NULL, MUTEX_DEFAULT, 24837c478bd9Sstevel@tonic-gate NULL); 24847c478bd9Sstevel@tonic-gate mutex_init(&aiop->aio_portq_mutex, NULL, MUTEX_DEFAULT, NULL); 24857c478bd9Sstevel@tonic-gate } 24867c478bd9Sstevel@tonic-gate return (aiop); 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate /* 24907c478bd9Sstevel@tonic-gate * Allocate an aio_req struct. 24917c478bd9Sstevel@tonic-gate */ 24927c478bd9Sstevel@tonic-gate static int 24937c478bd9Sstevel@tonic-gate aio_req_alloc(aio_req_t **nreqp, aio_result_t *resultp) 24947c478bd9Sstevel@tonic-gate { 24957c478bd9Sstevel@tonic-gate aio_req_t *reqp; 24967c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 24977c478bd9Sstevel@tonic-gate 24987c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex)); 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate if ((reqp = aiop->aio_free) != NULL) { 25017c478bd9Sstevel@tonic-gate aiop->aio_free = reqp->aio_req_next; 250234709573Sraf bzero(reqp, sizeof (*reqp)); 25037c478bd9Sstevel@tonic-gate } else { 25047c478bd9Sstevel@tonic-gate /* 25057c478bd9Sstevel@tonic-gate * Check whether memory is getting tight. 25067c478bd9Sstevel@tonic-gate * This is a temporary mechanism to avoid memory 25077c478bd9Sstevel@tonic-gate * exhaustion by a single process until we come up 25087c478bd9Sstevel@tonic-gate * with a per process solution such as setrlimit(). 25097c478bd9Sstevel@tonic-gate */ 25107c478bd9Sstevel@tonic-gate if (freemem < desfree) 25117c478bd9Sstevel@tonic-gate return (EAGAIN); 25127c478bd9Sstevel@tonic-gate reqp = kmem_zalloc(sizeof (struct aio_req_t), KM_NOSLEEP); 25137c478bd9Sstevel@tonic-gate if (reqp == NULL) 25147c478bd9Sstevel@tonic-gate return (EAGAIN); 25157c478bd9Sstevel@tonic-gate } 251634709573Sraf reqp->aio_req.aio_uio = &reqp->aio_req_uio; 251734709573Sraf reqp->aio_req.aio_uio->uio_iov = &reqp->aio_req_iov; 251834709573Sraf reqp->aio_req.aio_private = reqp; 25197c478bd9Sstevel@tonic-gate reqp->aio_req_buf.b_offset = -1; 25207c478bd9Sstevel@tonic-gate reqp->aio_req_resultp = resultp; 25217c478bd9Sstevel@tonic-gate if (aio_hash_insert(reqp, aiop)) { 25227c478bd9Sstevel@tonic-gate reqp->aio_req_next = aiop->aio_free; 25237c478bd9Sstevel@tonic-gate aiop->aio_free = reqp; 252475e1bcdeSPrakash Sangappa return (EBUSY); 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate *nreqp = reqp; 25277c478bd9Sstevel@tonic-gate return (0); 25287c478bd9Sstevel@tonic-gate } 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate /* 25317c478bd9Sstevel@tonic-gate * Allocate an aio_lio_t struct. 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate static int 25347c478bd9Sstevel@tonic-gate aio_lio_alloc(aio_lio_t **head) 25357c478bd9Sstevel@tonic-gate { 25367c478bd9Sstevel@tonic-gate aio_lio_t *liop; 25377c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex)); 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate if ((liop = aiop->aio_lio_free) != NULL) { 25427c478bd9Sstevel@tonic-gate aiop->aio_lio_free = liop->lio_next; 25437c478bd9Sstevel@tonic-gate } else { 25447c478bd9Sstevel@tonic-gate /* 25457c478bd9Sstevel@tonic-gate * Check whether memory is getting tight. 25467c478bd9Sstevel@tonic-gate * This is a temporary mechanism to avoid memory 25477c478bd9Sstevel@tonic-gate * exhaustion by a single process until we come up 25487c478bd9Sstevel@tonic-gate * with a per process solution such as setrlimit(). 25497c478bd9Sstevel@tonic-gate */ 25507c478bd9Sstevel@tonic-gate if (freemem < desfree) 25517c478bd9Sstevel@tonic-gate return (EAGAIN); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate liop = kmem_zalloc(sizeof (aio_lio_t), KM_NOSLEEP); 25547c478bd9Sstevel@tonic-gate if (liop == NULL) 25557c478bd9Sstevel@tonic-gate return (EAGAIN); 25567c478bd9Sstevel@tonic-gate } 25577c478bd9Sstevel@tonic-gate *head = liop; 25587c478bd9Sstevel@tonic-gate return (0); 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate /* 25627c478bd9Sstevel@tonic-gate * this is a special per-process thread that is only activated if 25637c478bd9Sstevel@tonic-gate * the process is unmapping a segment with outstanding aio. normally, 25647c478bd9Sstevel@tonic-gate * the process will have completed the aio before unmapping the 25657c478bd9Sstevel@tonic-gate * segment. If the process does unmap a segment with outstanding aio, 25667c478bd9Sstevel@tonic-gate * this special thread will guarentee that the locked pages due to 25677c478bd9Sstevel@tonic-gate * aphysio() are released, thereby permitting the segment to be 2568b0b27ce6Spraks * unmapped. In addition to this, the cleanup thread is woken up 2569b0b27ce6Spraks * during DR operations to release the locked pages. 25707c478bd9Sstevel@tonic-gate */ 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate static int 25737c478bd9Sstevel@tonic-gate aio_cleanup_thread(aio_t *aiop) 25747c478bd9Sstevel@tonic-gate { 25757c478bd9Sstevel@tonic-gate proc_t *p = curproc; 25767c478bd9Sstevel@tonic-gate struct as *as = p->p_as; 25777c478bd9Sstevel@tonic-gate int poked = 0; 25787c478bd9Sstevel@tonic-gate kcondvar_t *cvp; 25797c478bd9Sstevel@tonic-gate int exit_flag = 0; 2580b0b27ce6Spraks int rqclnup = 0; 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate sigfillset(&curthread->t_hold); 25837c478bd9Sstevel@tonic-gate sigdiffset(&curthread->t_hold, &cantmask); 25847c478bd9Sstevel@tonic-gate for (;;) { 25857c478bd9Sstevel@tonic-gate /* 25867c478bd9Sstevel@tonic-gate * if a segment is being unmapped, and the current 25877c478bd9Sstevel@tonic-gate * process's done queue is not empty, then every request 25887c478bd9Sstevel@tonic-gate * on the doneq with locked resources should be forced 25897c478bd9Sstevel@tonic-gate * to release their locks. By moving the doneq request 25907c478bd9Sstevel@tonic-gate * to the cleanupq, aio_cleanup() will process the cleanupq, 25917c478bd9Sstevel@tonic-gate * and place requests back onto the doneq. All requests 25927c478bd9Sstevel@tonic-gate * processed by aio_cleanup() will have their physical 25937c478bd9Sstevel@tonic-gate * resources unlocked. 25947c478bd9Sstevel@tonic-gate */ 25957c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 25967c478bd9Sstevel@tonic-gate if ((aiop->aio_flags & AIO_CLEANUP) == 0) { 25977c478bd9Sstevel@tonic-gate aiop->aio_flags |= AIO_CLEANUP; 25987c478bd9Sstevel@tonic-gate mutex_enter(&as->a_contents); 2599b0b27ce6Spraks if (aiop->aio_rqclnup) { 2600b0b27ce6Spraks aiop->aio_rqclnup = 0; 2601b0b27ce6Spraks rqclnup = 1; 2602b0b27ce6Spraks } 26037c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 260416660111SSurya Prakki if (aiop->aio_doneq) { 260516660111SSurya Prakki aio_req_t *doneqhead = aiop->aio_doneq; 26067c478bd9Sstevel@tonic-gate aiop->aio_doneq = NULL; 26077c478bd9Sstevel@tonic-gate aio_cleanupq_concat(aiop, doneqhead, AIO_DONEQ); 26087c478bd9Sstevel@tonic-gate } 26097c478bd9Sstevel@tonic-gate } 26107c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 26117c478bd9Sstevel@tonic-gate aio_cleanup(AIO_CLEANUP_THREAD); 26127c478bd9Sstevel@tonic-gate /* 26137c478bd9Sstevel@tonic-gate * thread should block on the cleanupcv while 26147c478bd9Sstevel@tonic-gate * AIO_CLEANUP is set. 26157c478bd9Sstevel@tonic-gate */ 26167c478bd9Sstevel@tonic-gate cvp = &aiop->aio_cleanupcv; 26177c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate if (aiop->aio_pollq != NULL || aiop->aio_cleanupq != NULL || 26207c478bd9Sstevel@tonic-gate aiop->aio_notifyq != NULL || 26217c478bd9Sstevel@tonic-gate aiop->aio_portcleanupq != NULL) { 26227c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 26237c478bd9Sstevel@tonic-gate continue; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate mutex_enter(&as->a_contents); 26267c478bd9Sstevel@tonic-gate 26277c478bd9Sstevel@tonic-gate /* 26287c478bd9Sstevel@tonic-gate * AIO_CLEANUP determines when the cleanup thread 2629b0b27ce6Spraks * should be active. This flag is set when 2630b0b27ce6Spraks * the cleanup thread is awakened by as_unmap() or 2631b0b27ce6Spraks * due to DR operations. 26327c478bd9Sstevel@tonic-gate * The flag is cleared when the blocking as_unmap() 26337c478bd9Sstevel@tonic-gate * that originally awakened us is allowed to 26347c478bd9Sstevel@tonic-gate * complete. as_unmap() blocks when trying to 26357c478bd9Sstevel@tonic-gate * unmap a segment that has SOFTLOCKed pages. when 26367c478bd9Sstevel@tonic-gate * the segment's pages are all SOFTUNLOCKed, 2637b0b27ce6Spraks * as->a_flags & AS_UNMAPWAIT should be zero. 2638b0b27ce6Spraks * 2639b0b27ce6Spraks * In case of cleanup request by DR, the flag is cleared 2640b0b27ce6Spraks * once all the pending aio requests have been processed. 2641b0b27ce6Spraks * 2642b0b27ce6Spraks * The flag shouldn't be cleared right away if the 2643b0b27ce6Spraks * cleanup thread was interrupted because the process 2644b0b27ce6Spraks * is doing forkall(). This happens when cv_wait_sig() 2645b0b27ce6Spraks * returns zero, because it was awakened by a pokelwps(). 2646b0b27ce6Spraks * If the process is not exiting, it must be doing forkall(). 26477c478bd9Sstevel@tonic-gate */ 26487c478bd9Sstevel@tonic-gate if ((poked == 0) && 2649b0b27ce6Spraks ((!rqclnup && (AS_ISUNMAPWAIT(as) == 0)) || 2650b0b27ce6Spraks (aiop->aio_pending == 0))) { 26517c478bd9Sstevel@tonic-gate aiop->aio_flags &= ~(AIO_CLEANUP | AIO_CLEANUP_PORT); 26527c478bd9Sstevel@tonic-gate cvp = &as->a_cv; 2653b0b27ce6Spraks rqclnup = 0; 26547c478bd9Sstevel@tonic-gate } 26557c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 26567c478bd9Sstevel@tonic-gate if (poked) { 26577c478bd9Sstevel@tonic-gate /* 26587c478bd9Sstevel@tonic-gate * If the process is exiting/killed, don't return 26597c478bd9Sstevel@tonic-gate * immediately without waiting for pending I/O's 26607c478bd9Sstevel@tonic-gate * and releasing the page locks. 26617c478bd9Sstevel@tonic-gate */ 26627c478bd9Sstevel@tonic-gate if (p->p_flag & (SEXITLWPS|SKILLED)) { 26637c478bd9Sstevel@tonic-gate /* 26647c478bd9Sstevel@tonic-gate * If exit_flag is set, then it is 26657c478bd9Sstevel@tonic-gate * safe to exit because we have released 26667c478bd9Sstevel@tonic-gate * page locks of completed I/O's. 26677c478bd9Sstevel@tonic-gate */ 26687c478bd9Sstevel@tonic-gate if (exit_flag) 26697c478bd9Sstevel@tonic-gate break; 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate /* 26747c478bd9Sstevel@tonic-gate * Wait for all the pending aio to complete. 26757c478bd9Sstevel@tonic-gate */ 26767c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 26777c478bd9Sstevel@tonic-gate aiop->aio_flags |= AIO_REQ_BLOCK; 26787c478bd9Sstevel@tonic-gate while (aiop->aio_pending != 0) 26797c478bd9Sstevel@tonic-gate cv_wait(&aiop->aio_cleanupcv, 26807c478bd9Sstevel@tonic-gate &aiop->aio_mutex); 26817c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 26827c478bd9Sstevel@tonic-gate exit_flag = 1; 26837c478bd9Sstevel@tonic-gate continue; 26847c478bd9Sstevel@tonic-gate } else if (p->p_flag & 26857c478bd9Sstevel@tonic-gate (SHOLDFORK|SHOLDFORK1|SHOLDWATCH)) { 26867c478bd9Sstevel@tonic-gate /* 26877c478bd9Sstevel@tonic-gate * hold LWP until it 26887c478bd9Sstevel@tonic-gate * is continued. 26897c478bd9Sstevel@tonic-gate */ 26907c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 26917c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 26927c478bd9Sstevel@tonic-gate stop(PR_SUSPENDED, SUSPEND_NORMAL); 26937c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 26947c478bd9Sstevel@tonic-gate poked = 0; 26957c478bd9Sstevel@tonic-gate continue; 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate } else { 26987c478bd9Sstevel@tonic-gate /* 26997c478bd9Sstevel@tonic-gate * When started this thread will sleep on as->a_cv. 27007c478bd9Sstevel@tonic-gate * as_unmap will awake this thread if the 27017c478bd9Sstevel@tonic-gate * segment has SOFTLOCKed pages (poked = 0). 27027c478bd9Sstevel@tonic-gate * 1. pokelwps() awakes this thread => 27037c478bd9Sstevel@tonic-gate * break the loop to check SEXITLWPS, SHOLDFORK, etc 27047c478bd9Sstevel@tonic-gate * 2. as_unmap awakes this thread => 27057c478bd9Sstevel@tonic-gate * to break the loop it is necessary that 27067c478bd9Sstevel@tonic-gate * - AS_UNMAPWAIT is set (as_unmap is waiting for 27077c478bd9Sstevel@tonic-gate * memory to be unlocked) 27087c478bd9Sstevel@tonic-gate * - AIO_CLEANUP is not set 27097c478bd9Sstevel@tonic-gate * (if AIO_CLEANUP is set we have to wait for 27107c478bd9Sstevel@tonic-gate * pending requests. aio_done will send a signal 27117c478bd9Sstevel@tonic-gate * for every request which completes to continue 27127c478bd9Sstevel@tonic-gate * unmapping the corresponding address range) 2713b0b27ce6Spraks * 3. A cleanup request will wake this thread up, ex. 2714b0b27ce6Spraks * by the DR operations. The aio_rqclnup flag will 2715b0b27ce6Spraks * be set. 27167c478bd9Sstevel@tonic-gate */ 27177c478bd9Sstevel@tonic-gate while (poked == 0) { 2718b0b27ce6Spraks /* 2719fa7f62f0Ssp92102 * The clean up requests that came in 2720fa7f62f0Ssp92102 * after we had just cleaned up, couldn't 2721fa7f62f0Ssp92102 * be causing the unmap thread to block - as 2722fa7f62f0Ssp92102 * unmap event happened first. 2723fa7f62f0Ssp92102 * Let aio_done() wake us up if it sees a need. 2724b0b27ce6Spraks */ 2725fa7f62f0Ssp92102 if (aiop->aio_rqclnup && 2726b0b27ce6Spraks (aiop->aio_flags & AIO_CLEANUP) == 0) 27277c478bd9Sstevel@tonic-gate break; 27287c478bd9Sstevel@tonic-gate poked = !cv_wait_sig(cvp, &as->a_contents); 27297c478bd9Sstevel@tonic-gate if (AS_ISUNMAPWAIT(as) == 0) 27307c478bd9Sstevel@tonic-gate cv_signal(cvp); 27317c478bd9Sstevel@tonic-gate if (aiop->aio_outstanding != 0) 27327c478bd9Sstevel@tonic-gate break; 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate } 27357c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 27367c478bd9Sstevel@tonic-gate } 27377c478bd9Sstevel@tonic-gate exit: 27387c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 27397c478bd9Sstevel@tonic-gate ASSERT((curproc->p_flag & (SEXITLWPS|SKILLED))); 27407c478bd9Sstevel@tonic-gate aston(curthread); /* make thread do post_syscall */ 27417c478bd9Sstevel@tonic-gate return (0); 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate /* 27457c478bd9Sstevel@tonic-gate * save a reference to a user's outstanding aio in a hash list. 27467c478bd9Sstevel@tonic-gate */ 27477c478bd9Sstevel@tonic-gate static int 27487c478bd9Sstevel@tonic-gate aio_hash_insert( 27497c478bd9Sstevel@tonic-gate aio_req_t *aio_reqp, 27507c478bd9Sstevel@tonic-gate aio_t *aiop) 27517c478bd9Sstevel@tonic-gate { 27527c478bd9Sstevel@tonic-gate long index; 27537c478bd9Sstevel@tonic-gate aio_result_t *resultp = aio_reqp->aio_req_resultp; 27547c478bd9Sstevel@tonic-gate aio_req_t *current; 27557c478bd9Sstevel@tonic-gate aio_req_t **nextp; 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate index = AIO_HASH(resultp); 27587c478bd9Sstevel@tonic-gate nextp = &aiop->aio_hash[index]; 27597c478bd9Sstevel@tonic-gate while ((current = *nextp) != NULL) { 27607c478bd9Sstevel@tonic-gate if (current->aio_req_resultp == resultp) 27617c478bd9Sstevel@tonic-gate return (DUPLICATE); 27627c478bd9Sstevel@tonic-gate nextp = ¤t->aio_hash_next; 27637c478bd9Sstevel@tonic-gate } 27647c478bd9Sstevel@tonic-gate *nextp = aio_reqp; 27657c478bd9Sstevel@tonic-gate aio_reqp->aio_hash_next = NULL; 27667c478bd9Sstevel@tonic-gate return (0); 27677c478bd9Sstevel@tonic-gate } 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate static int 27707c478bd9Sstevel@tonic-gate (*check_vp(struct vnode *vp, int mode))(vnode_t *, struct aio_req *, 27717c478bd9Sstevel@tonic-gate cred_t *) 27727c478bd9Sstevel@tonic-gate { 27737c478bd9Sstevel@tonic-gate struct snode *sp; 27747c478bd9Sstevel@tonic-gate dev_t dev; 27757c478bd9Sstevel@tonic-gate struct cb_ops *cb; 27767c478bd9Sstevel@tonic-gate major_t major; 27777c478bd9Sstevel@tonic-gate int (*aio_func)(); 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate dev = vp->v_rdev; 27807c478bd9Sstevel@tonic-gate major = getmajor(dev); 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate /* 27837c478bd9Sstevel@tonic-gate * return NULL for requests to files and STREAMs so 27847c478bd9Sstevel@tonic-gate * that libaio takes care of them. 27857c478bd9Sstevel@tonic-gate */ 27867c478bd9Sstevel@tonic-gate if (vp->v_type == VCHR) { 27877c478bd9Sstevel@tonic-gate /* no stream device for kaio */ 27887c478bd9Sstevel@tonic-gate if (STREAMSTAB(major)) { 27897c478bd9Sstevel@tonic-gate return (NULL); 27907c478bd9Sstevel@tonic-gate } 27917c478bd9Sstevel@tonic-gate } else { 27927c478bd9Sstevel@tonic-gate return (NULL); 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate /* 27967c478bd9Sstevel@tonic-gate * Check old drivers which do not have async I/O entry points. 27977c478bd9Sstevel@tonic-gate */ 27987c478bd9Sstevel@tonic-gate if (devopsp[major]->devo_rev < 3) 27997c478bd9Sstevel@tonic-gate return (NULL); 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate cb = devopsp[major]->devo_cb_ops; 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate if (cb->cb_rev < 1) 28047c478bd9Sstevel@tonic-gate return (NULL); 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate /* 28077c478bd9Sstevel@tonic-gate * Check whether this device is a block device. 28087c478bd9Sstevel@tonic-gate * Kaio is not supported for devices like tty. 28097c478bd9Sstevel@tonic-gate */ 28107c478bd9Sstevel@tonic-gate if (cb->cb_strategy == nodev || cb->cb_strategy == NULL) 28117c478bd9Sstevel@tonic-gate return (NULL); 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* 28147c478bd9Sstevel@tonic-gate * Clustering: If vnode is a PXFS vnode, then the device may be remote. 28157c478bd9Sstevel@tonic-gate * We cannot call the driver directly. Instead return the 28167c478bd9Sstevel@tonic-gate * PXFS functions. 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate if (IS_PXFSVP(vp)) { 28207c478bd9Sstevel@tonic-gate if (mode & FREAD) 28217c478bd9Sstevel@tonic-gate return (clpxfs_aio_read); 28227c478bd9Sstevel@tonic-gate else 28237c478bd9Sstevel@tonic-gate return (clpxfs_aio_write); 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate if (mode & FREAD) 28267c478bd9Sstevel@tonic-gate aio_func = (cb->cb_aread == nodev) ? NULL : driver_aio_read; 28277c478bd9Sstevel@tonic-gate else 28287c478bd9Sstevel@tonic-gate aio_func = (cb->cb_awrite == nodev) ? NULL : driver_aio_write; 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate /* 28317c478bd9Sstevel@tonic-gate * Do we need this ? 28327c478bd9Sstevel@tonic-gate * nodev returns ENXIO anyway. 28337c478bd9Sstevel@tonic-gate */ 28347c478bd9Sstevel@tonic-gate if (aio_func == nodev) 28357c478bd9Sstevel@tonic-gate return (NULL); 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate sp = VTOS(vp); 28387c478bd9Sstevel@tonic-gate smark(sp, SACC); 28397c478bd9Sstevel@tonic-gate return (aio_func); 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * Clustering: We want check_vp to return a function prototyped 28447c478bd9Sstevel@tonic-gate * correctly that will be common to both PXFS and regular case. 28457c478bd9Sstevel@tonic-gate * We define this intermediate function that will do the right 28467c478bd9Sstevel@tonic-gate * thing for driver cases. 28477c478bd9Sstevel@tonic-gate */ 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate static int 28507c478bd9Sstevel@tonic-gate driver_aio_write(vnode_t *vp, struct aio_req *aio, cred_t *cred_p) 28517c478bd9Sstevel@tonic-gate { 28527c478bd9Sstevel@tonic-gate dev_t dev; 28537c478bd9Sstevel@tonic-gate struct cb_ops *cb; 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VCHR); 28567c478bd9Sstevel@tonic-gate ASSERT(!IS_PXFSVP(vp)); 28577c478bd9Sstevel@tonic-gate dev = VTOS(vp)->s_dev; 28587c478bd9Sstevel@tonic-gate ASSERT(STREAMSTAB(getmajor(dev)) == NULL); 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate cb = devopsp[getmajor(dev)]->devo_cb_ops; 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate ASSERT(cb->cb_awrite != nodev); 28637c478bd9Sstevel@tonic-gate return ((*cb->cb_awrite)(dev, aio, cred_p)); 28647c478bd9Sstevel@tonic-gate } 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate /* 28677c478bd9Sstevel@tonic-gate * Clustering: We want check_vp to return a function prototyped 28687c478bd9Sstevel@tonic-gate * correctly that will be common to both PXFS and regular case. 28697c478bd9Sstevel@tonic-gate * We define this intermediate function that will do the right 28707c478bd9Sstevel@tonic-gate * thing for driver cases. 28717c478bd9Sstevel@tonic-gate */ 28727c478bd9Sstevel@tonic-gate 28737c478bd9Sstevel@tonic-gate static int 28747c478bd9Sstevel@tonic-gate driver_aio_read(vnode_t *vp, struct aio_req *aio, cred_t *cred_p) 28757c478bd9Sstevel@tonic-gate { 28767c478bd9Sstevel@tonic-gate dev_t dev; 28777c478bd9Sstevel@tonic-gate struct cb_ops *cb; 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VCHR); 28807c478bd9Sstevel@tonic-gate ASSERT(!IS_PXFSVP(vp)); 28817c478bd9Sstevel@tonic-gate dev = VTOS(vp)->s_dev; 28827c478bd9Sstevel@tonic-gate ASSERT(!STREAMSTAB(getmajor(dev))); 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate cb = devopsp[getmajor(dev)]->devo_cb_ops; 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate ASSERT(cb->cb_aread != nodev); 28877c478bd9Sstevel@tonic-gate return ((*cb->cb_aread)(dev, aio, cred_p)); 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate /* 28917c478bd9Sstevel@tonic-gate * This routine is called when a largefile call is made by a 32bit 28927c478bd9Sstevel@tonic-gate * process on a ILP32 or LP64 kernel. All 64bit processes are large 28937c478bd9Sstevel@tonic-gate * file by definition and will call alio() instead. 28947c478bd9Sstevel@tonic-gate */ 28957c478bd9Sstevel@tonic-gate static int 28967c478bd9Sstevel@tonic-gate alioLF( 28977c478bd9Sstevel@tonic-gate int mode_arg, 28987c478bd9Sstevel@tonic-gate void *aiocb_arg, 28997c478bd9Sstevel@tonic-gate int nent, 29007c478bd9Sstevel@tonic-gate void *sigev) 29017c478bd9Sstevel@tonic-gate { 29027c478bd9Sstevel@tonic-gate file_t *fp; 29037c478bd9Sstevel@tonic-gate file_t *prev_fp = NULL; 29047c478bd9Sstevel@tonic-gate int prev_mode = -1; 29057c478bd9Sstevel@tonic-gate struct vnode *vp; 29067c478bd9Sstevel@tonic-gate aio_lio_t *head; 29077c478bd9Sstevel@tonic-gate aio_req_t *reqp; 29087c478bd9Sstevel@tonic-gate aio_t *aiop; 29097c478bd9Sstevel@tonic-gate caddr_t cbplist; 29107c478bd9Sstevel@tonic-gate aiocb64_32_t cb64; 29117c478bd9Sstevel@tonic-gate aiocb64_32_t *aiocb = &cb64; 291234709573Sraf aiocb64_32_t *cbp; 291334709573Sraf caddr32_t *ucbp; 29147c478bd9Sstevel@tonic-gate #ifdef _LP64 29157c478bd9Sstevel@tonic-gate aiocb_t aiocb_n; 29167c478bd9Sstevel@tonic-gate #endif 29177c478bd9Sstevel@tonic-gate struct sigevent32 sigevk; 29187c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 29197c478bd9Sstevel@tonic-gate int (*aio_func)(); 29207c478bd9Sstevel@tonic-gate int mode; 292134709573Sraf int error = 0; 292234709573Sraf int aio_errors = 0; 29237c478bd9Sstevel@tonic-gate int i; 29247c478bd9Sstevel@tonic-gate size_t ssize; 29257c478bd9Sstevel@tonic-gate int deadhead = 0; 29267c478bd9Sstevel@tonic-gate int aio_notsupported = 0; 292734709573Sraf int lio_head_port; 292834709573Sraf int aio_port; 292934709573Sraf int aio_thread; 29307c478bd9Sstevel@tonic-gate port_kevent_t *pkevtp = NULL; 293134b3058fSpraks int portused = 0; 29327c478bd9Sstevel@tonic-gate port_notify32_t pnotify; 293334709573Sraf int event; 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 29367c478bd9Sstevel@tonic-gate if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX) 29377c478bd9Sstevel@tonic-gate return (EINVAL); 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate ASSERT(get_udatamodel() == DATAMODEL_ILP32); 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate ssize = (sizeof (caddr32_t) * nent); 29427c478bd9Sstevel@tonic-gate cbplist = kmem_alloc(ssize, KM_SLEEP); 29437c478bd9Sstevel@tonic-gate ucbp = (caddr32_t *)cbplist; 29447c478bd9Sstevel@tonic-gate 294534709573Sraf if (copyin(aiocb_arg, cbplist, ssize) || 294634709573Sraf (sigev && copyin(sigev, &sigevk, sizeof (sigevk)))) { 29477c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 29487c478bd9Sstevel@tonic-gate return (EFAULT); 29497c478bd9Sstevel@tonic-gate } 29507c478bd9Sstevel@tonic-gate 295134709573Sraf /* Event Ports */ 295234709573Sraf if (sigev && 295334709573Sraf (sigevk.sigev_notify == SIGEV_THREAD || 295434709573Sraf sigevk.sigev_notify == SIGEV_PORT)) { 295534709573Sraf if (sigevk.sigev_notify == SIGEV_THREAD) { 295634709573Sraf pnotify.portnfy_port = sigevk.sigev_signo; 295734709573Sraf pnotify.portnfy_user = sigevk.sigev_value.sival_ptr; 295834709573Sraf } else if (copyin( 295934709573Sraf (void *)(uintptr_t)sigevk.sigev_value.sival_ptr, 296034709573Sraf &pnotify, sizeof (pnotify))) { 29617c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 29627c478bd9Sstevel@tonic-gate return (EFAULT); 29637c478bd9Sstevel@tonic-gate } 296434709573Sraf error = port_alloc_event(pnotify.portnfy_port, 296534709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp); 296634709573Sraf if (error) { 296734709573Sraf if (error == ENOMEM || error == EAGAIN) 296834709573Sraf error = EAGAIN; 296934709573Sraf else 297034709573Sraf error = EINVAL; 297134709573Sraf kmem_free(cbplist, ssize); 297234709573Sraf return (error); 297334709573Sraf } 297434709573Sraf lio_head_port = pnotify.portnfy_port; 297534b3058fSpraks portused = 1; 29767c478bd9Sstevel@tonic-gate } 29777c478bd9Sstevel@tonic-gate 29787c478bd9Sstevel@tonic-gate /* 29797c478bd9Sstevel@tonic-gate * a list head should be allocated if notification is 29807c478bd9Sstevel@tonic-gate * enabled for this list. 29817c478bd9Sstevel@tonic-gate */ 29827c478bd9Sstevel@tonic-gate head = NULL; 29837c478bd9Sstevel@tonic-gate 298434709573Sraf if (mode_arg == LIO_WAIT || sigev) { 29857c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 29867c478bd9Sstevel@tonic-gate error = aio_lio_alloc(&head); 29877c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 29887c478bd9Sstevel@tonic-gate if (error) 29897c478bd9Sstevel@tonic-gate goto done; 29907c478bd9Sstevel@tonic-gate deadhead = 1; 29917c478bd9Sstevel@tonic-gate head->lio_nent = nent; 29927c478bd9Sstevel@tonic-gate head->lio_refcnt = nent; 299334709573Sraf head->lio_port = -1; 299434709573Sraf head->lio_portkev = NULL; 299534709573Sraf if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL && 299634709573Sraf sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) { 29977c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP); 29987c478bd9Sstevel@tonic-gate if (sqp == NULL) { 29997c478bd9Sstevel@tonic-gate error = EAGAIN; 30007c478bd9Sstevel@tonic-gate goto done; 30017c478bd9Sstevel@tonic-gate } 30027c478bd9Sstevel@tonic-gate sqp->sq_func = NULL; 30037c478bd9Sstevel@tonic-gate sqp->sq_next = NULL; 30047c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_ASYNCIO; 30057c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = curproc->p_pid; 30067c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(curproc); 30077c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 30087c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetuid(curproc->p_cred); 30097c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sigevk.sigev_signo; 30107c478bd9Sstevel@tonic-gate sqp->sq_info.si_value.sival_int = 30117c478bd9Sstevel@tonic-gate sigevk.sigev_value.sival_int; 30127c478bd9Sstevel@tonic-gate head->lio_sigqp = sqp; 30137c478bd9Sstevel@tonic-gate } else { 30147c478bd9Sstevel@tonic-gate head->lio_sigqp = NULL; 30157c478bd9Sstevel@tonic-gate } 301634709573Sraf if (pkevtp) { 301734709573Sraf /* 301834709573Sraf * Prepare data to send when list of aiocb's 301934709573Sraf * has completed. 302034709573Sraf */ 302134709573Sraf port_init_event(pkevtp, (uintptr_t)sigev, 302234709573Sraf (void *)(uintptr_t)pnotify.portnfy_user, 302334709573Sraf NULL, head); 302434709573Sraf pkevtp->portkev_events = AIOLIO64; 302534709573Sraf head->lio_portkev = pkevtp; 302634709573Sraf head->lio_port = pnotify.portnfy_port; 302734709573Sraf } 30287c478bd9Sstevel@tonic-gate } 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++, ucbp++) { 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate cbp = (aiocb64_32_t *)(uintptr_t)*ucbp; 30337c478bd9Sstevel@tonic-gate /* skip entry if it can't be copied. */ 303434709573Sraf if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb))) { 30357c478bd9Sstevel@tonic-gate if (head) { 30367c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 30377c478bd9Sstevel@tonic-gate head->lio_nent--; 30387c478bd9Sstevel@tonic-gate head->lio_refcnt--; 30397c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 30407c478bd9Sstevel@tonic-gate } 30417c478bd9Sstevel@tonic-gate continue; 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate /* skip if opcode for aiocb is LIO_NOP */ 30457c478bd9Sstevel@tonic-gate mode = aiocb->aio_lio_opcode; 30467c478bd9Sstevel@tonic-gate if (mode == LIO_NOP) { 30477c478bd9Sstevel@tonic-gate cbp = NULL; 30487c478bd9Sstevel@tonic-gate if (head) { 30497c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 30507c478bd9Sstevel@tonic-gate head->lio_nent--; 30517c478bd9Sstevel@tonic-gate head->lio_refcnt--; 30527c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 30537c478bd9Sstevel@tonic-gate } 30547c478bd9Sstevel@tonic-gate continue; 30557c478bd9Sstevel@tonic-gate } 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate /* increment file descriptor's ref count. */ 30587c478bd9Sstevel@tonic-gate if ((fp = getf(aiocb->aio_fildes)) == NULL) { 30597c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 30607c478bd9Sstevel@tonic-gate if (head) { 30617c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 30627c478bd9Sstevel@tonic-gate head->lio_nent--; 30637c478bd9Sstevel@tonic-gate head->lio_refcnt--; 30647c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 30657c478bd9Sstevel@tonic-gate } 30667c478bd9Sstevel@tonic-gate aio_errors++; 30677c478bd9Sstevel@tonic-gate continue; 30687c478bd9Sstevel@tonic-gate } 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate /* 30717c478bd9Sstevel@tonic-gate * check the permission of the partition 30727c478bd9Sstevel@tonic-gate */ 30737c478bd9Sstevel@tonic-gate if ((fp->f_flag & mode) == 0) { 30747c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 30757c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 30767c478bd9Sstevel@tonic-gate if (head) { 30777c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 30787c478bd9Sstevel@tonic-gate head->lio_nent--; 30797c478bd9Sstevel@tonic-gate head->lio_refcnt--; 30807c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 30817c478bd9Sstevel@tonic-gate } 30827c478bd9Sstevel@tonic-gate aio_errors++; 30837c478bd9Sstevel@tonic-gate continue; 30847c478bd9Sstevel@tonic-gate } 30857c478bd9Sstevel@tonic-gate 30867c478bd9Sstevel@tonic-gate /* 30877c478bd9Sstevel@tonic-gate * common case where requests are to the same fd 30887c478bd9Sstevel@tonic-gate * for the same r/w operation 30897c478bd9Sstevel@tonic-gate * for UFS, need to set EBADFD 30907c478bd9Sstevel@tonic-gate */ 309134709573Sraf vp = fp->f_vnode; 309234709573Sraf if (fp != prev_fp || mode != prev_mode) { 30937c478bd9Sstevel@tonic-gate aio_func = check_vp(vp, mode); 30947c478bd9Sstevel@tonic-gate if (aio_func == NULL) { 30957c478bd9Sstevel@tonic-gate prev_fp = NULL; 30967c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 30977c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADFD); 30987c478bd9Sstevel@tonic-gate aio_notsupported++; 30997c478bd9Sstevel@tonic-gate if (head) { 31007c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 31017c478bd9Sstevel@tonic-gate head->lio_nent--; 31027c478bd9Sstevel@tonic-gate head->lio_refcnt--; 31037c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 31047c478bd9Sstevel@tonic-gate } 31057c478bd9Sstevel@tonic-gate continue; 31067c478bd9Sstevel@tonic-gate } else { 31077c478bd9Sstevel@tonic-gate prev_fp = fp; 31087c478bd9Sstevel@tonic-gate prev_mode = mode; 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate } 311134709573Sraf 31127c478bd9Sstevel@tonic-gate #ifdef _LP64 31137c478bd9Sstevel@tonic-gate aiocb_LFton(aiocb, &aiocb_n); 31147c478bd9Sstevel@tonic-gate error = aio_req_setup(&reqp, aiop, &aiocb_n, 3115*d2749ac6SRoger A. Faulkner (aio_result_t *)&cbp->aio_resultp, vp, 0); 31167c478bd9Sstevel@tonic-gate #else 31177c478bd9Sstevel@tonic-gate error = aio_req_setupLF(&reqp, aiop, aiocb, 3118*d2749ac6SRoger A. Faulkner (aio_result_t *)&cbp->aio_resultp, vp, 0); 31197c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 31207c478bd9Sstevel@tonic-gate if (error) { 31217c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 312234709573Sraf lio_set_uerror(&cbp->aio_resultp, error); 31237c478bd9Sstevel@tonic-gate if (head) { 31247c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 31257c478bd9Sstevel@tonic-gate head->lio_nent--; 31267c478bd9Sstevel@tonic-gate head->lio_refcnt--; 31277c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 31287c478bd9Sstevel@tonic-gate } 31297c478bd9Sstevel@tonic-gate aio_errors++; 31307c478bd9Sstevel@tonic-gate continue; 31317c478bd9Sstevel@tonic-gate } 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate reqp->aio_req_lio = head; 31347c478bd9Sstevel@tonic-gate deadhead = 0; 31357c478bd9Sstevel@tonic-gate 31367c478bd9Sstevel@tonic-gate /* 31377c478bd9Sstevel@tonic-gate * Set the errno field now before sending the request to 31387c478bd9Sstevel@tonic-gate * the driver to avoid a race condition 31397c478bd9Sstevel@tonic-gate */ 31407c478bd9Sstevel@tonic-gate (void) suword32(&cbp->aio_resultp.aio_errno, 31417c478bd9Sstevel@tonic-gate EINPROGRESS); 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb32 = *ucbp; 31447c478bd9Sstevel@tonic-gate 314534709573Sraf event = (mode == LIO_READ)? AIOAREAD64 : AIOAWRITE64; 314634709573Sraf aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT); 314734709573Sraf aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD); 314834709573Sraf if (aio_port | aio_thread) { 314934709573Sraf port_kevent_t *lpkevp; 315034709573Sraf /* 315134709573Sraf * Prepare data to send with each aiocb completed. 315234709573Sraf */ 315334709573Sraf if (aio_port) { 315434709573Sraf void *paddr = (void *)(uintptr_t) 315534709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 315634709573Sraf if (copyin(paddr, &pnotify, sizeof (pnotify))) 315734709573Sraf error = EFAULT; 315834709573Sraf } else { /* aio_thread */ 315934709573Sraf pnotify.portnfy_port = 316034709573Sraf aiocb->aio_sigevent.sigev_signo; 316134709573Sraf pnotify.portnfy_user = 316234709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 316334709573Sraf } 316434709573Sraf if (error) 316534709573Sraf /* EMPTY */; 316634709573Sraf else if (pkevtp != NULL && 316734709573Sraf pnotify.portnfy_port == lio_head_port) 316834709573Sraf error = port_dup_event(pkevtp, &lpkevp, 316934709573Sraf PORT_ALLOC_DEFAULT); 317034709573Sraf else 317134709573Sraf error = port_alloc_event(pnotify.portnfy_port, 317234709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, 317334709573Sraf &lpkevp); 317434709573Sraf if (error == 0) { 317534709573Sraf port_init_event(lpkevp, (uintptr_t)*ucbp, 31767c478bd9Sstevel@tonic-gate (void *)(uintptr_t)pnotify.portnfy_user, 317734709573Sraf aio_port_callback, reqp); 317834709573Sraf lpkevp->portkev_events = event; 317934709573Sraf reqp->aio_req_portkev = lpkevp; 318034709573Sraf reqp->aio_req_port = pnotify.portnfy_port; 318134709573Sraf } 31827c478bd9Sstevel@tonic-gate } 31837c478bd9Sstevel@tonic-gate 31847c478bd9Sstevel@tonic-gate /* 31857c478bd9Sstevel@tonic-gate * send the request to driver. 31867c478bd9Sstevel@tonic-gate */ 31877c478bd9Sstevel@tonic-gate if (error == 0) { 31887c478bd9Sstevel@tonic-gate if (aiocb->aio_nbytes == 0) { 31897c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 31907c478bd9Sstevel@tonic-gate aio_zerolen(reqp); 31917c478bd9Sstevel@tonic-gate continue; 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, 31947c478bd9Sstevel@tonic-gate CRED()); 31957c478bd9Sstevel@tonic-gate } 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate /* 31987c478bd9Sstevel@tonic-gate * the fd's ref count is not decremented until the IO has 31997c478bd9Sstevel@tonic-gate * completed unless there was an error. 32007c478bd9Sstevel@tonic-gate */ 32017c478bd9Sstevel@tonic-gate if (error) { 32027c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 32037c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, error); 32047c478bd9Sstevel@tonic-gate if (head) { 32057c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 32067c478bd9Sstevel@tonic-gate head->lio_nent--; 32077c478bd9Sstevel@tonic-gate head->lio_refcnt--; 32087c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 32097c478bd9Sstevel@tonic-gate } 32107c478bd9Sstevel@tonic-gate if (error == ENOTSUP) 32117c478bd9Sstevel@tonic-gate aio_notsupported++; 32127c478bd9Sstevel@tonic-gate else 32137c478bd9Sstevel@tonic-gate aio_errors++; 321434b3058fSpraks lio_set_error(reqp, portused); 32157c478bd9Sstevel@tonic-gate } else { 32167c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate } 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate if (aio_notsupported) { 32217c478bd9Sstevel@tonic-gate error = ENOTSUP; 32227c478bd9Sstevel@tonic-gate } else if (aio_errors) { 32237c478bd9Sstevel@tonic-gate /* 32247c478bd9Sstevel@tonic-gate * return EIO if any request failed 32257c478bd9Sstevel@tonic-gate */ 32267c478bd9Sstevel@tonic-gate error = EIO; 32277c478bd9Sstevel@tonic-gate } 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate if (mode_arg == LIO_WAIT) { 32307c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 32317c478bd9Sstevel@tonic-gate while (head->lio_refcnt > 0) { 32327c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) { 32337c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 32347c478bd9Sstevel@tonic-gate error = EINTR; 32357c478bd9Sstevel@tonic-gate goto done; 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate } 32387c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 32397c478bd9Sstevel@tonic-gate alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_LARGEFILE); 32407c478bd9Sstevel@tonic-gate } 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate done: 32437c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 32447c478bd9Sstevel@tonic-gate if (deadhead) { 32457c478bd9Sstevel@tonic-gate if (head->lio_sigqp) 32467c478bd9Sstevel@tonic-gate kmem_free(head->lio_sigqp, sizeof (sigqueue_t)); 324734709573Sraf if (head->lio_portkev) 324834709573Sraf port_free_event(head->lio_portkev); 32497c478bd9Sstevel@tonic-gate kmem_free(head, sizeof (aio_lio_t)); 32507c478bd9Sstevel@tonic-gate } 32517c478bd9Sstevel@tonic-gate return (error); 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 32557c478bd9Sstevel@tonic-gate static void 32567c478bd9Sstevel@tonic-gate aiocb_LFton(aiocb64_32_t *src, aiocb_t *dest) 32577c478bd9Sstevel@tonic-gate { 32587c478bd9Sstevel@tonic-gate dest->aio_fildes = src->aio_fildes; 32597c478bd9Sstevel@tonic-gate dest->aio_buf = (void *)(uintptr_t)src->aio_buf; 32607c478bd9Sstevel@tonic-gate dest->aio_nbytes = (size_t)src->aio_nbytes; 32617c478bd9Sstevel@tonic-gate dest->aio_offset = (off_t)src->aio_offset; 32627c478bd9Sstevel@tonic-gate dest->aio_reqprio = src->aio_reqprio; 32637c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify = src->aio_sigevent.sigev_notify; 32647c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_signo = src->aio_sigevent.sigev_signo; 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate /* 32677c478bd9Sstevel@tonic-gate * See comment in sigqueue32() on handling of 32-bit 32687c478bd9Sstevel@tonic-gate * sigvals in a 64-bit kernel. 32697c478bd9Sstevel@tonic-gate */ 32707c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_value.sival_int = 32717c478bd9Sstevel@tonic-gate (int)src->aio_sigevent.sigev_value.sival_int; 32727c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify_function = (void (*)(union sigval)) 32737c478bd9Sstevel@tonic-gate (uintptr_t)src->aio_sigevent.sigev_notify_function; 32747c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify_attributes = (pthread_attr_t *) 32757c478bd9Sstevel@tonic-gate (uintptr_t)src->aio_sigevent.sigev_notify_attributes; 32767c478bd9Sstevel@tonic-gate dest->aio_sigevent.__sigev_pad2 = src->aio_sigevent.__sigev_pad2; 32777c478bd9Sstevel@tonic-gate dest->aio_lio_opcode = src->aio_lio_opcode; 32787c478bd9Sstevel@tonic-gate dest->aio_state = src->aio_state; 32797c478bd9Sstevel@tonic-gate dest->aio__pad[0] = src->aio__pad[0]; 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate #endif 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate /* 32847c478bd9Sstevel@tonic-gate * This function is used only for largefile calls made by 328534709573Sraf * 32 bit applications. 32867c478bd9Sstevel@tonic-gate */ 32877c478bd9Sstevel@tonic-gate static int 32887c478bd9Sstevel@tonic-gate aio_req_setupLF( 32897c478bd9Sstevel@tonic-gate aio_req_t **reqpp, 32907c478bd9Sstevel@tonic-gate aio_t *aiop, 32917c478bd9Sstevel@tonic-gate aiocb64_32_t *arg, 32927c478bd9Sstevel@tonic-gate aio_result_t *resultp, 3293*d2749ac6SRoger A. Faulkner vnode_t *vp, 3294*d2749ac6SRoger A. Faulkner int old_solaris_req) 32957c478bd9Sstevel@tonic-gate { 329634709573Sraf sigqueue_t *sqp = NULL; 32977c478bd9Sstevel@tonic-gate aio_req_t *reqp; 32987c478bd9Sstevel@tonic-gate struct uio *uio; 329934709573Sraf struct sigevent32 *sigev; 33007c478bd9Sstevel@tonic-gate int error; 33017c478bd9Sstevel@tonic-gate 330234709573Sraf sigev = &arg->aio_sigevent; 330334709573Sraf if (sigev->sigev_notify == SIGEV_SIGNAL && 330434709573Sraf sigev->sigev_signo > 0 && sigev->sigev_signo < NSIG) { 33057c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP); 33067c478bd9Sstevel@tonic-gate if (sqp == NULL) 33077c478bd9Sstevel@tonic-gate return (EAGAIN); 33087c478bd9Sstevel@tonic-gate sqp->sq_func = NULL; 33097c478bd9Sstevel@tonic-gate sqp->sq_next = NULL; 33107c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_ASYNCIO; 33117c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = curproc->p_pid; 33127c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(curproc); 33137c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 33147c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetuid(curproc->p_cred); 33157c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sigev->sigev_signo; 331634709573Sraf sqp->sq_info.si_value.sival_int = sigev->sigev_value.sival_int; 331734709573Sraf } 33187c478bd9Sstevel@tonic-gate 33197c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate if (aiop->aio_flags & AIO_REQ_BLOCK) { 33227c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 33237c478bd9Sstevel@tonic-gate if (sqp) 33247c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 33257c478bd9Sstevel@tonic-gate return (EIO); 33267c478bd9Sstevel@tonic-gate } 33277c478bd9Sstevel@tonic-gate /* 33287c478bd9Sstevel@tonic-gate * get an aio_reqp from the free list or allocate one 33297c478bd9Sstevel@tonic-gate * from dynamic memory. 33307c478bd9Sstevel@tonic-gate */ 33317c478bd9Sstevel@tonic-gate if (error = aio_req_alloc(&reqp, resultp)) { 33327c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 33337c478bd9Sstevel@tonic-gate if (sqp) 33347c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 33357c478bd9Sstevel@tonic-gate return (error); 33367c478bd9Sstevel@tonic-gate } 33377c478bd9Sstevel@tonic-gate aiop->aio_pending++; 33387c478bd9Sstevel@tonic-gate aiop->aio_outstanding++; 33397c478bd9Sstevel@tonic-gate reqp->aio_req_flags = AIO_PENDING; 3340*d2749ac6SRoger A. Faulkner if (old_solaris_req) { 3341*d2749ac6SRoger A. Faulkner /* this is an old solaris aio request */ 3342*d2749ac6SRoger A. Faulkner reqp->aio_req_flags |= AIO_SOLARIS; 3343*d2749ac6SRoger A. Faulkner aiop->aio_flags |= AIO_SOLARIS_REQ; 3344*d2749ac6SRoger A. Faulkner } 334534709573Sraf if (sigev->sigev_notify == SIGEV_THREAD || 334634709573Sraf sigev->sigev_notify == SIGEV_PORT) 334734709573Sraf aio_enq(&aiop->aio_portpending, reqp, 0); 33487c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 33497c478bd9Sstevel@tonic-gate /* 33507c478bd9Sstevel@tonic-gate * initialize aio request. 33517c478bd9Sstevel@tonic-gate */ 33527c478bd9Sstevel@tonic-gate reqp->aio_req_fd = arg->aio_fildes; 33537c478bd9Sstevel@tonic-gate reqp->aio_req_sigqp = sqp; 33547c478bd9Sstevel@tonic-gate reqp->aio_req_iocb.iocb = NULL; 335534709573Sraf reqp->aio_req_lio = NULL; 33567c478bd9Sstevel@tonic-gate reqp->aio_req_buf.b_file = vp; 33577c478bd9Sstevel@tonic-gate uio = reqp->aio_req.aio_uio; 33587c478bd9Sstevel@tonic-gate uio->uio_iovcnt = 1; 33597c478bd9Sstevel@tonic-gate uio->uio_iov->iov_base = (caddr_t)(uintptr_t)arg->aio_buf; 33607c478bd9Sstevel@tonic-gate uio->uio_iov->iov_len = arg->aio_nbytes; 33617c478bd9Sstevel@tonic-gate uio->uio_loffset = arg->aio_offset; 33627c478bd9Sstevel@tonic-gate *reqpp = reqp; 33637c478bd9Sstevel@tonic-gate return (0); 33647c478bd9Sstevel@tonic-gate } 33657c478bd9Sstevel@tonic-gate 33667c478bd9Sstevel@tonic-gate /* 33677c478bd9Sstevel@tonic-gate * This routine is called when a non largefile call is made by a 32bit 33687c478bd9Sstevel@tonic-gate * process on a ILP32 or LP64 kernel. 33697c478bd9Sstevel@tonic-gate */ 33707c478bd9Sstevel@tonic-gate static int 33717c478bd9Sstevel@tonic-gate alio32( 33727c478bd9Sstevel@tonic-gate int mode_arg, 33737c478bd9Sstevel@tonic-gate void *aiocb_arg, 33747c478bd9Sstevel@tonic-gate int nent, 337534709573Sraf void *sigev) 33767c478bd9Sstevel@tonic-gate { 33777c478bd9Sstevel@tonic-gate file_t *fp; 33787c478bd9Sstevel@tonic-gate file_t *prev_fp = NULL; 33797c478bd9Sstevel@tonic-gate int prev_mode = -1; 33807c478bd9Sstevel@tonic-gate struct vnode *vp; 33817c478bd9Sstevel@tonic-gate aio_lio_t *head; 33827c478bd9Sstevel@tonic-gate aio_req_t *reqp; 33837c478bd9Sstevel@tonic-gate aio_t *aiop; 338434709573Sraf caddr_t cbplist; 33857c478bd9Sstevel@tonic-gate aiocb_t cb; 33867c478bd9Sstevel@tonic-gate aiocb_t *aiocb = &cb; 33877c478bd9Sstevel@tonic-gate #ifdef _LP64 33887c478bd9Sstevel@tonic-gate aiocb32_t *cbp; 33897c478bd9Sstevel@tonic-gate caddr32_t *ucbp; 33907c478bd9Sstevel@tonic-gate aiocb32_t cb32; 33917c478bd9Sstevel@tonic-gate aiocb32_t *aiocb32 = &cb32; 339234709573Sraf struct sigevent32 sigevk; 33937c478bd9Sstevel@tonic-gate #else 33947c478bd9Sstevel@tonic-gate aiocb_t *cbp, **ucbp; 339534709573Sraf struct sigevent sigevk; 33967c478bd9Sstevel@tonic-gate #endif 33977c478bd9Sstevel@tonic-gate sigqueue_t *sqp; 33987c478bd9Sstevel@tonic-gate int (*aio_func)(); 33997c478bd9Sstevel@tonic-gate int mode; 340034709573Sraf int error = 0; 340134709573Sraf int aio_errors = 0; 34027c478bd9Sstevel@tonic-gate int i; 34037c478bd9Sstevel@tonic-gate size_t ssize; 34047c478bd9Sstevel@tonic-gate int deadhead = 0; 34057c478bd9Sstevel@tonic-gate int aio_notsupported = 0; 340634709573Sraf int lio_head_port; 340734709573Sraf int aio_port; 340834709573Sraf int aio_thread; 34097c478bd9Sstevel@tonic-gate port_kevent_t *pkevtp = NULL; 341034b3058fSpraks int portused = 0; 34117c478bd9Sstevel@tonic-gate #ifdef _LP64 34127c478bd9Sstevel@tonic-gate port_notify32_t pnotify; 34137c478bd9Sstevel@tonic-gate #else 34147c478bd9Sstevel@tonic-gate port_notify_t pnotify; 34157c478bd9Sstevel@tonic-gate #endif 341634709573Sraf int event; 341734709573Sraf 34187c478bd9Sstevel@tonic-gate aiop = curproc->p_aio; 34197c478bd9Sstevel@tonic-gate if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX) 34207c478bd9Sstevel@tonic-gate return (EINVAL); 34217c478bd9Sstevel@tonic-gate 34227c478bd9Sstevel@tonic-gate #ifdef _LP64 34237c478bd9Sstevel@tonic-gate ssize = (sizeof (caddr32_t) * nent); 34247c478bd9Sstevel@tonic-gate #else 34257c478bd9Sstevel@tonic-gate ssize = (sizeof (aiocb_t *) * nent); 34267c478bd9Sstevel@tonic-gate #endif 34277c478bd9Sstevel@tonic-gate cbplist = kmem_alloc(ssize, KM_SLEEP); 34287c478bd9Sstevel@tonic-gate ucbp = (void *)cbplist; 34297c478bd9Sstevel@tonic-gate 343034709573Sraf if (copyin(aiocb_arg, cbplist, ssize) || 343134709573Sraf (sigev && copyin(sigev, &sigevk, sizeof (struct sigevent32)))) { 34327c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 34337c478bd9Sstevel@tonic-gate return (EFAULT); 34347c478bd9Sstevel@tonic-gate } 34357c478bd9Sstevel@tonic-gate 343634709573Sraf /* Event Ports */ 343734709573Sraf if (sigev && 343834709573Sraf (sigevk.sigev_notify == SIGEV_THREAD || 343934709573Sraf sigevk.sigev_notify == SIGEV_PORT)) { 344034709573Sraf if (sigevk.sigev_notify == SIGEV_THREAD) { 344134709573Sraf pnotify.portnfy_port = sigevk.sigev_signo; 344234709573Sraf pnotify.portnfy_user = sigevk.sigev_value.sival_ptr; 344334709573Sraf } else if (copyin( 344434709573Sraf (void *)(uintptr_t)sigevk.sigev_value.sival_ptr, 344534709573Sraf &pnotify, sizeof (pnotify))) { 34467c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 34477c478bd9Sstevel@tonic-gate return (EFAULT); 34487c478bd9Sstevel@tonic-gate } 344934709573Sraf error = port_alloc_event(pnotify.portnfy_port, 345034709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp); 345134709573Sraf if (error) { 345234709573Sraf if (error == ENOMEM || error == EAGAIN) 345334709573Sraf error = EAGAIN; 345434709573Sraf else 345534709573Sraf error = EINVAL; 345634709573Sraf kmem_free(cbplist, ssize); 345734709573Sraf return (error); 345834709573Sraf } 345934709573Sraf lio_head_port = pnotify.portnfy_port; 346034b3058fSpraks portused = 1; 34617c478bd9Sstevel@tonic-gate } 34627c478bd9Sstevel@tonic-gate 34637c478bd9Sstevel@tonic-gate /* 34647c478bd9Sstevel@tonic-gate * a list head should be allocated if notification is 34657c478bd9Sstevel@tonic-gate * enabled for this list. 34667c478bd9Sstevel@tonic-gate */ 34677c478bd9Sstevel@tonic-gate head = NULL; 34687c478bd9Sstevel@tonic-gate 346934709573Sraf if (mode_arg == LIO_WAIT || sigev) { 34707c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 34717c478bd9Sstevel@tonic-gate error = aio_lio_alloc(&head); 34727c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 34737c478bd9Sstevel@tonic-gate if (error) 34747c478bd9Sstevel@tonic-gate goto done; 34757c478bd9Sstevel@tonic-gate deadhead = 1; 34767c478bd9Sstevel@tonic-gate head->lio_nent = nent; 34777c478bd9Sstevel@tonic-gate head->lio_refcnt = nent; 347834709573Sraf head->lio_port = -1; 347934709573Sraf head->lio_portkev = NULL; 348034709573Sraf if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL && 348134709573Sraf sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) { 34827c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP); 34837c478bd9Sstevel@tonic-gate if (sqp == NULL) { 34847c478bd9Sstevel@tonic-gate error = EAGAIN; 34857c478bd9Sstevel@tonic-gate goto done; 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate sqp->sq_func = NULL; 34887c478bd9Sstevel@tonic-gate sqp->sq_next = NULL; 34897c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_ASYNCIO; 34907c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = curproc->p_pid; 34917c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(curproc); 34927c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid(); 34937c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetuid(curproc->p_cred); 349434709573Sraf sqp->sq_info.si_signo = sigevk.sigev_signo; 34957c478bd9Sstevel@tonic-gate sqp->sq_info.si_value.sival_int = 349634709573Sraf sigevk.sigev_value.sival_int; 34977c478bd9Sstevel@tonic-gate head->lio_sigqp = sqp; 34987c478bd9Sstevel@tonic-gate } else { 34997c478bd9Sstevel@tonic-gate head->lio_sigqp = NULL; 35007c478bd9Sstevel@tonic-gate } 350134709573Sraf if (pkevtp) { 350234709573Sraf /* 350334709573Sraf * Prepare data to send when list of aiocb's has 350434709573Sraf * completed. 350534709573Sraf */ 350634709573Sraf port_init_event(pkevtp, (uintptr_t)sigev, 350734709573Sraf (void *)(uintptr_t)pnotify.portnfy_user, 350834709573Sraf NULL, head); 350934709573Sraf pkevtp->portkev_events = AIOLIO; 351034709573Sraf head->lio_portkev = pkevtp; 351134709573Sraf head->lio_port = pnotify.portnfy_port; 351234709573Sraf } 35137c478bd9Sstevel@tonic-gate } 35147c478bd9Sstevel@tonic-gate 35157c478bd9Sstevel@tonic-gate for (i = 0; i < nent; i++, ucbp++) { 35167c478bd9Sstevel@tonic-gate 35177c478bd9Sstevel@tonic-gate /* skip entry if it can't be copied. */ 35187c478bd9Sstevel@tonic-gate #ifdef _LP64 35197c478bd9Sstevel@tonic-gate cbp = (aiocb32_t *)(uintptr_t)*ucbp; 352034709573Sraf if (cbp == NULL || copyin(cbp, aiocb32, sizeof (*aiocb32))) 35217c478bd9Sstevel@tonic-gate #else 35227c478bd9Sstevel@tonic-gate cbp = (aiocb_t *)*ucbp; 352334709573Sraf if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb))) 35247c478bd9Sstevel@tonic-gate #endif 352534709573Sraf { 35267c478bd9Sstevel@tonic-gate if (head) { 35277c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 35287c478bd9Sstevel@tonic-gate head->lio_nent--; 35297c478bd9Sstevel@tonic-gate head->lio_refcnt--; 35307c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate continue; 35337c478bd9Sstevel@tonic-gate } 35347c478bd9Sstevel@tonic-gate #ifdef _LP64 35357c478bd9Sstevel@tonic-gate /* 35367c478bd9Sstevel@tonic-gate * copy 32 bit structure into 64 bit structure 35377c478bd9Sstevel@tonic-gate */ 35387c478bd9Sstevel@tonic-gate aiocb_32ton(aiocb32, aiocb); 35397c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 35407c478bd9Sstevel@tonic-gate 35417c478bd9Sstevel@tonic-gate /* skip if opcode for aiocb is LIO_NOP */ 35427c478bd9Sstevel@tonic-gate mode = aiocb->aio_lio_opcode; 35437c478bd9Sstevel@tonic-gate if (mode == LIO_NOP) { 35447c478bd9Sstevel@tonic-gate cbp = NULL; 35457c478bd9Sstevel@tonic-gate if (head) { 35467c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 35477c478bd9Sstevel@tonic-gate head->lio_nent--; 35487c478bd9Sstevel@tonic-gate head->lio_refcnt--; 35497c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 35507c478bd9Sstevel@tonic-gate } 35517c478bd9Sstevel@tonic-gate continue; 35527c478bd9Sstevel@tonic-gate } 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate /* increment file descriptor's ref count. */ 35557c478bd9Sstevel@tonic-gate if ((fp = getf(aiocb->aio_fildes)) == NULL) { 35567c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 35577c478bd9Sstevel@tonic-gate if (head) { 35587c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 35597c478bd9Sstevel@tonic-gate head->lio_nent--; 35607c478bd9Sstevel@tonic-gate head->lio_refcnt--; 35617c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 35627c478bd9Sstevel@tonic-gate } 35637c478bd9Sstevel@tonic-gate aio_errors++; 35647c478bd9Sstevel@tonic-gate continue; 35657c478bd9Sstevel@tonic-gate } 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate /* 35687c478bd9Sstevel@tonic-gate * check the permission of the partition 35697c478bd9Sstevel@tonic-gate */ 35707c478bd9Sstevel@tonic-gate if ((fp->f_flag & mode) == 0) { 35717c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 35727c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, EBADF); 35737c478bd9Sstevel@tonic-gate if (head) { 35747c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 35757c478bd9Sstevel@tonic-gate head->lio_nent--; 35767c478bd9Sstevel@tonic-gate head->lio_refcnt--; 35777c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 35787c478bd9Sstevel@tonic-gate } 35797c478bd9Sstevel@tonic-gate aio_errors++; 35807c478bd9Sstevel@tonic-gate continue; 35817c478bd9Sstevel@tonic-gate } 35827c478bd9Sstevel@tonic-gate 35837c478bd9Sstevel@tonic-gate /* 35847c478bd9Sstevel@tonic-gate * common case where requests are to the same fd 35857c478bd9Sstevel@tonic-gate * for the same r/w operation 35867c478bd9Sstevel@tonic-gate * for UFS, need to set EBADFD 35877c478bd9Sstevel@tonic-gate */ 358834709573Sraf vp = fp->f_vnode; 358934709573Sraf if (fp != prev_fp || mode != prev_mode) { 35907c478bd9Sstevel@tonic-gate aio_func = check_vp(vp, mode); 35917c478bd9Sstevel@tonic-gate if (aio_func == NULL) { 35927c478bd9Sstevel@tonic-gate prev_fp = NULL; 35937c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 359434709573Sraf lio_set_uerror(&cbp->aio_resultp, EBADFD); 35957c478bd9Sstevel@tonic-gate aio_notsupported++; 35967c478bd9Sstevel@tonic-gate if (head) { 35977c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 35987c478bd9Sstevel@tonic-gate head->lio_nent--; 35997c478bd9Sstevel@tonic-gate head->lio_refcnt--; 36007c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate continue; 36037c478bd9Sstevel@tonic-gate } else { 36047c478bd9Sstevel@tonic-gate prev_fp = fp; 36057c478bd9Sstevel@tonic-gate prev_mode = mode; 36067c478bd9Sstevel@tonic-gate } 36077c478bd9Sstevel@tonic-gate } 360834709573Sraf 360934709573Sraf error = aio_req_setup(&reqp, aiop, aiocb, 3610*d2749ac6SRoger A. Faulkner (aio_result_t *)&cbp->aio_resultp, vp, 0); 361134709573Sraf if (error) { 36127c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 36137c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, error); 36147c478bd9Sstevel@tonic-gate if (head) { 36157c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 36167c478bd9Sstevel@tonic-gate head->lio_nent--; 36177c478bd9Sstevel@tonic-gate head->lio_refcnt--; 36187c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 36197c478bd9Sstevel@tonic-gate } 36207c478bd9Sstevel@tonic-gate aio_errors++; 36217c478bd9Sstevel@tonic-gate continue; 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate reqp->aio_req_lio = head; 36257c478bd9Sstevel@tonic-gate deadhead = 0; 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate /* 36287c478bd9Sstevel@tonic-gate * Set the errno field now before sending the request to 36297c478bd9Sstevel@tonic-gate * the driver to avoid a race condition 36307c478bd9Sstevel@tonic-gate */ 36317c478bd9Sstevel@tonic-gate (void) suword32(&cbp->aio_resultp.aio_errno, 36327c478bd9Sstevel@tonic-gate EINPROGRESS); 36337c478bd9Sstevel@tonic-gate 363434709573Sraf reqp->aio_req_iocb.iocb32 = (caddr32_t)(uintptr_t)cbp; 36357c478bd9Sstevel@tonic-gate 363634709573Sraf event = (mode == LIO_READ)? AIOAREAD : AIOAWRITE; 363734709573Sraf aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT); 363834709573Sraf aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD); 363934709573Sraf if (aio_port | aio_thread) { 364034709573Sraf port_kevent_t *lpkevp; 364134709573Sraf /* 364234709573Sraf * Prepare data to send with each aiocb completed. 364334709573Sraf */ 36447c478bd9Sstevel@tonic-gate #ifdef _LP64 364534709573Sraf if (aio_port) { 364634709573Sraf void *paddr = (void *)(uintptr_t) 364734709573Sraf aiocb32->aio_sigevent.sigev_value.sival_ptr; 364834709573Sraf if (copyin(paddr, &pnotify, sizeof (pnotify))) 364934709573Sraf error = EFAULT; 365034709573Sraf } else { /* aio_thread */ 365134709573Sraf pnotify.portnfy_port = 365234709573Sraf aiocb32->aio_sigevent.sigev_signo; 365334709573Sraf pnotify.portnfy_user = 365434709573Sraf aiocb32->aio_sigevent.sigev_value.sival_ptr; 365534709573Sraf } 36567c478bd9Sstevel@tonic-gate #else 365734709573Sraf if (aio_port) { 365834709573Sraf void *paddr = 365934709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 366034709573Sraf if (copyin(paddr, &pnotify, sizeof (pnotify))) 366134709573Sraf error = EFAULT; 366234709573Sraf } else { /* aio_thread */ 366334709573Sraf pnotify.portnfy_port = 366434709573Sraf aiocb->aio_sigevent.sigev_signo; 366534709573Sraf pnotify.portnfy_user = 366634709573Sraf aiocb->aio_sigevent.sigev_value.sival_ptr; 366734709573Sraf } 36687c478bd9Sstevel@tonic-gate #endif 366934709573Sraf if (error) 367034709573Sraf /* EMPTY */; 367134709573Sraf else if (pkevtp != NULL && 367234709573Sraf pnotify.portnfy_port == lio_head_port) 367334709573Sraf error = port_dup_event(pkevtp, &lpkevp, 367434709573Sraf PORT_ALLOC_DEFAULT); 367534709573Sraf else 367634709573Sraf error = port_alloc_event(pnotify.portnfy_port, 367734709573Sraf PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, 367834709573Sraf &lpkevp); 367934709573Sraf if (error == 0) { 368034709573Sraf port_init_event(lpkevp, (uintptr_t)cbp, 368134709573Sraf (void *)(uintptr_t)pnotify.portnfy_user, 368234709573Sraf aio_port_callback, reqp); 368334709573Sraf lpkevp->portkev_events = event; 368434709573Sraf reqp->aio_req_portkev = lpkevp; 368534709573Sraf reqp->aio_req_port = pnotify.portnfy_port; 368634709573Sraf } 36877c478bd9Sstevel@tonic-gate } 36887c478bd9Sstevel@tonic-gate 36897c478bd9Sstevel@tonic-gate /* 36907c478bd9Sstevel@tonic-gate * send the request to driver. 36917c478bd9Sstevel@tonic-gate */ 36927c478bd9Sstevel@tonic-gate if (error == 0) { 36937c478bd9Sstevel@tonic-gate if (aiocb->aio_nbytes == 0) { 36947c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 36957c478bd9Sstevel@tonic-gate aio_zerolen(reqp); 36967c478bd9Sstevel@tonic-gate continue; 36977c478bd9Sstevel@tonic-gate } 36987c478bd9Sstevel@tonic-gate error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, 36997c478bd9Sstevel@tonic-gate CRED()); 37007c478bd9Sstevel@tonic-gate } 37017c478bd9Sstevel@tonic-gate 37027c478bd9Sstevel@tonic-gate /* 37037c478bd9Sstevel@tonic-gate * the fd's ref count is not decremented until the IO has 37047c478bd9Sstevel@tonic-gate * completed unless there was an error. 37057c478bd9Sstevel@tonic-gate */ 37067c478bd9Sstevel@tonic-gate if (error) { 37077c478bd9Sstevel@tonic-gate releasef(aiocb->aio_fildes); 37087c478bd9Sstevel@tonic-gate lio_set_uerror(&cbp->aio_resultp, error); 37097c478bd9Sstevel@tonic-gate if (head) { 37107c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 37117c478bd9Sstevel@tonic-gate head->lio_nent--; 37127c478bd9Sstevel@tonic-gate head->lio_refcnt--; 37137c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate if (error == ENOTSUP) 37167c478bd9Sstevel@tonic-gate aio_notsupported++; 37177c478bd9Sstevel@tonic-gate else 37187c478bd9Sstevel@tonic-gate aio_errors++; 371934b3058fSpraks lio_set_error(reqp, portused); 37207c478bd9Sstevel@tonic-gate } else { 37217c478bd9Sstevel@tonic-gate clear_active_fd(aiocb->aio_fildes); 37227c478bd9Sstevel@tonic-gate } 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate if (aio_notsupported) { 37267c478bd9Sstevel@tonic-gate error = ENOTSUP; 37277c478bd9Sstevel@tonic-gate } else if (aio_errors) { 37287c478bd9Sstevel@tonic-gate /* 37297c478bd9Sstevel@tonic-gate * return EIO if any request failed 37307c478bd9Sstevel@tonic-gate */ 37317c478bd9Sstevel@tonic-gate error = EIO; 37327c478bd9Sstevel@tonic-gate } 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate if (mode_arg == LIO_WAIT) { 37357c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 37367c478bd9Sstevel@tonic-gate while (head->lio_refcnt > 0) { 37377c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) { 37387c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 37397c478bd9Sstevel@tonic-gate error = EINTR; 37407c478bd9Sstevel@tonic-gate goto done; 37417c478bd9Sstevel@tonic-gate } 37427c478bd9Sstevel@tonic-gate } 37437c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 37447c478bd9Sstevel@tonic-gate alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_32); 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate 37477c478bd9Sstevel@tonic-gate done: 37487c478bd9Sstevel@tonic-gate kmem_free(cbplist, ssize); 37497c478bd9Sstevel@tonic-gate if (deadhead) { 37507c478bd9Sstevel@tonic-gate if (head->lio_sigqp) 37517c478bd9Sstevel@tonic-gate kmem_free(head->lio_sigqp, sizeof (sigqueue_t)); 375234709573Sraf if (head->lio_portkev) 375334709573Sraf port_free_event(head->lio_portkev); 37547c478bd9Sstevel@tonic-gate kmem_free(head, sizeof (aio_lio_t)); 37557c478bd9Sstevel@tonic-gate } 37567c478bd9Sstevel@tonic-gate return (error); 37577c478bd9Sstevel@tonic-gate } 37587c478bd9Sstevel@tonic-gate 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 37617c478bd9Sstevel@tonic-gate void 37627c478bd9Sstevel@tonic-gate aiocb_32ton(aiocb32_t *src, aiocb_t *dest) 37637c478bd9Sstevel@tonic-gate { 37647c478bd9Sstevel@tonic-gate dest->aio_fildes = src->aio_fildes; 37657c478bd9Sstevel@tonic-gate dest->aio_buf = (caddr_t)(uintptr_t)src->aio_buf; 37667c478bd9Sstevel@tonic-gate dest->aio_nbytes = (size_t)src->aio_nbytes; 37677c478bd9Sstevel@tonic-gate dest->aio_offset = (off_t)src->aio_offset; 37687c478bd9Sstevel@tonic-gate dest->aio_reqprio = src->aio_reqprio; 37697c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify = src->aio_sigevent.sigev_notify; 37707c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_signo = src->aio_sigevent.sigev_signo; 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate /* 37737c478bd9Sstevel@tonic-gate * See comment in sigqueue32() on handling of 32-bit 37747c478bd9Sstevel@tonic-gate * sigvals in a 64-bit kernel. 37757c478bd9Sstevel@tonic-gate */ 37767c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_value.sival_int = 37777c478bd9Sstevel@tonic-gate (int)src->aio_sigevent.sigev_value.sival_int; 37787c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify_function = (void (*)(union sigval)) 37797c478bd9Sstevel@tonic-gate (uintptr_t)src->aio_sigevent.sigev_notify_function; 37807c478bd9Sstevel@tonic-gate dest->aio_sigevent.sigev_notify_attributes = (pthread_attr_t *) 37817c478bd9Sstevel@tonic-gate (uintptr_t)src->aio_sigevent.sigev_notify_attributes; 37827c478bd9Sstevel@tonic-gate dest->aio_sigevent.__sigev_pad2 = src->aio_sigevent.__sigev_pad2; 37837c478bd9Sstevel@tonic-gate dest->aio_lio_opcode = src->aio_lio_opcode; 37847c478bd9Sstevel@tonic-gate dest->aio_state = src->aio_state; 37857c478bd9Sstevel@tonic-gate dest->aio__pad[0] = src->aio__pad[0]; 37867c478bd9Sstevel@tonic-gate } 37877c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate /* 37907c478bd9Sstevel@tonic-gate * aio_port_callback() is called just before the event is retrieved from the 37917c478bd9Sstevel@tonic-gate * port. The task of this callback function is to finish the work of the 37927c478bd9Sstevel@tonic-gate * transaction for the application, it means : 37937c478bd9Sstevel@tonic-gate * - copyout transaction data to the application 37947c478bd9Sstevel@tonic-gate * (this thread is running in the right process context) 37957c478bd9Sstevel@tonic-gate * - keep trace of the transaction (update of counters). 37967c478bd9Sstevel@tonic-gate * - free allocated buffers 37977c478bd9Sstevel@tonic-gate * The aiocb pointer is the object element of the port_kevent_t structure. 37987c478bd9Sstevel@tonic-gate * 37997c478bd9Sstevel@tonic-gate * flag : 38007c478bd9Sstevel@tonic-gate * PORT_CALLBACK_DEFAULT : do copyout and free resources 38017c478bd9Sstevel@tonic-gate * PORT_CALLBACK_CLOSE : don't do copyout, free resources 38027c478bd9Sstevel@tonic-gate */ 38037c478bd9Sstevel@tonic-gate 38047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38057c478bd9Sstevel@tonic-gate int 38067c478bd9Sstevel@tonic-gate aio_port_callback(void *arg, int *events, pid_t pid, int flag, void *evp) 38077c478bd9Sstevel@tonic-gate { 38087c478bd9Sstevel@tonic-gate aio_t *aiop = curproc->p_aio; 38097c478bd9Sstevel@tonic-gate aio_req_t *reqp = arg; 38107c478bd9Sstevel@tonic-gate struct iovec *iov; 38117c478bd9Sstevel@tonic-gate struct buf *bp; 38127c478bd9Sstevel@tonic-gate void *resultp; 38137c478bd9Sstevel@tonic-gate 38147c478bd9Sstevel@tonic-gate if (pid != curproc->p_pid) { 38157c478bd9Sstevel@tonic-gate /* wrong proc !!, can not deliver data here ... */ 38167c478bd9Sstevel@tonic-gate return (EACCES); 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_portq_mutex); 38207c478bd9Sstevel@tonic-gate reqp->aio_req_portkev = NULL; 38217c478bd9Sstevel@tonic-gate aio_req_remove_portq(aiop, reqp); /* remove request from portq */ 38227c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex); 38237c478bd9Sstevel@tonic-gate aphysio_unlock(reqp); /* unlock used pages */ 38247c478bd9Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex); 38257c478bd9Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_COPYOUTDONE) { 38267c478bd9Sstevel@tonic-gate aio_req_free_port(aiop, reqp); /* back to free list */ 38277c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 38287c478bd9Sstevel@tonic-gate return (0); 38297c478bd9Sstevel@tonic-gate } 38307c478bd9Sstevel@tonic-gate 38317c478bd9Sstevel@tonic-gate iov = reqp->aio_req_uio.uio_iov; 38327c478bd9Sstevel@tonic-gate bp = &reqp->aio_req_buf; 38337c478bd9Sstevel@tonic-gate resultp = (void *)reqp->aio_req_resultp; 38347c478bd9Sstevel@tonic-gate aio_req_free_port(aiop, reqp); /* request struct back to free list */ 38357c478bd9Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex); 38367c478bd9Sstevel@tonic-gate if (flag == PORT_CALLBACK_DEFAULT) 38377c478bd9Sstevel@tonic-gate aio_copyout_result_port(iov, bp, resultp); 38387c478bd9Sstevel@tonic-gate return (0); 38397c478bd9Sstevel@tonic-gate } 3840