From: Max Zhen <max.zhen@amd.com>
To: Lizhi Hou <lizhi.hou@amd.com>, <ogabbay@kernel.org>,
<quic_jhugo@quicinc.com>, <mario.limonciello@amd.com>,
<karol.wachowski@linux.intel.com>,
<dri-devel@lists.freedesktop.org>
Cc: <linux-kernel@vger.kernel.org>, <sonal.santan@amd.com>
Subject: Re: [PATCH V3] accel/amdxdna: Fix unsafe use of handle_mm_fault()
Date: Thu, 10 Sep 2026 15:39:47 -0700 [thread overview]
Message-ID: <e263dca3-c61d-45ae-a7da-096d7f509f26@amd.com> (raw)
In-Reply-To: <20260910211338.1102315-1-lizhi.hou@amd.com>
On 9/10/2026 Thu 14:13, Lizhi Hou wrote:
> handle_mm_fault() must not be called from the mmap callback because
> the VMA has not yet been linked. The handle_mm_fault() API contract
> assumes that the VMA is already linked.
>
> Remove the handle_mm_fault() call from the mmap callback. For imported
> BOs, mark the mapping as invalid and rely on the first command submission
> to fault in the pages.
>
> For shmem BOs, set the VM_MIXEDMAP flag and use vm_insert_pages().
> Implement amdxdna_gem_mixed_vm_ops to handle the page faults.
>
> Fixes: e486147c912f ("accel/amdxdna: Add BO import and export")
> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Reviewed-by: Max Zhen <max.zhen@amd.com>
> ---
> v2 & v3:
> Fix sashiko comment.
>
> drivers/accel/amdxdna/amdxdna_gem.c | 151 ++++++++++++++++++++++------
> 1 file changed, 118 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
> index 0d165b66c1fc..a12a762b3a6b 100644
> --- a/drivers/accel/amdxdna/amdxdna_gem.c
> +++ b/drivers/accel/amdxdna/amdxdna_gem.c
> @@ -14,6 +14,7 @@
> #include <linux/dma-direct.h>
> #include <linux/iosys-map.h>
> #include <linux/pagemap.h>
> +#include <linux/swap.h>
> #include <linux/vmalloc.h>
>
> #include "amdxdna_cbuf.h"
> @@ -490,16 +491,16 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
> {
> struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
> unsigned long num_pages = vma_pages(vma);
> - unsigned long offset = 0;
> int ret;
>
> - if (!is_import_bo(abo)) {
> - ret = drm_gem_shmem_mmap(&abo->base, vma);
> - if (ret) {
> - XDNA_ERR(xdna, "Failed shmem mmap %d", ret);
> - return ret;
> - }
> - } else {
> + /*
> + * Until today there is not any use case to mmap with non-zero
> + * offset. Put an explicit check here.
> + */
> + if (vma->vm_pgoff - drm_vma_node_start(&to_gobj(abo)->vma_node))
> + return -EINVAL;
> +
> + if (is_import_bo(abo)) {
> vma->vm_private_data = NULL;
> vma->vm_ops = NULL;
> ret = dma_buf_mmap(abo->dma_buf, vma, 0);
> @@ -508,23 +509,28 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
> return ret;
> }
>
> + amdxdna_mark_mapp_invalid(abo, vma);
> +
> /* Drop the reference drm_gem_mmap_obj() acquired.*/
> drm_gem_object_put(to_gobj(abo));
> + return 0;
> }
>
> - do {
> - vm_fault_t fault_ret;
> -
> - fault_ret = handle_mm_fault(vma, vma->vm_start + offset,
> - FAULT_FLAG_WRITE, NULL);
> - if (fault_ret & VM_FAULT_ERROR) {
> - XDNA_ERR(xdna, "Fault in page failed");
> - amdxdna_mark_mapp_invalid(abo, vma);
> - break;
> - }
> + ret = drm_gem_shmem_mmap(&abo->base, vma);
> + if (ret) {
> + XDNA_ERR(xdna, "Failed shmem mmap %d", ret);
> + return ret;
> + }
>
> - offset += PAGE_SIZE;
> - } while (--num_pages);
> + vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
> + ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages, &num_pages);
> + if (ret) {
> + XDNA_ERR(xdna, "Failed to insert pages %d", ret);
> + dma_resv_lock(to_gobj(abo)->resv, NULL);
> + drm_gem_shmem_put_pages_locked(&abo->base);
> + dma_resv_unlock(to_gobj(abo)->resv);
> + return ret;
> + }
>
> return 0;
> }
> @@ -536,6 +542,10 @@ static int amdxdna_gem_obj_mmap(struct drm_gem_object *gobj,
> struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
> int ret;
>
> + XDNA_DBG(xdna, "BO map_offset 0x%llx type %d userptr 0x%lx size 0x%lx",
> + drm_vma_node_offset_addr(&gobj->vma_node), abo->type,
> + vma->vm_start, gobj->size);
> +
> ret = amdxdna_hmm_register(abo, vma);
> if (ret)
> return ret;
> @@ -546,9 +556,6 @@ static int amdxdna_gem_obj_mmap(struct drm_gem_object *gobj,
> goto hmm_unreg;
> }
>
> - XDNA_DBG(xdna, "BO map_offset 0x%llx type %d userptr 0x%lx size 0x%lx",
> - drm_vma_node_offset_addr(&gobj->vma_node), abo->type,
> - vma->vm_start, gobj->size);
> return 0;
>
> hmm_unreg:
> @@ -556,14 +563,99 @@ static int amdxdna_gem_obj_mmap(struct drm_gem_object *gobj,
> return ret;
> }
>
> +/*
> + * VM operations for amdxdna shmem VMAs that use VM_MIXEDMAP.
> + *
> + * drm_gem_shmem_vm_ops cannot be used on VM_MIXEDMAP VMAs because its fault
> + * handler calls vmf_insert_pfn() → vmf_insert_pfn_prot() which contains:
> + * BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn))
> + * All amdxdna shmem pages are ordinary struct pages so pfn_valid() is always
> + * true, making the combination fatal.
> + *
> + * These ops use vmf_insert_page() (struct-page based) instead, which is the
> + * correct API for VM_MIXEDMAP VMAs backed by real struct pages. The open and
> + * close handlers replicate drm_gem_shmem_vm_open/close using only exported
> + * symbols.
> + */
> +static vm_fault_t amdxdna_gem_mixedmap_fault(struct vm_fault *vmf)
> +{
> + struct vm_area_struct *vma = vmf->vma;
> + struct drm_gem_object *gobj = vma->vm_private_data;
> + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gobj);
> + loff_t num_pages = gobj->size >> PAGE_SHIFT;
> + vm_fault_t ret = VM_FAULT_SIGBUS;
> + pgoff_t page_offset;
> + struct page *page;
> +
> + /*
> + * Partial free of vma is unexpected. Otherwise, the wrong page
> + * will be faulted in and the user application may crash itself.
> + */
> + page_offset = vmf->pgoff - vma->vm_pgoff;
> +
> + dma_resv_lock(gobj->resv, NULL);
> +
> + if (!shmem->pages || shmem->madv < 0 || page_offset >= num_pages)
> + goto out;
> +
> + page = shmem->pages[page_offset];
> + if (WARN_ON_ONCE(!page))
> + goto out;
> +
> + /*
> + * Use vmf_insert_page() (struct-page path) not vmf_insert_pfn()
> + * (PFN path) because this VMA carries VM_MIXEDMAP.
> + */
> + ret = vmf_insert_page(vma, vmf->address, page);
> + if (ret == VM_FAULT_NOPAGE)
> + folio_mark_accessed(page_folio(page));
> +
> +out:
> + dma_resv_unlock(gobj->resv);
> + return ret;
> +}
> +
> +static void amdxdna_gem_mixedmap_vm_open(struct vm_area_struct *vma)
> +{
> + struct drm_gem_object *gobj = vma->vm_private_data;
> + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gobj);
> +
> + /*
> + * Bump pages_use_count so the page array stays alive for the new
> + * mapping copy created by fork(). Mirrors drm_gem_shmem_vm_open().
> + */
> + dma_resv_lock(gobj->resv, NULL);
> + drm_WARN_ON_ONCE(gobj->dev, !refcount_inc_not_zero(&shmem->pages_use_count));
> + dma_resv_unlock(gobj->resv);
> +
> + drm_gem_vm_open(vma);
> +}
> +
> +static void amdxdna_gem_mixedmap_vm_close(struct vm_area_struct *vma)
> +{
> + struct drm_gem_object *gobj = vma->vm_private_data;
> + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gobj);
> +
> + dma_resv_lock(gobj->resv, NULL);
> + drm_gem_shmem_put_pages_locked(shmem);
> + dma_resv_unlock(gobj->resv);
> +
> + drm_gem_vm_close(vma);
> +}
> +
> +static const struct vm_operations_struct amdxdna_gem_mixedmap_vm_ops = {
> + .fault = amdxdna_gem_mixedmap_fault,
> + .open = amdxdna_gem_mixedmap_vm_open,
> + .close = amdxdna_gem_mixedmap_vm_close,
> +};
> +
> static int amdxdna_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
> {
> struct drm_gem_object *gobj = dma_buf->priv;
> struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
> - unsigned long num_pages = vma_pages(vma);
> int ret;
>
> - vma->vm_ops = &drm_gem_shmem_vm_ops;
> + vma->vm_ops = &amdxdna_gem_mixedmap_vm_ops;
> vma->vm_private_data = gobj;
>
> drm_gem_object_get(gobj);
> @@ -573,16 +665,9 @@ static int amdxdna_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struc
>
> /* The buffer is based on memory pages. Fix the flag. */
> vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
> - ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages,
> - &num_pages);
> - if (ret)
> - goto close_vma;
>
> return 0;
>
> -close_vma:
> - vma->vm_ops->close(vma);
> - return ret;
> put_obj:
> drm_gem_object_put(gobj);
> return ret;
> @@ -878,7 +963,7 @@ static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = {
> .vmap = amdxdna_gem_obj_vmap,
> .vunmap = amdxdna_gem_obj_vunmap,
> .mmap = amdxdna_gem_obj_mmap,
> - .vm_ops = &drm_gem_shmem_vm_ops,
> + .vm_ops = &amdxdna_gem_mixedmap_vm_ops,
> .export = amdxdna_gem_prime_export,
> };
>
next prev parent reply other threads:[~2026-09-10 22:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-10 21:13 Lizhi Hou
2026-09-10 22:39 ` Max Zhen [this message]
2026-09-11 15:25 ` Lizhi Hou
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=e263dca3-c61d-45ae-a7da-096d7f509f26@amd.com \
--to=max.zhen@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=karol.wachowski@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lizhi.hou@amd.com \
--cc=mario.limonciello@amd.com \
--cc=ogabbay@kernel.org \
--cc=quic_jhugo@quicinc.com \
--cc=sonal.santan@amd.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®