Hi Felix,
No objection at all - 16f0013157bf ("drm/amdkfd: Allocate doorbells
only when needed") looks right to me. Thanks for the archaeology
and for taking care of the tag before submission.
Regards,
Henry
Felix Kuehling <[email protected]> 于2026年10月14日周三 01:40写道:
>
> On 2026-10-09 23:02, Henry Martin wrote:
> > The check-and-allocate sequence on pdd->qpd.proc_doorbells is
> > lockless at every call site of kfd_alloc_process_doorbells():
> > kfd_get_process_doorbells() (mmap of /dev/kfd),
> > kfd_ioctl_create_queue() and the CRIU restore path each test the
> > pointer under different locking (or none), so two racing threads can
> > both observe NULL and each allocate a doorbell BO and bitmap,
> > orphaning one allocation and handing the two mappings different
> > backing pages.
> >
> > Move the serialization into kfd_alloc_process_doorbells() itself,
> > using a new per-process-device mutex so all three call sites are
> > covered regardless of their own locking. The device-global
> > kfd->doorbell_mutex is not suitable here: it is acquired under
> > dqm->lock on the kernel-doorbell path (start_cpsch() -> pm_init() ->
> > kq_initialize() -> kfd_get_kernel_doorbell()), so holding it across
> > the sleeping allocations above would create a lock-ordering
> > inversion with dqm->lock via TTM eviction, and it would also
> > serialize doorbell setup of unrelated processes behind a
> > device-wide lock for per-process state.
> >
> > This issue was discovered by Tencent CodeBuddy Security.
> >
> > Cc: [email protected]
> > Fixes: 2105a15a2046 ("drm/amdgpu: use doorbell mgr for kfd process
> > doorbells")
>
> I don't think the Fixes tag is correct, even though that's what Claude
> suggested. As far as I can see, the code had the same possible race
> condition before that change. I believe the problem goes back all the
> way to 16f0013157bf ("drm/amdkfd: Allocate doorbells only when needed").
> If you don't mind, I'll update that in the commit description before I
> submit your patch. With that, the patch is
>
> Reviewed-by: Felix Kuehling <[email protected]>
>
> Thanks,
> Felix
>
>
> > Signed-off-by: Henry Martin <[email protected]>
> > ---
> >
> > v2: Use a per-process-device mutex instead of kfd->doorbell_mutex
> > (avoids the dqm->lock ordering inversion and the device-wide
> > serialization) and correct the Fixes tag. Pointed out by Felix
> > Kuehling.
> >
> > drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
> > drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 +++
> > drivers/gpu/drm/amd/amdkfd/kfd_process.c | 1 +
> > 3 files changed, 18 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> > b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> > index fdcf7f2d1b5b4..55acadc986bee 100644
> > --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> > +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> > @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd,
> > struct kfd_process_device *
> > int r;
> > struct qcm_process_device *qpd = &pdd->qpd;
> >
> > + mutex_lock(&pdd->doorbell_mutex);
> > +
> > + /* Another thread may have won the check-and-allocate race */
> > + if (qpd->proc_doorbells) {
> > + mutex_unlock(&pdd->doorbell_mutex);
> > + return 0;
> > + }
> > +
> > /* Allocate bitmap for dynamic doorbell allocation */
> > qpd->doorbell_bitmap =
> > bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
> > GFP_KERNEL);
> > if (!qpd->doorbell_bitmap) {
> > DRM_ERROR("Failed to allocate process doorbell bitmap\n");
> > - return -ENOMEM;
> > + r = -ENOMEM;
> > + goto unlock;
> > }
> >
> > r = init_doorbell_bitmap(&pdd->qpd, kfd);
> > @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd,
> > struct kfd_process_device *
> > DRM_ERROR("Failed to allocate process doorbells\n");
> > goto err;
> > }
> > +
> > + mutex_unlock(&pdd->doorbell_mutex);
> > return 0;
> >
> > err:
> > bitmap_free(qpd->doorbell_bitmap);
> > qpd->doorbell_bitmap = NULL;
> > +unlock:
> > + mutex_unlock(&pdd->doorbell_mutex);
> > return r;
> > }
> >
> > diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> > b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> > index d8631847f0eb9..96e59133fee02 100644
> > --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> > +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> > @@ -779,6 +779,9 @@ struct kfd_process_device {
> > /* per-process-per device QCM data structure */
> > struct qcm_process_device qpd;
> >
> > + /* Serializes process doorbell allocation for this device */
> > + struct mutex doorbell_mutex;
> > +
> > /*Apertures*/
> > uint64_t lds_base;
> > uint64_t lds_limit;
> > diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> > b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> > index 0a7c1900da959..4efe4dae79c13 100644
> > --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> > +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> > @@ -1788,6 +1788,7 @@ struct kfd_process_device
> > *kfd_create_process_device_data(struct kfd_node *dev,
> > pdd->dev = dev;
> > INIT_LIST_HEAD(&pdd->qpd.queues_list);
> > INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
> > + mutex_init(&pdd->doorbell_mutex);
> > pdd->qpd.dqm = dev->dqm;
> > pdd->qpd.pqm = &p->pqm;
> > pdd->qpd.evicted = 0;