Skip to content

Commit e5cd15d

Browse files
committed
sched/wqueue: restore -ENOENT from work_cancel() for unqueued work
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 from the asynchronous cancel when the work is not queued, and document it. The synchronous variant keeps returning OK: it waits for any running callback, so the work is guaranteed to be finished when it returns. Assisted-by: Claude Code Signed-off-by: raiden00pl <raiden00@railab.me>
1 parent 4ef0e89 commit e5cd15d

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

sched/wqueue/kwork_cancel.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, bool sync,
4848
{
4949
irqstate_t flags;
5050
pid_t self = sync ? nxsched_gettid() : INVALID_PROCESS_ID;
51+
int ret = OK;
5152

5253
if (wqueue == NULL || work == NULL)
5354
{
@@ -84,6 +85,17 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, bool sync,
8485
work_timer_reset(wqueue);
8586
}
8687
}
88+
else if (!sync)
89+
{
90+
/* The work is not queued: either it was never queued or a worker
91+
* has already dequeued it and may be executing its callback right
92+
* now. Report -ENOENT so that callers (e.g. aio_cancel()) do not
93+
* free resources that the callback is still using. The sync
94+
* variant waits for such a callback below and returns OK.
95+
*/
96+
97+
ret = -ENOENT;
98+
}
8799

88100
if (sync)
89101
{
@@ -102,7 +114,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, bool sync,
102114

103115
if (sync_wait == NULL)
104116
{
105-
return OK;
117+
return ret;
106118
}
107119

108120
nxsem_wait_uninterruptible(sync_wait);
@@ -130,6 +142,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, bool sync,
130142
* Zero on success, a negated errno on failure
131143
*
132144
* -EINVAL - An invalid work queue was specified
145+
* -ENOENT - There is no such work queued (it may be executing right now)
133146
*
134147
****************************************************************************/
135148

0 commit comments

Comments
 (0)