From nobody Sun Oct 18 15:16:46 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4j72Mf3Hl9z6vrk6 for ; Sun, 18 Oct 2026 15:16:46 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4j72Mf2WPFz3Nw3 for ; Sun, 18 Oct 2026 15:16:46 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792336606; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QwCEGVbLpmE3bOd2X3vuaXm/zTmLjTXL6oO2tYaF6UQ=; b=KgTIRj5lvFSiMGhM2s8W+NCNYEJQ88nNZ7FlNlTYD3Jz7Qsx3iHWctF8YONFPYvFYJQYdz IA2IOIO3wB93ODBWELpWfFpGFU3Uw0Y3vzT0KiZVy8MB/PwN/m2ijW0TUmMHEn2NbAjO31 C5t5WL+BnwHcKmR/+nDgcHjsSkUZkiHRfnKwHYLZ4aNwYmBwQWX11GNXXvLTVFyRRT405N eylYBZXX/QNdG016Cx8f8OhuC8EEnu7LxXG4DIPE7a8egsrwidEbuLj7Xi8h0I30vsA6QT gH7ocyyzyDnCz2l0JedMG60aZBIHRNEcrECmTwuMYDru7hbvJXgu5OINllgm9g== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792336606; b=BaLyjWqFB9bhi1EqKTkVPDpJ2G9UAT3fJv/2NiZ16iZlCgtW3Qyo1uaGhgpKoxIWINrGBT JmXhB2VGuLftGG85a/PumNuM7PckZJ7EvXQ5AWXXS2jcpI7Osr14f2hTMd/6lGbElE2k0F JYlwnySbnZaBusjNa90j/ApH+pYWEILprm/6lrdxWLUHDfSaLHB8YXURpFKS9otV91Zj1i BcUW0k3tY/UY/q8eepxc8aBEcPpg5BORilXg8c8+p5U+6QcW6LEkbenScGmEMq3J25p7kn TyPfLKhCEcN78RfFseiOGJw/F9seRSdGoCb7D/taU3+/NHylDKzt2nUfxvEQMg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792336606; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QwCEGVbLpmE3bOd2X3vuaXm/zTmLjTXL6oO2tYaF6UQ=; b=Og2XXmTF4g2XZzX/aBeXTLp+z90Ot7fBlJ9A2gLhgIiP0rCNe85/2E0pcGmHZtm2cqrliK L77AZAMubI/tvsCE9p5E7UhYb6YmJStLKnjZ7NS6V5fEFTLYS1ElI1oe7Dez/77hoPY7WP yCdQ9E2poz9lbHxLNGmg5fgNALVheiQTx7FLRnamOYtWk4zRpD1DMuQlCPJfiUpbzTcwp6 yV43drs2T+farg7xyqNXa54UMJZ4TpicWl4BipvKOkBYm0b/BpePIF2qPy1IRetA//Ts0G fGK5gLTJtUjZUiDnnx71+P0O6LX6QpEN8cLH5SOgVwvHeClIQjgu6alEJR+hjg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j72Mf1tVrzvrJ for ; Sun, 18 Oct 2026 15:16:46 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 40fa2 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 18 Oct 2026 15:16:46 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: JustAnotherHumanBeing From: Vladimir Kondratyev Subject: git: 2ff9182d8921 - main - LinuxKPI: account for delayed work cancelled after taskqueue dequeue List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: Commit messages for the main branch of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: wulf X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 2ff9182d89215322de1958057bf2345d34a6576e Auto-Submitted: auto-generated Date: Sun, 18 Oct 2026 15:16:46 +0000 Message-Id: <6ad4e2de.40fa2.249bf6c5@gitrepo.freebsd.org> The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=2ff9182d89215322de1958057bf2345d34a6576e commit 2ff9182d89215322de1958057bf2345d34a6576e Author: JustAnotherHumanBeing AuthorDate: 2026-10-18 15:15:54 +0000 Commit: Vladimir Kondratyev CommitDate: 2026-10-18 15:15:54 +0000 LinuxKPI: account for delayed work cancelled after taskqueue dequeue I encounter intermittent shutdown/restart hangs with i915/GuC and the normal 34 ms scheduling-disable delay. Setting that delay to zero has avoided the hang in my testing. This change fixes a reproducible LinuxKPI cancellation-accounting defect that can leave the corresponding context reference unreleased, rather than changing the driver's delay. Commit 79e290d96786 corrected the ordinary queued and already-executing return values of cancel_delayed_work_sync(). There is still a gap between native taskqueue dequeue and LinuxKPI callback ownership: 1. In sys/kern/subr_taskqueue.c, taskqueue_run_locked() removes the task, clears ta_pending and sets tb_running before calling its handler. 2. Before linux_work_fn() claims the callback, linux_cancel_delayed_work_sync_int() atomically changes WORK_ST_TASK to WORK_ST_IDLE. 3. taskqueue_cancel() can now return EBUSY with pending == 0: the native task is busy, but the Linux callback has not started. 4. linux_work_fn() subsequently sees IDLE and skips the callback. The cancelling thread drains the task and retries, but returns false because neither the timer-stop result nor the native pending count records what it cancelled. The task can also finish consuming IDLE before taskqueue_cancel() is called, giving success with pending == 0 and the same incorrect false return. This affects zero-delay WORK_ST_TIMER and WORK_ST_CANCEL left by a failed nonblocking cancellation as well. A zero-delay self-requeue handled by linux_work_fn()'s executor loop can similarly be pending without a native queue entry. Use the old state returned by the atomic transition to account for pending work suppressed by this cancellation: TIMER, TASK and CANCEL contribute a true result. EXEC does not: the callback has already been claimed, or has finished with that sticky state. Keep the native pending-count aggregation, drain operations and retry decisions unchanged; use a separate local variable for the callout-stop result. In particular, EBUSY alone is not treated as successful cancellation, which would regress the already-running-callback case fixed by 79e290d96786. One affected consumer is guc_request_alloc() in drm-kmod's drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c. It calls intel_context_sched_disable_unpin() when cancel_delayed_work_sync() returns true. Suppressing the delayed callback while returning false can leave neither path responsible for releasing that reference, retaining the engine wakeref that shutdown later waits for. Fixes: 79e290d96786 ("Fix cancel_delayed_work_sync() return value") Signed-off-by: JustAnotherHumanBeing Differential Revision: https://reviews.freebsd.org/D60046 --- sys/compat/linuxkpi/common/src/linux_work.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c index bf4c82767621..8667fe75b948 100644 --- a/sys/compat/linuxkpi/common/src/linux_work.c +++ b/sys/compat/linuxkpi/common/src/linux_work.c @@ -507,12 +507,10 @@ linux_cancel_delayed_work(struct delayed_work *dwork) } /* - * This function cancels the given delayed work structure in a - * synchronous fashion. It returns true if pending delayed work was - * cancelled. Else the work was not pending. + * Cancel and drain delayed work, reporting cancelled pending work through + * cancelled and the taskqueue pending count through pending. * - * If the work restarted itself or was busy while being cancelled, - * retry_needed is set to true so the caller can re-check the state. + * Return true if the caller needs to re-check the state after draining. */ static bool linux_cancel_delayed_work_sync_int(struct delayed_work *dwork, u_int *pending, @@ -527,19 +525,30 @@ linux_cancel_delayed_work_sync_int(struct delayed_work *dwork, u_int *pending, }; struct taskqueue *tq; int ret, state; + bool stopped; WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "linux_cancel_delayed_work_sync() might sleep"); mtx_lock(&dwork->timer.mtx); state = linux_update_state(&dwork->work.state, states); + /* + * A taskqueue worker can have dequeued the task without linux_work_fn() + * having claimed the callback yet. In that case taskqueue_cancel() + * reports EBUSY with no pending tasks, but our transition to IDLE still + * prevents the callback. Account for this using the state consumed by + * the atomic transition, not just the native queue's pending count. + * WORK_ST_EXEC, in contrast, means the callback was already claimed. + */ + *cancelled = (state == WORK_ST_TIMER || state == WORK_ST_TASK || + state == WORK_ST_CANCEL); switch (state) { case WORK_ST_IDLE: mtx_unlock(&dwork->timer.mtx); return (false); case WORK_ST_TIMER: case WORK_ST_CANCEL: - *cancelled = (callout_stop(&dwork->timer.callout) == 1); + stopped = (callout_stop(&dwork->timer.callout) == 1); tq = dwork->work.work_queue->taskqueue; ret = taskqueue_cancel(tq, &dwork->work.work_task, pending); @@ -547,7 +556,7 @@ linux_cancel_delayed_work_sync_int(struct delayed_work *dwork, u_int *pending, callout_drain(&dwork->timer.callout); taskqueue_drain(tq, &dwork->work.work_task); - return (*cancelled || (ret != 0)); + return (stopped || (ret != 0)); default: tq = dwork->work.work_queue->taskqueue; ret = taskqueue_cancel(tq, &dwork->work.work_task, pending);