Skip to content

Commit 32832a4

Browse files
hdelleraxboe
authored andcommitted
io_uring: Fix io_uring mmap() by using architecture-provided get_unmapped_area()
The io_uring testcase is broken on IA-64 since commit d808459 ("io_uring: Adjust mapping wrt architecture aliasing requirements"). The reason is, that this commit introduced an own architecture independend get_unmapped_area() search algorithm which finds on IA-64 a memory region which is outside of the regular memory region used for shared userspace mappings and which can't be used on that platform due to aliasing. To avoid similar problems on IA-64 and other platforms in the future, it's better to switch back to the architecture-provided get_unmapped_area() function and adjust the needed input parameters before the call. Beside fixing the issue, the function now becomes easier to understand and maintain. This patch has been successfully tested with the io_uring testcase on physical x86-64, ppc64le, IA-64 and PA-RISC machines. On PA-RISC the LTP mmmap testcases did not report any regressions. Cc: stable@vger.kernel.org # 6.4 Signed-off-by: Helge Deller <deller@gmx.de> Reported-by: matoro <matoro_mailinglist_kernel@matoro.tk> Fixes: d808459 ("io_uring: Adjust mapping wrt architecture aliasing requirements") Link: https://lore.kernel.org/r/20230721152432.196382-2-deller@gmx.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent a9be202 commit 32832a4

File tree

2 files changed

+27
-30
lines changed

2 files changed

+27
-30
lines changed

arch/parisc/kernel/sys_parisc.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,17 @@
2626
#include <linux/compat.h>
2727

2828
/*
29-
* Construct an artificial page offset for the mapping based on the physical
29+
* Construct an artificial page offset for the mapping based on the virtual
3030
* address of the kernel file mapping variable.
31+
* If filp is zero the calculated pgoff value aliases the memory of the given
32+
* address. This is useful for io_uring where the mapping shall alias a kernel
33+
* address and a userspace adress where both the kernel and the userspace
34+
* access the same memory region.
3135
*/
32-
#define GET_FILP_PGOFF(filp) \
33-
(filp ? (((unsigned long) filp->f_mapping) >> 8) \
34-
& ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL)
36+
#define GET_FILP_PGOFF(filp, addr) \
37+
((filp ? (((unsigned long) filp->f_mapping) >> 8) \
38+
& ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL) \
39+
+ (addr >> PAGE_SHIFT))
3540

3641
static unsigned long shared_align_offset(unsigned long filp_pgoff,
3742
unsigned long pgoff)
@@ -111,7 +116,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp,
111116
do_color_align = 0;
112117
if (filp || (flags & MAP_SHARED))
113118
do_color_align = 1;
114-
filp_pgoff = GET_FILP_PGOFF(filp);
119+
filp_pgoff = GET_FILP_PGOFF(filp, addr);
115120

116121
if (flags & MAP_FIXED) {
117122
/* Even MAP_FIXED mappings must reside within TASK_SIZE */

io_uring/io_uring.c

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3437,8 +3437,6 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp,
34373437
unsigned long addr, unsigned long len,
34383438
unsigned long pgoff, unsigned long flags)
34393439
{
3440-
const unsigned long mmap_end = arch_get_mmap_end(addr, len, flags);
3441-
struct vm_unmapped_area_info info;
34423440
void *ptr;
34433441

34443442
/*
@@ -3453,32 +3451,26 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp,
34533451
if (IS_ERR(ptr))
34543452
return -ENOMEM;
34553453

3456-
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
3457-
info.length = len;
3458-
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
3459-
info.high_limit = arch_get_mmap_base(addr, current->mm->mmap_base);
3454+
/*
3455+
* Some architectures have strong cache aliasing requirements.
3456+
* For such architectures we need a coherent mapping which aliases
3457+
* kernel memory *and* userspace memory. To achieve that:
3458+
* - use a NULL file pointer to reference physical memory, and
3459+
* - use the kernel virtual address of the shared io_uring context
3460+
* (instead of the userspace-provided address, which has to be 0UL
3461+
* anyway).
3462+
* For architectures without such aliasing requirements, the
3463+
* architecture will return any suitable mapping because addr is 0.
3464+
*/
3465+
filp = NULL;
3466+
flags |= MAP_SHARED;
3467+
pgoff = 0; /* has been translated to ptr above */
34603468
#ifdef SHM_COLOUR
3461-
info.align_mask = PAGE_MASK & (SHM_COLOUR - 1UL);
3469+
addr = (uintptr_t) ptr;
34623470
#else
3463-
info.align_mask = PAGE_MASK & (SHMLBA - 1UL);
3471+
addr = 0UL;
34643472
#endif
3465-
info.align_offset = (unsigned long) ptr;
3466-
3467-
/*
3468-
* A failed mmap() very likely causes application failure,
3469-
* so fall back to the bottom-up function here. This scenario
3470-
* can happen with large stack limits and large mmap()
3471-
* allocations.
3472-
*/
3473-
addr = vm_unmapped_area(&info);
3474-
if (offset_in_page(addr)) {
3475-
info.flags = 0;
3476-
info.low_limit = TASK_UNMAPPED_BASE;
3477-
info.high_limit = mmap_end;
3478-
addr = vm_unmapped_area(&info);
3479-
}
3480-
3481-
return addr;
3473+
return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags);
34823474
}
34833475

34843476
#else /* !CONFIG_MMU */

0 commit comments

Comments
 (0)