Sven noticed that calling ioremap() and iounmap() multiple times leads to a vmap memory leak: vmap allocation for size 4198400 failed: use vmalloc=<size> to increase size It seems we missed calling remove_vm_area() for ioummap(). Signed-off-by: Helge Deller <deller@xxxxxx> Noticed-by: Sven Schnelle <svens@xxxxxxxxxxxxxx> Cc: <stable@xxxxxxxxxxxxxxx> diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 92a9b5f12f98..bcfa98aa134c 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -3,13 +3,14 @@ * arch/parisc/mm/ioremap.c * * (C) Copyright 1995 1996 Linus Torvalds - * (C) Copyright 2001-2006 Helge Deller <deller@xxxxxx> + * (C) Copyright 2001-2019 Helge Deller <deller@xxxxxx> * (C) Copyright 2005 Kyle McMartin <kyle@xxxxxxxxxxxxxxxx> */ #include <linux/vmalloc.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/io.h> #include <asm/pgalloc.h> @@ -84,7 +85,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l addr = (void __iomem *) area->addr; if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, phys_addr, pgprot)) { - vfree(addr); + remove_vm_area((void __force *)addr); + kfree(area); return NULL; } @@ -94,7 +96,24 @@ EXPORT_SYMBOL(__ioremap); void iounmap(const volatile void __iomem *addr) { - if (addr > high_memory) - return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); + struct vm_struct *p, *o; + + if (addr <= high_memory) + return; + + addr = (volatile void __iomem *) + (PAGE_MASK & (unsigned long __force)addr); + + p = find_vm_area((void __force *)addr); + if (!p) { + printk(KERN_ERR "iounmap: bad address %p\n", addr); + dump_stack(); + return; + } + + /* Finally remove it */ + o = remove_vm_area((void __force *)addr); + BUG_ON(p != o || o == NULL); + kfree(p); } EXPORT_SYMBOL(iounmap);