All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes
@ 2026-10-09  8:52 ` Junrui Luo
  0 siblings, 0 replies; 5+ messages in thread
From: Junrui Luo via B4 Relay @ 2026-10-09  8:52 UTC (permalink / raw)
  To: Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Andrew Morton,
	Balbir Singh, Mary Guillemard, Mohamed Ahmed, James Jones
  Cc: dri-devel, nouveau, linux-kernel, Yuhao Jiang, stable, Junrui Luo

From: Junrui Luo <moonafterrain@outlook.com>

A new mapping takes over the page tables of the mappings it replaces.
nouveau_uvmm_sm_prepare() only acquires page tables for the range no
existing mapping covers, and the map path frees the replaced mappings
without putting their references. That is only valid while all of them
use the same page size, which select_page_shift() no longer guarantees.

Rebinding a GART BO over a 2MiB VRAM BO therefore leaves the new mapping
owning page tables built for a different page size, and it then maps at a
size that was never referenced over that range. Since raw map does not
allocate, nvkm_vmm_iter() can walk down to a NULL leaf and dereference
it. The remainders of a split have the same problem: op_map_prepare()
recomputes a page size with select_page_shift() while the remainder keeps
the parent's page tables, so a parent that was itself downgraded can leave
a remainder that re-aligns to a larger size. This happens on the unmap
path too.

Reject the bind, and make split remainders inherit the page size of the
mapping they are split from.

Fixes: c488a94e7e14 ("drm/nouveau/uvmm: Allow larger pages")
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Assisted-by: LLM
Cc: stable@vger.kernel.org
Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
---
Changes in v2:
- Drop patch 1, which has been merged.
- Use the abbreviated conditional operator for page_shift (Lyude Paul).
- Compare against remap_args.page_shift (Lyude Paul).
- Use Assisted-by: LLM (Balbir Singh).
- Add Lyude's Reviewed-by.
- Link to v1: https://lore.kernel.org/r/20260817-nouveau-fixes-v1-0-f518d0c735f3@outlook.com
---
 drivers/gpu/drm/nouveau/nouveau_uvmm.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
index f5e4756b4de4..aa5b93808f41 100644
--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
@@ -85,6 +85,8 @@ struct uvmm_map_args {
 	u64 addr;
 	u64 range;
 	u8 kind;
+	/* Page size to give the new mapping, or 0 to derive it from the op. */
+	u8 page_shift;
 };
 
 static int
@@ -655,7 +657,7 @@ op_map_prepare(struct nouveau_uvmm *uvmm,
 
 	uvma->region = args->region;
 	uvma->kind = args->kind;
-	uvma->page_shift = select_page_shift(uvmm, op);
+	uvma->page_shift = args->page_shift ?: select_page_shift(uvmm, op);
 
 	drm_gpuva_map(&uvmm->base, &uvma->va, op);
 
@@ -684,8 +686,20 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 	struct drm_gpuva_op *op;
 	u64 vmm_get_start = args ? args->addr : 0;
 	u64 vmm_get_end = args ? args->addr + args->range : 0;
+	u8 map_page_shift = 0;
 	int ret;
 
+	/* A new mapping takes over the page tables of the mappings it replaces,
+	 * so every one of them has to be using its page size. The new mapping
+	 * is the last op drm_gpuvm_sm_map_ops_create() emits.
+	 */
+	if (args) {
+		struct drm_gpuva_op *last = drm_gpuva_last_op(ops);
+
+		if (last->op == DRM_GPUVA_OP_MAP)
+			map_page_shift = select_page_shift(uvmm, &last->map);
+	}
+
 	drm_gpuva_for_each_op(op, ops) {
 		switch (op->op) {
 		case DRM_GPUVA_OP_MAP: {
@@ -713,11 +727,22 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 			struct uvmm_map_args remap_args = {
 				.kind = uvma_from_va(va)->kind,
 				.region = uvma_from_va(va)->region,
+				/* The remainders of the split keep the page
+				 * tables of the mapping they are split from,
+				 * so they must keep its page size too.
+				 */
+				.page_shift = uvma_from_va(va)->page_shift,
 			};
 			u64 ustart = va->va.addr;
 			u64 urange = va->va.range;
 			u64 uend = ustart + urange;
 
+			if (map_page_shift &&
+			    remap_args.page_shift != map_page_shift) {
+				ret = -EINVAL;
+				goto unwind;
+			}
+
 			op_unmap_prepare(r->unmap);
 
 			if (r->prev) {
@@ -756,6 +781,11 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 			u64 uend = ustart + urange;
 			u8 page_shift = uvma_from_va(va)->page_shift;
 
+			if (map_page_shift && page_shift != map_page_shift) {
+				ret = -EINVAL;
+				goto unwind;
+			}
+
 			op_unmap_prepare(u);
 
 			if (!args)

---
base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
change-id: 20260817-nouveau-fixes-23877845c3ab

Best regards,
-- 
Junrui Luo <moonafterrain@outlook.com>



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes
@ 2026-10-09  8:52 ` Junrui Luo
  0 siblings, 0 replies; 5+ messages in thread
From: Junrui Luo @ 2026-10-09  8:52 UTC (permalink / raw)
  To: Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Andrew Morton,
	Balbir Singh, Mary Guillemard, Mohamed Ahmed, James Jones
  Cc: dri-devel, nouveau, linux-kernel, Yuhao Jiang, stable, Junrui Luo

A new mapping takes over the page tables of the mappings it replaces.
nouveau_uvmm_sm_prepare() only acquires page tables for the range no
existing mapping covers, and the map path frees the replaced mappings
without putting their references. That is only valid while all of them
use the same page size, which select_page_shift() no longer guarantees.

Rebinding a GART BO over a 2MiB VRAM BO therefore leaves the new mapping
owning page tables built for a different page size, and it then maps at a
size that was never referenced over that range. Since raw map does not
allocate, nvkm_vmm_iter() can walk down to a NULL leaf and dereference
it. The remainders of a split have the same problem: op_map_prepare()
recomputes a page size with select_page_shift() while the remainder keeps
the parent's page tables, so a parent that was itself downgraded can leave
a remainder that re-aligns to a larger size. This happens on the unmap
path too.

Reject the bind, and make split remainders inherit the page size of the
mapping they are split from.

Fixes: c488a94e7e14 ("drm/nouveau/uvmm: Allow larger pages")
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Assisted-by: LLM
Cc: stable@vger.kernel.org
Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
---
Changes in v2:
- Drop patch 1, which has been merged.
- Use the abbreviated conditional operator for page_shift (Lyude Paul).
- Compare against remap_args.page_shift (Lyude Paul).
- Use Assisted-by: LLM (Balbir Singh).
- Add Lyude's Reviewed-by.
- Link to v1: https://lore.kernel.org/r/20260817-nouveau-fixes-v1-0-f518d0c735f3@outlook.com
---
 drivers/gpu/drm/nouveau/nouveau_uvmm.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
index f5e4756b4de4..aa5b93808f41 100644
--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
@@ -85,6 +85,8 @@ struct uvmm_map_args {
 	u64 addr;
 	u64 range;
 	u8 kind;
+	/* Page size to give the new mapping, or 0 to derive it from the op. */
+	u8 page_shift;
 };
 
 static int
@@ -655,7 +657,7 @@ op_map_prepare(struct nouveau_uvmm *uvmm,
 
 	uvma->region = args->region;
 	uvma->kind = args->kind;
-	uvma->page_shift = select_page_shift(uvmm, op);
+	uvma->page_shift = args->page_shift ?: select_page_shift(uvmm, op);
 
 	drm_gpuva_map(&uvmm->base, &uvma->va, op);
 
@@ -684,8 +686,20 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 	struct drm_gpuva_op *op;
 	u64 vmm_get_start = args ? args->addr : 0;
 	u64 vmm_get_end = args ? args->addr + args->range : 0;
+	u8 map_page_shift = 0;
 	int ret;
 
+	/* A new mapping takes over the page tables of the mappings it replaces,
+	 * so every one of them has to be using its page size. The new mapping
+	 * is the last op drm_gpuvm_sm_map_ops_create() emits.
+	 */
+	if (args) {
+		struct drm_gpuva_op *last = drm_gpuva_last_op(ops);
+
+		if (last->op == DRM_GPUVA_OP_MAP)
+			map_page_shift = select_page_shift(uvmm, &last->map);
+	}
+
 	drm_gpuva_for_each_op(op, ops) {
 		switch (op->op) {
 		case DRM_GPUVA_OP_MAP: {
@@ -713,11 +727,22 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 			struct uvmm_map_args remap_args = {
 				.kind = uvma_from_va(va)->kind,
 				.region = uvma_from_va(va)->region,
+				/* The remainders of the split keep the page
+				 * tables of the mapping they are split from,
+				 * so they must keep its page size too.
+				 */
+				.page_shift = uvma_from_va(va)->page_shift,
 			};
 			u64 ustart = va->va.addr;
 			u64 urange = va->va.range;
 			u64 uend = ustart + urange;
 
+			if (map_page_shift &&
+			    remap_args.page_shift != map_page_shift) {
+				ret = -EINVAL;
+				goto unwind;
+			}
+
 			op_unmap_prepare(r->unmap);
 
 			if (r->prev) {
@@ -756,6 +781,11 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
 			u64 uend = ustart + urange;
 			u8 page_shift = uvma_from_va(va)->page_shift;
 
+			if (map_page_shift && page_shift != map_page_shift) {
+				ret = -EINVAL;
+				goto unwind;
+			}
+
 			op_unmap_prepare(u);
 
 			if (!args)

---
base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
change-id: 20260817-nouveau-fixes-23877845c3ab

Best regards,
-- 
Junrui Luo <moonafterrain@outlook.com>


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes
  2026-10-09  8:52 ` Junrui Luo
  (?)
@ 2026-10-09  9:36 ` sashiko-bot
  -1 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-10-09  9:36 UTC (permalink / raw)
  To: Junrui Luo; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] drm/nouveau: UAF in select_page_shift() due to lockless resource access
--

commit 96b9704295117874e5545da9ce1209804365ab06
Author: Junrui Luo <moonafterrain@outlook.com>

drm/nouveau/uvmm: reject replace across page sizes

This commit fixes an issue where rebinding mappings across different page
sizes leaves split remainders with incorrect page tables. It rejects binds
with mismatched page sizes and ensures split remainders inherit their
parent's page size.

Link: https://lore.kernel.org/r/20260817-nouveau-fixes-v1-0-f518d0c735f3@outlook.com

> diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> index f5e4756b4de4a..aa5b93808f41c 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> @@ -684,8 +686,20 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm,
>  	struct drm_gpuva_op *op;
>  	u64 vmm_get_start = args ? args->addr : 0;
>  	u64 vmm_get_end = args ? args->addr + args->range : 0;
> +	u8 map_page_shift = 0;
>  	int ret;
>  
> +	/* A new mapping takes over the page tables of the mappings it replaces,
> +	 * so every one of them has to be using its page size. The new mapping
> +	 * is the last op drm_gpuvm_sm_map_ops_create() emits.
> +	 */
> +	if (args) {
> +		struct drm_gpuva_op *last = drm_gpuva_last_op(ops);
> +
> +		if (last->op == DRM_GPUVA_OP_MAP)
> +			map_page_shift = select_page_shift(uvmm, &last->map);

[Severity: High]
Does this call to select_page_shift() introduce a Use-After-Free (UAF) due to
lockless resource access?

In nouveau_uvmm_bind_job_submit(), the map prepare sequence is called before
drm_exec_until_all_locked() acquires the GEM objects' dma_resv locks:

drivers/gpu/drm/nouveau/nouveau_uvmm.c:nouveau_uvmm_bind_job_submit() {
    ...
    ret = nouveau_uvmm_sm_map_prepare(uvmm, &op->new,
                                      reg, op->ops,
                                      op->va.addr,
                                      op->va.range,
                                      op->flags & 0xff);
    ...
}

Inside select_page_shift(), the code accesses nvbo->bo.resource and dereferences
its properties without the dma_resv_lock held:

drivers/gpu/drm/nouveau/nouveau_uvmm.c:select_page_shift() {
    ...
    struct nouveau_mem *mem = nouveau_mem(nvbo->bo.resource);
    struct nvif_vmm *vmm = &uvmm->vmm.vmm;
    ...
        /* Skip incompatible domains. */
        if ((mem->mem.type & NVIF_MEM_VRAM) && !vmm->page[i].vram)
            continue;
    ...
}

Because the dma_resv lock is not held during this preparation phase, TTM can
concurrently evict or move the BO, freeing the old ttm_resource (and its
wrapping nouveau_mem structure).

This could leave a dangling pointer and cause a UAF when accessing
mem->mem.type, potentially leading to a kernel panic or privilege escalation.

> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261009-nouveau-fixes-v2-1-a0b71bf8df1b@outlook.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes
  2026-10-09  8:52 ` Junrui Luo
  (?)
  (?)
@ 2026-10-09 22:19 ` lyude
  2026-10-09 22:23   ` lyude
  -1 siblings, 1 reply; 5+ messages in thread
From: lyude @ 2026-10-09 22:19 UTC (permalink / raw)
  To: moonafterrain, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Andrew Morton,
	Balbir Singh, Mary Guillemard, Mohamed Ahmed, James Jones
  Cc: dri-devel, nouveau, linux-kernel, Yuhao Jiang, stable

Looks good to me, will push to drm-misc-fixes in a moment.

On Fri, 2026-10-09 at 16:52 +0800, Junrui Luo via B4 Relay wrote:
> From: Junrui Luo <moonafterrain@outlook.com>
> 
> A new mapping takes over the page tables of the mappings it replaces.
> nouveau_uvmm_sm_prepare() only acquires page tables for the range no
> existing mapping covers, and the map path frees the replaced mappings
> without putting their references. That is only valid while all of
> them
> use the same page size, which select_page_shift() no longer
> guarantees.
> 
> Rebinding a GART BO over a 2MiB VRAM BO therefore leaves the new
> mapping
> owning page tables built for a different page size, and it then maps
> at a
> size that was never referenced over that range. Since raw map does
> not
> allocate, nvkm_vmm_iter() can walk down to a NULL leaf and
> dereference
> it. The remainders of a split have the same problem: op_map_prepare()
> recomputes a page size with select_page_shift() while the remainder
> keeps
> the parent's page tables, so a parent that was itself downgraded can
> leave
> a remainder that re-aligns to a larger size. This happens on the
> unmap
> path too.
> 
> Reject the bind, and make split remainders inherit the page size of
> the
> mapping they are split from.
> 
> Fixes: c488a94e7e14 ("drm/nouveau/uvmm: Allow larger pages")
> Reported-by: Yuhao Jiang <danisjiang@gmail.com>
> Assisted-by: LLM
> Cc: stable@vger.kernel.org
> Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
> Reviewed-by: Lyude Paul <lyude@redhat.com>
> ---
> Changes in v2:
> - Drop patch 1, which has been merged.
> - Use the abbreviated conditional operator for page_shift (Lyude
> Paul).
> - Compare against remap_args.page_shift (Lyude Paul).
> - Use Assisted-by: LLM (Balbir Singh).
> - Add Lyude's Reviewed-by.
> - Link to v1:
> https://lore.kernel.org/r/20260817-nouveau-fixes-v1-0-f518d0c735f3@outlook.com
> ---
>  drivers/gpu/drm/nouveau/nouveau_uvmm.c | 32
> +++++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> index f5e4756b4de4..aa5b93808f41 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> @@ -85,6 +85,8 @@ struct uvmm_map_args {
>  	u64 addr;
>  	u64 range;
>  	u8 kind;
> +	/* Page size to give the new mapping, or 0 to derive it from
> the op. */
> +	u8 page_shift;
>  };
>  
>  static int
> @@ -655,7 +657,7 @@ op_map_prepare(struct nouveau_uvmm *uvmm,
>  
>  	uvma->region = args->region;
>  	uvma->kind = args->kind;
> -	uvma->page_shift = select_page_shift(uvmm, op);
> +	uvma->page_shift = args->page_shift ?:
> select_page_shift(uvmm, op);
>  
>  	drm_gpuva_map(&uvmm->base, &uvma->va, op);
>  
> @@ -684,8 +686,20 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> *uvmm,
>  	struct drm_gpuva_op *op;
>  	u64 vmm_get_start = args ? args->addr : 0;
>  	u64 vmm_get_end = args ? args->addr + args->range : 0;
> +	u8 map_page_shift = 0;
>  	int ret;
>  
> +	/* A new mapping takes over the page tables of the mappings
> it replaces,
> +	 * so every one of them has to be using its page size. The
> new mapping
> +	 * is the last op drm_gpuvm_sm_map_ops_create() emits.
> +	 */
> +	if (args) {
> +		struct drm_gpuva_op *last = drm_gpuva_last_op(ops);
> +
> +		if (last->op == DRM_GPUVA_OP_MAP)
> +			map_page_shift = select_page_shift(uvmm,
> &last->map);
> +	}
> +
>  	drm_gpuva_for_each_op(op, ops) {
>  		switch (op->op) {
>  		case DRM_GPUVA_OP_MAP: {
> @@ -713,11 +727,22 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> *uvmm,
>  			struct uvmm_map_args remap_args = {
>  				.kind = uvma_from_va(va)->kind,
>  				.region = uvma_from_va(va)->region,
> +				/* The remainders of the split keep
> the page
> +				 * tables of the mapping they are
> split from,
> +				 * so they must keep its page size
> too.
> +				 */
> +				.page_shift = uvma_from_va(va)-
> >page_shift,
>  			};
>  			u64 ustart = va->va.addr;
>  			u64 urange = va->va.range;
>  			u64 uend = ustart + urange;
>  
> +			if (map_page_shift &&
> +			    remap_args.page_shift != map_page_shift)
> {
> +				ret = -EINVAL;
> +				goto unwind;
> +			}
> +
>  			op_unmap_prepare(r->unmap);
>  
>  			if (r->prev) {
> @@ -756,6 +781,11 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> *uvmm,
>  			u64 uend = ustart + urange;
>  			u8 page_shift = uvma_from_va(va)-
> >page_shift;
>  
> +			if (map_page_shift && page_shift !=
> map_page_shift) {
> +				ret = -EINVAL;
> +				goto unwind;
> +			}
> +
>  			op_unmap_prepare(u);
>  
>  			if (!args)
> 
> ---
> base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
> change-id: 20260817-nouveau-fixes-23877845c3ab
> 
> Best regards,


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes
  2026-10-09 22:19 ` lyude
@ 2026-10-09 22:23   ` lyude
  0 siblings, 0 replies; 5+ messages in thread
From: lyude @ 2026-10-09 22:23 UTC (permalink / raw)
  To: moonafterrain, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Andrew Morton,
	Balbir Singh, Mary Guillemard, Mohamed Ahmed, James Jones
  Cc: dri-devel, nouveau, linux-kernel, Yuhao Jiang, stable

Wait-nope, hold on. Was double checking this to make sure there wasn't
anything I missed, and the sashiko comment I'm seeing looks quite
legitimate. Mind dropping my R-b and addressing that if it looks
legitimate?

On Fri, 2026-10-09 at 18:19 -0400, lyude@redhat.com wrote:
> Looks good to me, will push to drm-misc-fixes in a moment.
> 
> On Fri, 2026-10-09 at 16:52 +0800, Junrui Luo via B4 Relay wrote:
> > From: Junrui Luo <moonafterrain@outlook.com>
> > 
> > A new mapping takes over the page tables of the mappings it
> > replaces.
> > nouveau_uvmm_sm_prepare() only acquires page tables for the range
> > no
> > existing mapping covers, and the map path frees the replaced
> > mappings
> > without putting their references. That is only valid while all of
> > them
> > use the same page size, which select_page_shift() no longer
> > guarantees.
> > 
> > Rebinding a GART BO over a 2MiB VRAM BO therefore leaves the new
> > mapping
> > owning page tables built for a different page size, and it then
> > maps
> > at a
> > size that was never referenced over that range. Since raw map does
> > not
> > allocate, nvkm_vmm_iter() can walk down to a NULL leaf and
> > dereference
> > it. The remainders of a split have the same problem:
> > op_map_prepare()
> > recomputes a page size with select_page_shift() while the remainder
> > keeps
> > the parent's page tables, so a parent that was itself downgraded
> > can
> > leave
> > a remainder that re-aligns to a larger size. This happens on the
> > unmap
> > path too.
> > 
> > Reject the bind, and make split remainders inherit the page size of
> > the
> > mapping they are split from.
> > 
> > Fixes: c488a94e7e14 ("drm/nouveau/uvmm: Allow larger pages")
> > Reported-by: Yuhao Jiang <danisjiang@gmail.com>
> > Assisted-by: LLM
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
> > Reviewed-by: Lyude Paul <lyude@redhat.com>
> > ---
> > Changes in v2:
> > - Drop patch 1, which has been merged.
> > - Use the abbreviated conditional operator for page_shift (Lyude
> > Paul).
> > - Compare against remap_args.page_shift (Lyude Paul).
> > - Use Assisted-by: LLM (Balbir Singh).
> > - Add Lyude's Reviewed-by.
> > - Link to v1:
> > https://lore.kernel.org/r/20260817-nouveau-fixes-v1-0-f518d0c735f3@outlook.com
> > ---
> >  drivers/gpu/drm/nouveau/nouveau_uvmm.c | 32
> > +++++++++++++++++++++++++++++++-
> >  1 file changed, 31 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> > b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> > index f5e4756b4de4..aa5b93808f41 100644
> > --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> > +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
> > @@ -85,6 +85,8 @@ struct uvmm_map_args {
> >  	u64 addr;
> >  	u64 range;
> >  	u8 kind;
> > +	/* Page size to give the new mapping, or 0 to derive it
> > from
> > the op. */
> > +	u8 page_shift;
> >  };
> >  
> >  static int
> > @@ -655,7 +657,7 @@ op_map_prepare(struct nouveau_uvmm *uvmm,
> >  
> >  	uvma->region = args->region;
> >  	uvma->kind = args->kind;
> > -	uvma->page_shift = select_page_shift(uvmm, op);
> > +	uvma->page_shift = args->page_shift ?:
> > select_page_shift(uvmm, op);
> >  
> >  	drm_gpuva_map(&uvmm->base, &uvma->va, op);
> >  
> > @@ -684,8 +686,20 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> > *uvmm,
> >  	struct drm_gpuva_op *op;
> >  	u64 vmm_get_start = args ? args->addr : 0;
> >  	u64 vmm_get_end = args ? args->addr + args->range : 0;
> > +	u8 map_page_shift = 0;
> >  	int ret;
> >  
> > +	/* A new mapping takes over the page tables of the
> > mappings
> > it replaces,
> > +	 * so every one of them has to be using its page size. The
> > new mapping
> > +	 * is the last op drm_gpuvm_sm_map_ops_create() emits.
> > +	 */
> > +	if (args) {
> > +		struct drm_gpuva_op *last =
> > drm_gpuva_last_op(ops);
> > +
> > +		if (last->op == DRM_GPUVA_OP_MAP)
> > +			map_page_shift = select_page_shift(uvmm,
> > &last->map);
> > +	}
> > +
> >  	drm_gpuva_for_each_op(op, ops) {
> >  		switch (op->op) {
> >  		case DRM_GPUVA_OP_MAP: {
> > @@ -713,11 +727,22 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> > *uvmm,
> >  			struct uvmm_map_args remap_args = {
> >  				.kind = uvma_from_va(va)->kind,
> >  				.region = uvma_from_va(va)-
> > >region,
> > +				/* The remainders of the split
> > keep
> > the page
> > +				 * tables of the mapping they are
> > split from,
> > +				 * so they must keep its page size
> > too.
> > +				 */
> > +				.page_shift = uvma_from_va(va)-
> > > page_shift,
> >  			};
> >  			u64 ustart = va->va.addr;
> >  			u64 urange = va->va.range;
> >  			u64 uend = ustart + urange;
> >  
> > +			if (map_page_shift &&
> > +			    remap_args.page_shift !=
> > map_page_shift)
> > {
> > +				ret = -EINVAL;
> > +				goto unwind;
> > +			}
> > +
> >  			op_unmap_prepare(r->unmap);
> >  
> >  			if (r->prev) {
> > @@ -756,6 +781,11 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm
> > *uvmm,
> >  			u64 uend = ustart + urange;
> >  			u8 page_shift = uvma_from_va(va)-
> > > page_shift;
> >  
> > +			if (map_page_shift && page_shift !=
> > map_page_shift) {
> > +				ret = -EINVAL;
> > +				goto unwind;
> > +			}
> > +
> >  			op_unmap_prepare(u);
> >  
> >  			if (!args)
> > 
> > ---
> > base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
> > change-id: 20260817-nouveau-fixes-23877845c3ab
> > 
> > Best regards,


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-09 22:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09  8:52 [PATCH v2] drm/nouveau/uvmm: reject replace across page sizes Junrui Luo via B4 Relay
2026-10-09  8:52 ` Junrui Luo
2026-10-09  9:36 ` sashiko-bot
2026-10-09 22:19 ` lyude
2026-10-09 22:23   ` lyude

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.