Index: lib/libc/sys/aio_return.2 =================================================================== --- lib/libc/sys/aio_return.2 +++ lib/libc/sys/aio_return.2 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 2, 2021 +.Dd January 9, 2021 .Dt AIO_RETURN 2 .Os .Sh NAME @@ -75,6 +75,13 @@ .Fa iocb argument does not reference a completed asynchronous I/O request. +.It Bq Er EINVAL +The I/O operation was submitted with +.Fn lio_listio , +and the value of the +.Fa aio_lio_opcode +field is not supported by +.Fn lio_listio . .El .Sh SEE ALSO .Xr aio_cancel 2 , Index: sys/kern/vfs_aio.c =================================================================== --- sys/kern/vfs_aio.c +++ sys/kern/vfs_aio.c @@ -1556,16 +1556,26 @@ goto err2; } + /* Get the opcode. */ + if (type == LIO_NOP) { + switch (job->uaiocb.aio_lio_opcode) { + case LIO_WRITE: + case LIO_NOP: + case LIO_READ: + opcode = job->uaiocb.aio_lio_opcode; + break; + default: + error = EINVAL; + goto err2; + } + } else + opcode = job->uaiocb.aio_lio_opcode = type; + ksiginfo_init(&job->ksi); /* Save userspace address of the job info. */ job->ujob = ujob; - /* Get the opcode. */ - if (type != LIO_NOP) - job->uaiocb.aio_lio_opcode = type; - opcode = job->uaiocb.aio_lio_opcode; - /* * Validate the opcode and fetch the file object for the specified * file descriptor. Index: sys/sys/aio.h =================================================================== --- sys/sys/aio.h +++ sys/sys/aio.h @@ -43,7 +43,7 @@ #define LIO_NOP 0x0 #define LIO_WRITE 0x1 #define LIO_READ 0x2 -#ifdef _KERNEL +#if defined(_KERNEL) || defined(_WANT_ALL_LIO_OPCODES) #define LIO_SYNC 0x3 #define LIO_MLOCK 0x4 #define LIO_WRITEV 0x5 Index: tests/sys/aio/lio_test.c =================================================================== --- tests/sys/aio/lio_test.c +++ tests/sys/aio/lio_test.c @@ -26,8 +26,11 @@ * $FreeBSD$ */ +#define _WANT_ALL_LIO_OPCODES + #include #include +#include #include #include @@ -198,6 +201,49 @@ ATF_REQUIRE_EQ(0, sem_destroy(&completions)); } +/* + * Only select opcodes are allowed with lio_listio + */ +ATF_TC_WITHOUT_HEAD(lio_listio_invalid_opcode); +ATF_TC_BODY(lio_listio_invalid_opcode, tc) +{ + struct aiocb sync_cb, mlock_cb, writev_cb, readv_cb; + struct aiocb *list[] = {&sync_cb, &mlock_cb, &writev_cb, &readv_cb}; + struct iovec iov; + int fd; + + fd = open("testfile", O_CREAT | O_RDWR); + ATF_REQUIRE_MSG(fd >= 0, "open: %s", strerror(errno)); + + bzero(&sync_cb, sizeof(sync_cb)); + sync_cb.aio_fildes = fd; + sync_cb.aio_lio_opcode = LIO_SYNC; + + bzero(&mlock_cb, sizeof(mlock_cb)); + mlock_cb.aio_lio_opcode = LIO_MLOCK; + + iov.iov_base = NULL; + iov.iov_len = 0; + + bzero(&readv_cb, sizeof(readv_cb)); + readv_cb.aio_fildes = fd; + readv_cb.aio_lio_opcode = LIO_READV; + readv_cb.aio_iov = &iov; + readv_cb.aio_iovcnt = 1; + + bzero(&writev_cb, sizeof(writev_cb)); + writev_cb.aio_fildes = fd; + writev_cb.aio_lio_opcode = LIO_WRITEV; + writev_cb.aio_iov = &iov; + writev_cb.aio_iovcnt = 1; + + ATF_CHECK_ERRNO(EIO, lio_listio(LIO_WAIT, list, nitems(list), NULL)); + ATF_CHECK_ERRNO(EINVAL, aio_return(&sync_cb) < 0); + ATF_CHECK_ERRNO(EINVAL, aio_return(&mlock_cb) < 0); + ATF_CHECK_ERRNO(EINVAL, aio_return(&readv_cb) < 0); + ATF_CHECK_ERRNO(EINVAL, aio_return(&writev_cb) < 0); +} + ATF_TP_ADD_TCS(tp) { @@ -207,6 +253,7 @@ ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_signal); ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_thread); ATF_TP_ADD_TC(tp, lio_listio_empty_wait); + ATF_TP_ADD_TC(tp, lio_listio_invalid_opcode); return (atf_no_error()); }