diff --git a/lib/libc/sys/aio_return.2 b/lib/libc/sys/aio_return.2 index d94fcc7eba62..aebe978fe140 100644 --- a/lib/libc/sys/aio_return.2 +++ b/lib/libc/sys/aio_return.2 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 2, 2021 +.Dd January 11, 2021 .Dt AIO_RETURN 2 .Os .Sh NAME @@ -75,6 +75,12 @@ The .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 +is invalid. .El .Sh SEE ALSO .Xr aio_cancel 2 , diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 8666d6ea4217..bc0d7e04c9d5 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -1556,16 +1556,26 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj, 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. diff --git a/sys/sys/aio.h b/sys/sys/aio.h index dbfbadcd1254..ee928b8bf846 100644 --- a/sys/sys/aio.h +++ b/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 diff --git a/tests/sys/aio/lio_test.c b/tests/sys/aio/lio_test.c index b6965cc9a4ee..fb519aac978d 100644 --- a/tests/sys/aio/lio_test.c +++ b/tests/sys/aio/lio_test.c @@ -26,8 +26,11 @@ * $FreeBSD$ */ +#define _WANT_ALL_LIO_OPCODES + #include #include +#include #include #include @@ -198,6 +201,53 @@ ATF_TC_BODY(lio_listio_empty_nowait_thread, tc) 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_EQ(EINVAL, aio_error(&sync_cb)); + ATF_CHECK_ERRNO(EINVAL, aio_return(&sync_cb) < 0); + ATF_CHECK_EQ(EINVAL, aio_error(&mlock_cb)); + ATF_CHECK_ERRNO(EINVAL, aio_return(&mlock_cb) < 0); + ATF_CHECK_EQ(EINVAL, aio_error(&readv_cb)); + ATF_CHECK_ERRNO(EINVAL, aio_return(&readv_cb) < 0); + ATF_CHECK_EQ(EINVAL, aio_error(&writev_cb)); + ATF_CHECK_ERRNO(EINVAL, aio_return(&writev_cb) < 0); +} + ATF_TP_ADD_TCS(tp) { @@ -207,6 +257,7 @@ ATF_TP_ADD_TCS(tp) 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()); }