From: Lizhi Hou <lizhi.hou@amd.com>
To: Max Zhen <max.zhen@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: Fri, 11 Sep 2026 08:25:30 -0700 [thread overview]
Message-ID: <eac6b351-5526-c47f-9797-6d5329c909cf@amd.com> (raw)
In-Reply-To: <e263dca3-c61d-45ae-a7da-096d7f509f26@amd.com>
Applied to drm-misc-next
On 9/10/26 15:39, Max Zhen wrote:
>
>
> 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,
>> };
>
prev parent reply other threads:[~2026-09-11 15:25 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
2026-09-11 15:25 ` Lizhi Hou [this message]
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=eac6b351-5526-c47f-9797-6d5329c909cf@amd.com \
--to=lizhi.hou@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=karol.wachowski@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mario.limonciello@amd.com \
--cc=max.zhen@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®