This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 410c52eedf5c0c8c033a1cdce0dc0cc710f01c43
Author: zhangyuan29 <[email protected]>
AuthorDate: Thu Nov 12 00:43:51 2026 +0800

    fs/aio: unlink lio_listio entries before waking the submitter
    
    aio_signal() sends the per-request notification and SIGPOLL first, and
    only then checks and unlinks aiocbp->lio_link.  Either signal can wake
    an lio_listio(LIO_WAIT) caller, which may return and release the
    aiocb list, usually on its stack, while the worker still touches
    lio_link.
    
    Unlink the entry and note whether it emptied the batch before sending
    any notification.  The notification order is unchanged.
    
    Signed-off-by: zhangyuan29 <[email protected]>
    Signed-off-by: jingfei <[email protected]>
---
 fs/aio/aio_signal.c | 67 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 43 insertions(+), 24 deletions(-)

diff --git a/fs/aio/aio_signal.c b/fs/aio/aio_signal.c
index c8c734d12dd..a813125a5b6 100644
--- a/fs/aio/aio_signal.c
+++ b/fs/aio/aio_signal.c
@@ -60,7 +60,10 @@
  *   negated errno value is returned.
  *
  * Assumptions:
- *   This function runs only in the context of the worker thread.
+ *   This function runs only in the context of the worker thread.  The
+ *   aiocbp is owned by the submitter and may become invalid once the
+ *   submitter is woken, so lio_link must be unlinked before any
+ *   notification that can wake it.
  *
  ****************************************************************************/
 
@@ -69,18 +72,42 @@ int aio_signal(pid_t pid, FAR struct aiocb *aiocbp)
   union sigval value;
   int status;
   int ret;
+  bool last = false; /* This completion emptied the lio_listio batch */
 
   DEBUGASSERT(aiocbp);
 
   ret = OK; /* Assume success */
 
+  /* Unlink from the lio_listio batch before anything that can wake the
+   * submitter: aiocbp usually lives on the submitter's stack, and once
+   * woken the submitter may return and invalidate it before we get a
+   * chance to touch lio_link.  Even the in-list check needs the lock:
+   * completing a neighboring batch entry updates lio_link.prev under it.
+   * The batch-completion notification stays at its original position
+   * (after the poll signal) so the per-request -> poll -> batch
+   * notification order is unchanged.
+   */
+
+  aio_lock();
+  if (list_in_list(&aiocbp->lio_link))
+    {
+      last = list_is_empty(&aiocbp->lio_link);
+      list_delete(&aiocbp->lio_link);
+    }
+
+  aio_unlock();
+
   /* Signal the client */
 
-  ret = nxsig_notification(pid, &aiocbp->aio_sigevent,
-                           SI_ASYNCIO, &aiocbp->aio_sigwork);
-  if (ret < 0)
+  status = nxsig_notification(pid, &aiocbp->aio_sigevent,
+                              SI_ASYNCIO, &aiocbp->aio_sigwork);
+  if (status < 0)
     {
-      ferr("ERROR: nxsig_notification failed: %d\n", ret);
+      ferr("ERROR: nxsig_notification failed: %d\n", status);
+      if (ret >= OK)
+        {
+          ret = status;
+        }
     }
 
   /* Send the poll signal in any event in case the caller is waiting
@@ -98,28 +125,20 @@ int aio_signal(pid_t pid, FAR struct aiocb *aiocbp)
         }
     }
 
-  if (list_in_list(&aiocbp->lio_link))
-    {
-      /* This I/O is queued by lio_listio, remove this I/O from the list,
-       * signal the client when all I/O is completed
-       */
-
-      aio_lock();
-      status = list_is_empty(&aiocbp->lio_link);
-      list_delete(&aiocbp->lio_link);
-      aio_unlock();
+  /* This I/O was queued by lio_listio and emptied the batch: signal the
+   * client that all I/O of the batch has completed.
+   */
 
-      if (status)
+  if (last)
+    {
+      status = nxsig_notification(pid, &aiocbp->lio_sigevent, SI_ASYNCIO,
+                                  &aiocbp->lio_sigwork);
+      if (status < 0)
         {
-          status = nxsig_notification(pid, &aiocbp->lio_sigevent, SI_ASYNCIO,
-                                      &aiocbp->lio_sigwork);
-          if (status < 0)
+          ferr("ERROR: nxsig_notification failed: %d\n", status);
+          if (ret >= OK)
             {
-              ferr("ERROR: nxsig_notification failed: %d\n", status);
-              if (ret >= OK)
-                {
-                  ret = status;
-                }
+              ret = status;
             }
         }
     }

Reply via email to