All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marek Czernohous <mczernohous@gmail.com>
To: nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: sashiko-bot@kernel.org, linux-kernel@vger.kernel.org,
	Danilo Krummrich <dakr@kernel.org>, Lyude Paul <lyude@redhat.com>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>
Subject: Re: [PATCH 1/3] drm/nouveau: destroy the fence event before cancelling its work
Date: Sat, 15 Aug 2026 22:25:28 +0200	[thread overview]
Message-ID: <178682552848.3774290.16460050233438707000@gmail.com> (raw)
In-Reply-To: <20260815200914.8A1131F000E9@smtp.kernel.org>

The bot is right, and this is worse than a wording problem: 1/3 does
introduce the race, it does not merely fail to rule it out.  Please
do not apply 1/3.  2/3 and 3/3 are independent of it and unaffected.

What I missed is why the old order was safe in the first place.  It was
not an accident of ordering, it was load-bearing:

  nouveau_fence_context_kill() signals every fence on fctx->pending,
  and dma_fence_add_callback() returns -ENOENT for an already signalled
  fence before it ever reaches __dma_fence_enable_signaling()
  (drivers/dma-buf/dma-fence.c:707-710).  So once the kill has run,
  nouveau_fence_enable_signaling() is no longer reachable for those
  fences, and nvif_event_dtor() afterwards has nobody left to race
  with.

Moving the dtor to the front puts it exactly where those fences are
still live, so nvif_event_allow() can be in flight on another CPU with
nvif_event_constructed() already evaluated to true.  There is nothing to
serialise the two: nouveau_fence_context_del() takes no lock at all,
enable_signaling() runs under fence->lock, which for nouveau is
fctx->lock (nouveau_fence.c:218-219), and the dtor cannot take that,
since the nvif ioctl may sleep and fctx->lock is taken with interrupts
off.  The window is then held open for the whole of cancel_work_sync(),
which can block arbitrarily long.

So my patch traded a narrow re-arm window for a wider NULL-deref window.
That is a bad trade and my commit message argued for it with a "guard"
that is a plain unsynchronised read of object->client.

The re-arm problem the patch was aimed at is real, but the fix has to
keep the kill in front of the dtor.  The obvious shape is to move the
drain to the back instead of the dtor to the front:

	nouveau_fence_context_kill(fctx, 0);
	nvif_event_dtor(&fctx->event);
	cancel_work_sync(&fctx->uevent_work);

The kill closes enable_signaling(), the dtor then stops the handler, and
the drain last picks up anything the handler queued on its way out.  I
want to convince myself properly that kill-before-drain is safe, rather
than send a second version tonight on the strength of it looking right,
so I will post a v2 once I have.

Thanks to the bot for catching this before anyone applied it.  For what
it is worth, my own review pass had found the same mechanism a few hours
earlier and I mis-filed it as a wording problem in the commit message
instead of asking whether the patch itself was wrong.  That one is on
me.

WARNING: multiple messages have this Message-ID (diff)
From: Marek Czernohous <mczernohous@gmail.com>
To: nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: sashiko-bot@kernel.org, linux-kernel@vger.kernel.org,
	Danilo Krummrich <dakr@kernel.org>,
	Simona Vetter <simona@ffwll.ch>
Subject: Re: [PATCH 1/3] drm/nouveau: destroy the fence event before cancelling its work
Date: Sat, 15 Aug 2026 22:25:28 +0200	[thread overview]
Message-ID: <178682552848.3774290.16460050233438707000@gmail.com> (raw)
In-Reply-To: <20260815200914.8A1131F000E9@smtp.kernel.org>

The bot is right, and this is worse than a wording problem: 1/3 does
introduce the race, it does not merely fail to rule it out.  Please
do not apply 1/3.  2/3 and 3/3 are independent of it and unaffected.

What I missed is why the old order was safe in the first place.  It was
not an accident of ordering, it was load-bearing:

  nouveau_fence_context_kill() signals every fence on fctx->pending,
  and dma_fence_add_callback() returns -ENOENT for an already signalled
  fence before it ever reaches __dma_fence_enable_signaling()
  (drivers/dma-buf/dma-fence.c:707-710).  So once the kill has run,
  nouveau_fence_enable_signaling() is no longer reachable for those
  fences, and nvif_event_dtor() afterwards has nobody left to race
  with.

Moving the dtor to the front puts it exactly where those fences are
still live, so nvif_event_allow() can be in flight on another CPU with
nvif_event_constructed() already evaluated to true.  There is nothing to
serialise the two: nouveau_fence_context_del() takes no lock at all,
enable_signaling() runs under fence->lock, which for nouveau is
fctx->lock (nouveau_fence.c:218-219), and the dtor cannot take that,
since the nvif ioctl may sleep and fctx->lock is taken with interrupts
off.  The window is then held open for the whole of cancel_work_sync(),
which can block arbitrarily long.

So my patch traded a narrow re-arm window for a wider NULL-deref window.
That is a bad trade and my commit message argued for it with a "guard"
that is a plain unsynchronised read of object->client.

The re-arm problem the patch was aimed at is real, but the fix has to
keep the kill in front of the dtor.  The obvious shape is to move the
drain to the back instead of the dtor to the front:

	nouveau_fence_context_kill(fctx, 0);
	nvif_event_dtor(&fctx->event);
	cancel_work_sync(&fctx->uevent_work);

The kill closes enable_signaling(), the dtor then stops the handler, and
the drain last picks up anything the handler queued on its way out.  I
want to convince myself properly that kill-before-drain is safe, rather
than send a second version tonight on the strength of it looking right,
so I will post a v2 once I have.

Thanks to the bot for catching this before anyone applied it.  For what
it is worth, my own review pass had found the same mechanism a few hours
earlier and I mis-filed it as a wording problem in the commit message
instead of asking whether the patch itself was wrong.  That one is on
me.

  reply	other threads:[~2026-08-15 20:25 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-15 19:54 [PATCH 0/3] drm/nouveau: teardown ordering fixes for events and work Marek Czernohous
2026-08-15 19:54 ` Marek Czernohous
2026-08-15 19:54 ` [PATCH 2/3] drm/nouveau: cancel the DP IRQ work before freeing the connector Marek Czernohous
2026-08-15 19:54   ` Marek Czernohous
2026-08-15 20:11   ` sashiko-bot
2026-08-15 20:42     ` Marek Czernohous
2026-08-15 20:42       ` Marek Czernohous
2026-08-20 18:26       ` lyude
2026-08-20 18:26         ` lyude
2026-08-20 18:36       ` lyude
2026-08-20 18:36         ` lyude
2026-08-20 18:13   ` lyude
2026-08-20 18:13     ` lyude
2026-08-20 18:27   ` lyude
2026-08-20 18:27     ` lyude
2026-08-15 19:54 ` [PATCH 3/3] drm/nouveau: don't dereference outp before checking it in nouveau_dp_irq Marek Czernohous
2026-08-15 19:54   ` Marek Czernohous
2026-08-20 18:28   ` lyude
2026-08-20 18:28     ` lyude
2026-08-15 19:54 ` [PATCH 1/3] drm/nouveau: destroy the fence event before cancelling its work Marek Czernohous
2026-08-15 19:54   ` Marek Czernohous
2026-08-15 20:09   ` sashiko-bot
2026-08-15 20:25     ` Marek Czernohous [this message]
2026-08-15 20:25       ` Marek Czernohous
2026-08-16 12:58   ` [PATCH v2] drm/nouveau: disable the fence uevent work instead of just cancelling it Marek Czernohous
2026-08-16 12:58     ` Marek Czernohous
2026-08-16 13:21     ` Marek Czernohous
2026-08-16 13:21       ` Marek Czernohous
2026-08-20 17:55     ` lyude
2026-08-20 17:55       ` lyude
2026-08-20 18:08       ` lyude
2026-08-20 18:08         ` lyude
2026-08-18 23:58 ` [PATCH 0/3] drm/nouveau: teardown ordering fixes for events and work lyude
2026-08-18 23:58   ` lyude

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178682552848.3774290.16460050233438707000@gmail.com \
    --to=mczernohous@gmail.com \
    --cc=airlied@gmail.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lyude@redhat.com \
    --cc=nouveau@lists.freedesktop.org \
    --cc=sashiko-bot@kernel.org \
    --cc=simona@ffwll.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.