diff options
Diffstat (limited to 'arch/powerpc/platforms/book3s')
-rw-r--r-- | arch/powerpc/platforms/book3s/vas-api.c | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c index f381b177ea06..49b15e7a8265 100644 --- a/arch/powerpc/platforms/book3s/vas-api.c +++ b/arch/powerpc/platforms/book3s/vas-api.c @@ -425,23 +425,22 @@ static vm_fault_t vas_mmap_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - mutex_lock(&txwin->task_ref.mmap_mutex); /* * The window may be inactive due to lost credit (Ex: core * removal with DLPAR). If the window is active again when * the credit is available, map the new paste address at the * window virtual address. */ - if (txwin->status == VAS_WIN_ACTIVE) { - paste_addr = cp_inst->coproc->vops->paste_addr(txwin); - if (paste_addr) { - fault = vmf_insert_pfn(vma, vma->vm_start, - (paste_addr >> PAGE_SHIFT)); - mutex_unlock(&txwin->task_ref.mmap_mutex); - return fault; + scoped_guard(mutex, &txwin->task_ref.mmap_mutex) { + if (txwin->status == VAS_WIN_ACTIVE) { + paste_addr = cp_inst->coproc->vops->paste_addr(txwin); + if (paste_addr) { + fault = vmf_insert_pfn(vma, vma->vm_start, + (paste_addr >> PAGE_SHIFT)); + return fault; + } } } - mutex_unlock(&txwin->task_ref.mmap_mutex); /* * Received this fault due to closing the actual window. @@ -464,7 +463,42 @@ static vm_fault_t vas_mmap_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } +/* + * During mmap() paste address, mapping VMA is saved in VAS window + * struct which is used to unmap during migration if the window is + * still open. But the user space can remove this mapping with + * munmap() before closing the window and the VMA address will + * be invalid. Set VAS window VMA to NULL in this function which + * is called before VMA free. + */ +static void vas_mmap_close(struct vm_area_struct *vma) +{ + struct file *fp = vma->vm_file; + struct coproc_instance *cp_inst = fp->private_data; + struct vas_window *txwin; + + /* Should not happen */ + if (!cp_inst || !cp_inst->txwin) { + pr_err("No attached VAS window for the paste address mmap\n"); + return; + } + + txwin = cp_inst->txwin; + /* + * task_ref.vma is set in coproc_mmap() during mmap paste + * address. So it has to be the same VMA that is getting freed. + */ + if (WARN_ON(txwin->task_ref.vma != vma)) { + pr_err("Invalid paste address mmaping\n"); + return; + } + + scoped_guard(mutex, &txwin->task_ref.mmap_mutex) + txwin->task_ref.vma = NULL; +} + static const struct vm_operations_struct vas_vm_ops = { + .close = vas_mmap_close, .fault = vas_mmap_fault, }; @@ -485,6 +519,15 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) return -EINVAL; } + /* + * Map complete page to the paste address. So the user + * space should pass 0ULL to the offset parameter. + */ + if (vma->vm_pgoff) { + pr_debug("Page offset unsupported to map paste address\n"); + return -EINVAL; + } + /* Ensure instance has an open send window */ if (!txwin) { pr_err("No send window open?\n"); @@ -507,18 +550,16 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) * close/open event and allows mmap() only when the window is * active. */ - mutex_lock(&txwin->task_ref.mmap_mutex); + guard(mutex)(&txwin->task_ref.mmap_mutex); if (txwin->status != VAS_WIN_ACTIVE) { pr_err("Window is not active\n"); - rc = -EACCES; - goto out; + return -EACCES; } paste_addr = cp_inst->coproc->vops->paste_addr(txwin); if (!paste_addr) { pr_err("Window paste address failed\n"); - rc = -EINVAL; - goto out; + return -EINVAL; } pfn = paste_addr >> PAGE_SHIFT; @@ -538,8 +579,6 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) txwin->task_ref.vma = vma; vma->vm_ops = &vas_vm_ops; -out: - mutex_unlock(&txwin->task_ref.mmap_mutex); return rc; } |