mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
accel/amdxdna: Support read-only user-pointer BO mappings
Update the amdxdna user-pointer (ubuf) BO path to support creating buffer objects from read-only user mappings. Detect read-only VMAs by checking VMA permissions across all user virtual address ranges associated with the BO. When all entries are read-only, pin user pages without FOLL_WRITE and export the resulting dmabuf as read-only (O_RDONLY). This allows userptr BOs backed by read-only mappings to be safely imported and used without requiring write access, which was previously rejected due to unconditional FOLL_WRITE usage. Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Signed-off-by: Max Zhen <max.zhen@amd.com> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com> Link: https://patch.msgid.link/20260331172635.3275296-1-lizhi.hou@amd.com
This commit is contained in:
parent
43c9a66ea1
commit
f649e63d4a
|
|
@ -125,6 +125,26 @@ static const struct dma_buf_ops amdxdna_ubuf_dmabuf_ops = {
|
|||
.vunmap = amdxdna_ubuf_vunmap,
|
||||
};
|
||||
|
||||
static int readonly_va_entry(struct amdxdna_drm_va_entry *va_ent)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
int ret;
|
||||
|
||||
mmap_read_lock(mm);
|
||||
|
||||
vma = find_vma(mm, va_ent->vaddr);
|
||||
if (!vma ||
|
||||
vma->vm_start > va_ent->vaddr ||
|
||||
vma->vm_end - va_ent->vaddr < va_ent->len)
|
||||
ret = -ENOENT;
|
||||
else
|
||||
ret = vma->vm_flags & VM_WRITE ? 0 : 1;
|
||||
|
||||
mmap_read_unlock(mm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
||||
u32 num_entries, void __user *va_entries)
|
||||
{
|
||||
|
|
@ -134,6 +154,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
|||
struct amdxdna_ubuf_priv *ubuf;
|
||||
u32 npages, start = 0;
|
||||
struct dma_buf *dbuf;
|
||||
bool readonly = true;
|
||||
int i, ret;
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
|
||||
|
|
@ -172,6 +193,10 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
|||
ret = -EINVAL;
|
||||
goto free_ent;
|
||||
}
|
||||
|
||||
/* Pin pages as writable as long as not all entries are read-only. */
|
||||
if (readonly && readonly_va_entry(&va_ent[i]) != 1)
|
||||
readonly = false;
|
||||
}
|
||||
|
||||
ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
|
||||
|
|
@ -194,7 +219,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
|||
npages = va_ent[i].len >> PAGE_SHIFT;
|
||||
|
||||
ret = pin_user_pages_fast(va_ent[i].vaddr, npages,
|
||||
FOLL_WRITE | FOLL_LONGTERM,
|
||||
(readonly ? 0 : FOLL_WRITE) | FOLL_LONGTERM,
|
||||
&ubuf->pages[start]);
|
||||
if (ret >= 0) {
|
||||
start += ret;
|
||||
|
|
@ -211,7 +236,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
|||
|
||||
exp_info.ops = &amdxdna_ubuf_dmabuf_ops;
|
||||
exp_info.priv = ubuf;
|
||||
exp_info.flags = O_RDWR | O_CLOEXEC;
|
||||
exp_info.flags = (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC;
|
||||
|
||||
dbuf = dma_buf_export(&exp_info);
|
||||
if (IS_ERR(dbuf)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user