Skip to content

aio: various fixes for AIO LPT test cases on intel64 - #20097

Open
raiden00pl wants to merge 5 commits into
apache:masterfrom
raiden00pl:nuttx-qemu-pr-aio
Open

aio: various fixes for AIO LPT test cases on intel64#20097
raiden00pl wants to merge 5 commits into
apache:masterfrom
raiden00pl:nuttx-qemu-pr-aio

Conversation

@raiden00pl

Copy link
Copy Markdown
Member

Summary

various issues with AIO found by NTFC with LPT tests:

  • sched/wqueue: restore -ENOENT from work_cancel() for unqueued work
  • libs/libc/aio: fix nxstyle issues in lio_listio.c
  • libs/libc/aio: fix lio_listio() racing with early I/O completion
  • fs/aio: advance the pending list in aio_cancel() before work_cancel()
  • fs/aio: decant the container only after the I/O has been performed

taken from #20030

Impact

required for SMP intel64 to pass LPT tests

Testing

CI pass: https://github.com/apache/nuttx/actions/runs/34236734404/job/102183306099?pr=20030

work_cancel() used to return -ENOENT when the work structure was not
in the queue, and callers depend on that: aio_cancel() tears down the
AIO container (file_put() + aioc_free()) only when work_cancel()
reports success, because a work item that is not queued may already be
executing on a worker thread (see the comment in fs/aio/aio_cancel.c).

Since commit 6f72f54 ("sched/wqueue: Refactor delayed and periodical
workqueue") work_cancel() returns OK unconditionally, and commit
d2e01b9 ("sched/wqueue: harden custom queue lifecycle") kept that
behaviour and dropped -ENOENT from the function documentation.  Under
SMP the LTP aio_cancel tests then free the aio container and its file
while the lpwork thread is still executing aio_write_worker() on it,
which ends in a page fault in file_write() (f_inode == NULL) and a
panic.

Return -ENOENT again when the work is not queued, and document it.
For the synchronous variant "not queued" alone does not tell whether
the callback is running: the worker scan does, so report OK when a
running callback was found and waited for, and -ENOENT only when the
work was neither queued nor running.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
fix nxstyle issues in lio_listio.c

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
lio_listio(LIO_NOWAIT) submits the requests first and only afterwards
installs the SIGPOLL handler and attaches the per-request private data
in lio_sigsetup().  Under SMP the requests complete on the low priority
work queue while this is going on, and aio_signal() queues SIGPOLL for
each of them as it finishes:

- A signal delivered for a request that lio_sigsetup() found already
  finished (aio_priv left NULL) made lio_sighandler() dereference a
  NULL private pointer (LTP lio_listio 10-1, 15-1, 2-1 crash with a
  page fault in lio_sighandler on qemu-intel64 SMP).
- A signal delivered between the aio_result check and the aio_priv
  store of the last outstanding request was consumed without private
  data, no later signal arrived, and the caller was never notified.
- If every request had completed by the time the loop ran, no handler
  invocation could ever see the private data and the caller hung.
- After the completing handler had notified the caller, signals still
  queued for other requests ran the handler again with their own copy
  of the private data.

Block SIGPOLL while the handler is installed and the private data is
attached, so that the completion signals are delivered only once every
entry is set up.  Ignore a signal for a request without private data,
notify the caller directly from lio_sigsetup() when everything had
already completed, and detach the private data of every entry once the
list is done so that late signals find nothing to do.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
The "cancel everything on this descriptor" loop in aio_cancel() only
moved to the next container inside the branch taken when work_cancel()
succeeded.  When work_cancel() reports -ENOENT because a worker thread
is already executing the request, the loop restarted its search from
the same container and spun forever, hanging the task (and, since the
scan runs with interrupts enabled but never yields, that CPU) without
any output.  This was hit by the LTP aio_cancel tests on SMP.

Capture the next container before calling work_cancel() so the loop
always makes progress.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
The aio worker functions started by decanting the container, which
frees the container back to the pool and drops the file reference,
and only then performed the I/O through the aiocb.  Nothing was
holding the file open while the read/write/fsync was in progress, and
the request was no longer on the pending list, so a concurrent close()
or aio_cancel() could pull the file from under the running operation.

Keep the container until the operation has completed and decant it
just before signalling completion.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
@raiden00pl raiden00pl changed the title various fixes for AIO LPT test cases on intel64 aio: various fixes for AIO LPT test cases on intel64 Sep 9, 2026
@github-actions github-actions Bot added Area: File System File System issues Size: M The size of the change in this PR is medium labels Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: File System File System issues Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants