fs/aio: rework lio_listio() and fix AIO crashes and POSIX conformance - #20107
Open
xiaoxiang781216 wants to merge 16 commits into
Open
fs/aio: rework lio_listio() and fix AIO crashes and POSIX conformance#20107xiaoxiang781216 wants to merge 16 commits into
xiaoxiang781216 wants to merge 16 commits into
Conversation
…listio() Previously, lio_listio() would first call aio_read()/aio_write() to submit I/O, and then set the handler and private variables, which led to thread-unsafe behavior. After this change, lio_listio() now links all I/O requests into a list. When a task is completed, its corresponding node is removed from the list in aio_signal(). The signal is triggered only when the list is empty. Signed-off-by: wushenhui <wushenhui@xiaomi.com>
by a I/O not referenced by the 'list' Signed-off-by: wushenhui <wushenhui@xiaomi.com>
When aio_cancel() holds the lock, the I/O in the work_thread is blocked. If the I/O that aio_cancel() attempts to cancel is already running, work_cancel() will return an error, but aio_cancel() does not skip this I/O, resulting in a endless-loop. Signed-off-by: wushenhui <wushenhui@xiaomi.com>
Moving aioc_decant() after I/O finished, it can avoid use-after-free issue, and also avoid read/write errors caused by the caller prematurely closing the file. Signed-off-by: wushenhui <wushenhui@xiaomi.com>
In the POSIX standard, aio_cancel should return -1 and set errno to EBADF when it receives an invalid fd. Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
avoid wild pointer for the first time Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
aiocbp may be NULL when passed to nxsig_notification Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
A call to aio_error()may return -1 and set errno to EINVAL if aiocbp does not refer to an operation whose return status has not yet been retrieved. A call to aio_read() and aio_write() may return -1 and set errno to EINVAL if the criteria is not met. And in aio_read() and aio_write(), aio_result should be set so that aio_error() function can query correctly. Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
…ash. so let's skip delete it Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
In the case test of ltp, nent is set to 10, so the value of AIO_LISTIO_MAX in limit.h is modified to 11 in order to pass the ltp test. Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
aio_read and aio_write function miss check for fd. ltp requires a return value of 0 when fd is invalid. Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
xiaoxiang781216
requested review from
Donny9,
jerpelea,
pussuw and
yamt
as code owners
September 10, 2026 18:38
…andard by remove the parameter name from the prototype Signed-off-by: guoshichao <guoshichao@xiaomi.com>
Extract aio_read_internal/aio_write_internal that skip lio_link initialization. aio_read/aio_write initialize lio_link before calling the internal function, while lio_listio calls the internal function directly to preserve its own lio_link setup. This fixes a crash when aio_signal accesses uninitialized lio_link from aiocb filled with 0xff by the ostest. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
aio_fsync() dereferences aiocbp after a DEBUGASSERT(). Passing NULL can therefore panic debug builds and crash release builds. POSIX Issue 6 and later no longer define a NULL aiocbp special case for aio_fsync(). Treat NULL as an invalid argument and return ERROR with errno set to EINVAL, matching the defensive argument checks used by aio_read() and aio_write(). Signed-off-by: fangxinyong <fangxinyong@xiaomi.com>
Root cause: aio_fsync/aio_read/aio_write/lio_listio initialized aiocbp->lio_link with list_initialize(), which makes the node self-referential (prev = next = &node). aio_signal() tests list_in_list(&lio_link) (prev != NULL) to detect lio_listio batches, so it wrongly entered the lio_listio completion path for every standalone AIO operation and notified through the uninitialized lio_sigevent/lio_sigwork. With CONFIG_SIG_EVTHREAD=y, garbage lio_sigevent.sigev_notify == SIGEV_THREAD caused nxsig_notification() to queue &lio_sigwork.work onto the low-priority work queue with garbage func/value. After the aiocb was freed, the dangling work_s was dispatched with worker=NULL, crashing in work_dispatch() (prefetch abort at PC=0, lpwork task). Fix: initialize lio_link with list_clear_node() (prev = next = NULL) so list_in_list() returns false for non-lio_listio operations and aio_signal() skips the lio_listio path. Signed-off-by: dengwenqi <dengwenqi@xiaomi.com>
|
xiaoxiang781216
force-pushed
the
upstream-aio
branch
from
September 10, 2026 18:53
2a5dcfa to
7179aaa
Compare
Fix the misindented 'if (mode == LIO_NOWAIT && sig)' block (one space short) and hoist the opcode switch out of the 'if (aiocbp)' block via an early continue, so that the nesting and case label indentation pass nxstyle/checkpatch. No functional change. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
acassis
approved these changes
Sep 10, 2026
Member
|
intel64 LTP pass with this PR and #20112 |
raiden00pl
approved these changes
Sep 11, 2026
Member
|
@xiaoxiang781216 |
jerpelea
approved these changes
Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
lio_listio()to link all requests of a batch into a list before submitting any I/O;aio_signal()then removes each completed node underaio_lock()and notifies the caller only when the list becomes empty. This fixes the thread-unsafe "submit first, set up notification state later" ordering of the old implementation.lio_linkmachinery: uninitialized/overwritten list nodes (uselist_clear_node()for non-batch operations, call the newaio_read_internal()/aio_write_internal()fromlio_listio()to preserve list membership), a NULL-aiocbp dereference when no I/O could be queued, and an invalidlist_delete()for failed submissions inLIO_WAITmode.aiocuse-after-free: the I/O workers decanted (freed) the container before signaling completion;aioc_decant()now runs afteraio_signal().aio_cancel(): endless loop when cancelling already-running I/O, and missingEBADFvalidation of the file descriptor (file_get()/file_put()).aio_read()/aio_write()/aio_error()return values with POSIX:-1+errno = EINVALfor rejected requests (also retrievable viaaio_error()), but0with the error reported throughaio_error()for a bad file descriptor.aio_suspend()now re-checks the completion list after every wakeup so a SIGPOLL from unrelated AIO no longer causes a spurious return, and the timeout is honored across wakeups.aiocbpinaio_fsync()(POSIX Issue 6 removed the NULL special case).lio_listio()prototype match POSIX (restrictqualifiers, unnamed parameters).CONFIG_FS_AIO_LISTIO_MAX(default 10), validatenentagainst{AIO_LISTIO_MAX}inlio_listio(), and report it viasysconf(_SC_AIO_LISTIO_MAX).lio_listio.cfromlibs/libc/aiotofs/aioso the whole AIO implementation lives in one directory.Impact
fs/aio/,libs/libc/aio/,include/aio.h,include/limits.h,libs/libc/libc.csvandlibs/libc/unistd/lib_sysconf.c; no new dependencies.struct aiocblayout changes (the unusedaio_privfield is replaced bylio_link/lio_sigevent/lio_sigwork) — ABI-affecting for out-of-tree users ofinclude/aio.h, which is why this is submitted as one series.lio_listio()prototype gainsrestrictqualifiers per POSIX; existing callers compile unchanged.Testing
sim:nshwithCONFIG_FS_AIO=y,CONFIG_TESTING_OSTEST=y,CONFIG_TESTING_OSTEST_AIO=y: build is warning-free; the fullostestrun exits with status 0 and the AIO test reports all 7 cases (poll, LIO_WAIT, aio_suspend, individual signals, list completion signal, cancel by aiocb, cancel by fd) successful:tools/checkpatch.sh -c -u -m -gpasses for the whole series.