From nobody Sun Feb 8 02:34:50 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB37B18A956 for ; Thu, 8 Jan 2026 16:07:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767888468; cv=none; b=Vujf1l4fKBLu+u21s4h89NBkj527ilLTWDwoH/e4Sa+w+b+vDU9apaDlORpD24zN16Law/0txcqw26udFRrWk3k9LJmNyZgZNiGHe5TRCC+QUUlm1A6ed8z6MIy+0IoErBHeeQf6U4fZwFrFHbuEkw10RFD6+Cm/Wq7eDA3bS+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767888468; c=relaxed/simple; bh=hbq4/W/YT1F2KaupP7lFjIsAXhr1Ga/gdbdjOJfduHM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=IA+1VRSAc2VOXnzONqx7ewHqiiUoznTB9KlzLhMES+33PYXXrFqiOC3ANcZgIbBhsR1LsiBfW1KyYKtnnWYuFV6Y4+EcYbj3G46CGjGnl8Rqxy4OUK0rrJvtlYmzCQr8rqC/5HTP3ZsyDUrwgDe997DSFBJNxf/FCEX4VA2qhms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gPJzyNQB; arc=none smtp.client-ip=209.85.128.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gPJzyNQB" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-47d1622509eso22267055e9.3 for ; Thu, 08 Jan 2026 08:07:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767888464; x=1768493264; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=7DBTz/lbvXhEQEV6ZtSo3RgwmEle7n+kvmz64QebNMQ=; b=gPJzyNQBgxvF9Ebm3QkUuzIbNWSb0uZtBJFGqfzSTfYyQDik6QSMp4JuOUmmTcgmIx sUo8JHqY2HorWSgttN6PyJipWD7FbiM96F7FCN2VFoFRF3KRQ22cZyuucXMgaP6/8oZH 3Jd7wg73J2c4e6VS2sXdxIAviSGc7eGpsRtKqReE73o7mfjODzaoJkzq5mXXZj5nA/Mt LPCWayLz/HpgMDyHXhYhLB85wp9BI1ApYIp48CpKF59BIj4C8zNQ0W9lPmPmYHgwItl/ rP3IOlt5bktfaxCR57oCoGijkVjfpmZJGTmfIaVy5PXTnTDVmNhQQD/zdY6pvNRT15mb mtrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767888464; x=1768493264; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=7DBTz/lbvXhEQEV6ZtSo3RgwmEle7n+kvmz64QebNMQ=; b=YxL4lbvihsE0yoqWfED77lBsR2dwuxCVBA2tG6dho6lmFGQy4j+0DR98H/p7JEPOtl pYgO3tiNqqYyPAAR+xxXBJ/3TURi333BE4bPaF76P0n9UrHyqE/DE+VUoUcBab1Xs6An SpMNqZNAw6WAB88uueK/m/jLADXPFFRE/yTXNW9A4je8Sxq6gepUklWsd9i55sRMtRxI 0YzVt7xRWdrRmIY8qU3mWN7wbbR3TQ5LTT9KFz4BinC2SiCuvRHpDrWxL6TsdbgvD8GN Z5x/FkbGqkD9dkOz8HJNUYS2grchZKDqREpbTUTsw3UkX33awu/Wy/6TbDqeg4mQDS+Q ZGBg== X-Forwarded-Encrypted: i=1; AJvYcCU6fHDHjJCG4DZfIbCwPinOTt3/EHgpvWT4CKHbQUGqt/DgszPwKLxtoJDBzBDEJBOZrxP8P1WF13LLXYU=@vger.kernel.org X-Gm-Message-State: AOJu0YwUfBeAprZHVFY+LVfhczUfo+EPdbtXTVeun+ahujPQ+pktXlbE iRwOwCmPC8EvRerrNEeG/ZFjG0uYSjXXbu5zZWe9wubimbk4vHM8r+4BLT9ELpgHdXGf/hzq9Lm hqEcZWxxawWf8CiAHOA== X-Google-Smtp-Source: AGHT+IEO61c6TkZz/86mc/fyFkwWFW5LTEzhYmLyOElq55K/6sHbmhaCJ0Qo8xpHZev+T6S1nwRZjKWIEJKKzW0= X-Received: from wmlm26.prod.google.com ([2002:a7b:ca5a:0:b0:479:36b0:ff54]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:3112:b0:477:7f4a:44b4 with SMTP id 5b1f17b1804b1-47d84b26d08mr75677725e9.1.1767888464327; Thu, 08 Jan 2026 08:07:44 -0800 (PST) Date: Thu, 08 Jan 2026 16:07:31 +0000 In-Reply-To: <20260108-gpuvm-rust-v2-0-dbd014005a0b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260108-gpuvm-rust-v2-0-dbd014005a0b@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=6461; i=aliceryhl@google.com; h=from:subject:message-id; bh=hbq4/W/YT1F2KaupP7lFjIsAXhr1Ga/gdbdjOJfduHM=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBpX9ZN+0wnx9w0LDMduz613MpMKku8f0voThE3Z VzJVjwhM/yJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCaV/WTQAKCRAEWL7uWMY5 RhMXEACFw5E17eKTmxVsYmy97LYcw5RX+DOlTERXnLWyfaTGCutXDAMFYjO7Cgyx+2/qtxqCb99 hqDf4YYo3waLduiBL4An1/5xi73UuveVXb5QI2UU/IJH0WuTRV1HqeJkJ1IONrrkyW4noiadkVn Gw0eYLMfquuDYyOoUaErOw4VxStseS9p+FmlVRd/Ptf9SioxTfAJcd4phn5ghFDcv4n68RkedVX q4IOWzJeW6Z5Og/KeZ61MnjiheBZN+inCavhoLY1/50CajqYdCNp0IBKTria754kM1uj15kCHUu rbMNXd3o96bQovwfPVHwjT3gBTKyVajwwNIJbhMg1NckrQGcL91mFLkD7bwdx1bQhtx7Pw3ZiyC adN2XCGu97NVvZmRLGGovP1S6SY7VhMawU9B9m/E8REl/X4Nt33rR8AEJUrmcz9yMBtfdtCEHq6 QVkQ95QrPSf47m6PiDvjCPHicsXk8NeU0Ov6x1ucR0Ctpke9AMvT2Uu1zvSiDrJGXEJ7dsQkBeM Hkus5GvVkeYMcl7ZKC9NDu83ngLhyrCerTytirGraddM5y1Df5LVmtDeXHwnZLxX7rVxO0kWE4y kLY8maZejGtiEnO+uENM35VvKbvwGzNNApaxvBCpT/qEKian2IAu9pRgHonllLlMU5kKWHkQL9r wXLj8nU1Xc+Xczg== X-Mailer: b4 0.14.2 Message-ID: <20260108-gpuvm-rust-v2-1-dbd014005a0b@google.com> Subject: [PATCH v2 1/3] drm/gpuvm: take GEM lock inside drm_gpuvm_bo_obtain_prealloc() From: Alice Ryhl To: Danilo Krummrich , Daniel Almeida Cc: Matthew Brost , "=?utf-8?q?Thomas_Hellstr=C3=B6m?=" , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Boris Brezillon , Steven Price , Liviu Dudau , Miguel Ojeda , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Trevor Gross , Frank Binns , Matt Coster , Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Sean Paul , Marijn Suijten , Lyude Paul , Rodrigo Vivi , Sumit Semwal , "=?utf-8?q?Christian_K=C3=B6nig?=" , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-arm-msm@vger.kernel.org, freedreno@lists.freedesktop.org, nouveau@lists.freedesktop.org, intel-xe@lists.freedesktop.org, linux-media@vger.kernel.org, Alice Ryhl Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable When calling drm_gpuvm_bo_obtain_prealloc() and using immediate mode, this may result in a call to ops->vm_bo_free(vm_bo) while holding the GEMs gpuva mutex. This is a problem if ops->vm_bo_free(vm_bo) performs any operations that are not safe in the fence signalling critical path, and it turns out that Panthor (the only current user of the method) calls drm_gem_shmem_unpin() which takes a resv lock internally. This constitutes both a violation of signalling safety and lock inversion. To fix this, we modify the method to internally take the GEMs gpuva mutex so that the mutex can be unlocked before freeing the preallocated vm_bo. Note that this modification introduces a requirement that the driver uses immediate mode to call drm_gpuvm_bo_obtain_prealloc() as it would otherwise take the wrong lock. Fixes: 63e919a31625 ("panthor: use drm_gpuva_unlink_defer()") Reviewed-by: Boris Brezillon Signed-off-by: Alice Ryhl --- drivers/gpu/drm/drm_gpuvm.c | 69 ++++++++++++++++++++++++-------= ---- drivers/gpu/drm/panthor/panthor_mmu.c | 10 ----- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 8a06d296561d1a4b61a7137f8017a78d4ada3a7c..0de47e83d84df11a53e40fe82d0= 69882e46149b6 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1602,14 +1602,48 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create); =20 +/* + * drm_gpuvm_bo_destroy_not_in_lists() - final part of drm_gpuvm_bo cleanup + * @vm_bo: the &drm_gpuvm_bo to destroy + * + * It is illegal to call this method if the @vm_bo is present in the GEMs = gpuva + * list, the extobj list, or the evicted list. + * + * Note that this puts a refcount on the GEM object, which may destroy the= GEM + * object if the refcount reaches zero. It's illegal for this to happen if= the + * caller holds the GEMs gpuva mutex because it would free the mutex. + */ +static void +drm_gpuvm_bo_destroy_not_in_lists(struct drm_gpuvm_bo *vm_bo) +{ + struct drm_gpuvm *gpuvm =3D vm_bo->vm; + const struct drm_gpuvm_ops *ops =3D gpuvm->ops; + struct drm_gem_object *obj =3D vm_bo->obj; + + if (ops && ops->vm_bo_free) + ops->vm_bo_free(vm_bo); + else + kfree(vm_bo); + + drm_gpuvm_put(gpuvm); + drm_gem_object_put(obj); +} + +static void +drm_gpuvm_bo_destroy_not_in_lists_kref(struct kref *kref) +{ + struct drm_gpuvm_bo *vm_bo =3D container_of(kref, struct drm_gpuvm_bo, + kref); + + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); +} + static void drm_gpuvm_bo_destroy(struct kref *kref) { struct drm_gpuvm_bo *vm_bo =3D container_of(kref, struct drm_gpuvm_bo, kref); struct drm_gpuvm *gpuvm =3D vm_bo->vm; - const struct drm_gpuvm_ops *ops =3D gpuvm->ops; - struct drm_gem_object *obj =3D vm_bo->obj; bool lock =3D !drm_gpuvm_resv_protected(gpuvm); =20 if (!lock) @@ -1618,16 +1652,10 @@ drm_gpuvm_bo_destroy(struct kref *kref) drm_gpuvm_bo_list_del(vm_bo, extobj, lock); drm_gpuvm_bo_list_del(vm_bo, evict, lock); =20 - drm_gem_gpuva_assert_lock_held(gpuvm, obj); + drm_gem_gpuva_assert_lock_held(gpuvm, vm_bo->obj); list_del(&vm_bo->list.entry.gem); =20 - if (ops && ops->vm_bo_free) - ops->vm_bo_free(vm_bo); - else - kfree(vm_bo); - - drm_gpuvm_put(gpuvm); - drm_gem_object_put(obj); + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); } =20 /** @@ -1745,9 +1773,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put_deferred); void drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuvm) { - const struct drm_gpuvm_ops *ops =3D gpuvm->ops; struct drm_gpuvm_bo *vm_bo; - struct drm_gem_object *obj; struct llist_node *bo_defer; =20 bo_defer =3D llist_del_all(&gpuvm->bo_defer); @@ -1766,14 +1792,7 @@ drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuv= m) while (bo_defer) { vm_bo =3D llist_entry(bo_defer, struct drm_gpuvm_bo, list.entry.bo_defer= ); bo_defer =3D bo_defer->next; - obj =3D vm_bo->obj; - if (ops && ops->vm_bo_free) - ops->vm_bo_free(vm_bo); - else - kfree(vm_bo); - - drm_gpuvm_put(gpuvm); - drm_gem_object_put(obj); + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); } } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_deferred_cleanup); @@ -1861,6 +1880,9 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); * count is decreased. If not found @__vm_bo is returned without further * increase of the reference count. * + * The provided @__vm_bo must not already be in the gpuva, evict, or extobj + * lists prior to calling this method. + * * A new &drm_gpuvm_bo is added to the GEMs gpuva list. * * Returns: a pointer to the found &drm_gpuvm_bo or @__vm_bo if no existing @@ -1873,14 +1895,19 @@ drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *_= _vm_bo) struct drm_gem_object *obj =3D __vm_bo->obj; struct drm_gpuvm_bo *vm_bo; =20 + drm_WARN_ON(gpuvm->drm, !drm_gpuvm_immediate_mode(gpuvm)); + + mutex_lock(&obj->gpuva.lock); vm_bo =3D drm_gpuvm_bo_find(gpuvm, obj); if (vm_bo) { - drm_gpuvm_bo_put(__vm_bo); + mutex_unlock(&obj->gpuva.lock); + kref_put(&__vm_bo->kref, drm_gpuvm_bo_destroy_not_in_lists_kref); return vm_bo; } =20 drm_gem_gpuva_assert_lock_held(gpuvm, obj); list_add_tail(&__vm_bo->list.entry.gem, &obj->gpuva.list); + mutex_unlock(&obj->gpuva.lock); =20 return __vm_bo; } diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index b888fff05efe2ba035d0b4f639e8134d258b54be..198d59f42578fb75da7e2447340= 53c02d09dc129 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1244,17 +1244,7 @@ static int panthor_vm_prepare_map_op_ctx(struct pant= hor_vm_op_ctx *op_ctx, goto err_cleanup; } =20 - /* drm_gpuvm_bo_obtain_prealloc() will call drm_gpuvm_bo_put() on our - * pre-allocated BO if the association exists. Given we - * only have one ref on preallocated_vm_bo, drm_gpuvm_bo_destroy() will - * be called immediately, and we have to hold the VM resv lock when - * calling this function. - */ - dma_resv_lock(panthor_vm_resv(vm), NULL); - mutex_lock(&bo->base.base.gpuva.lock); op_ctx->map.vm_bo =3D drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); - mutex_unlock(&bo->base.base.gpuva.lock); - dma_resv_unlock(panthor_vm_resv(vm)); =20 op_ctx->map.bo_offset =3D offset; =20 --=20 2.52.0.351.gbe84eed79e-goog