Re: io_uring failure on parisc with VIPT caches

Helge Deller
2023-02-15T21:40:37Z

Here is an updated patch which
- should support other platforms which needs aliasing
- allows users to pass in an address in mmap(). This is checked
and returned -EINVAL if it does not fullfill the aliasing.
(this part is untested up to now!)

Jens, I think you need to add the "_FILE_OFFSET_BITS=64" define
when compiling your testsuite, e.g. for lfs-openat.t and lfs-openat-write.t

Helge

diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 862e05e6691d..d89fe16878dc 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -72,6 +72,7 @@
#include <linux/io_uring.h>
#include <linux/audit.h>
#include <linux/security.h>
+#include <asm/shmparam.h>

#define CREATE_TRACE_POINTS
#include <trace/events/io_uring.h>
@@ -3059,6 +3060,63 @@ static __cold int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
return remap_pfn_range(vma, vma->vm_start, pfn, sz, vma->vm_page_prot);
}

+static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp,
+ unsigned long addr0, unsigned long len,
+ unsigned long pgoff, unsigned long flags)
+{
+ const unsigned long mmap_end = arch_get_mmap_end(addr, len, flags);
+ struct vm_unmapped_area_info info;
+ unsigned long addr;
+ void *ptr;
+
+ ptr = io_uring_validate_mmap_request(filp, pgoff, len);
+ if (IS_ERR(ptr))
+ return -ENOMEM;
+
+ info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+ info.length = len;
+ info.low_limit = max(PAGE_SIZE, mmap_min_addr);
+ info.high_limit = arch_get_mmap_base(addr, current->mm->mmap_base);
+#ifdef SHM_COLOUR
+ info.align_mask = PAGE_MASK & (SHM_COLOUR - 1UL);;
+#else
+ info.align_mask = PAGE_MASK & (SHMLBA - 1UL);
+#endif
+ info.align_offset = (unsigned long) ptr;
+
+ if (addr0) {
+ /* check page alignment and shm aliasing */
+ if ((addr0 & (PAGE_SIZE - 1UL) ||
+ ((addr0 & info.align_mask) !=
+ (info.align_offset & info.align_mask))))
+ return -EINVAL;
+ info.low_limit = max(addr0, info.low_limit);
+ info.high_limit = min(addr0 + len, info.high_limit);
+ }
+
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ addr = vm_unmapped_area(&info);
+
+ /* if address was given, check against found address */
+ if (addr0 && addr != addr0)
+ return -EINVAL;
+
+ if (offset_in_page(addr)) {
+ VM_BUG_ON(addr != -ENOMEM);
+ info.flags = 0;
+ info.low_limit = TASK_UNMAPPED_BASE;
+ info.high_limit = mmap_end;
+ addr = vm_unmapped_area(&info);
+ }
+
+ return addr;
+}
+
#else /* !CONFIG_MMU */

static int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
@@ -3273,6 +3331,8 @@ static const struct file_operations io_uring_fops = {
#ifndef CONFIG_MMU
.get_unmapped_area = io_uring_nommu_get_unmapped_area,
.mmap_capabilities = io_uring_nommu_mmap_capabilities,
+#else
+ .get_unmapped_area = io_uring_mmu_get_unmapped_area,
#endif
.poll = io_uring_poll,
#ifdef CONFIG_PROC_FS