On Fri, Dec 1, 2023, at 13:16, Philipp Stanner wrote: > The implementation of pci_iounmap() is currently scattered over two > files, drivers/pci/iounmap.c and lib/iomap.c. Additionally, > architectures can define their own version. > > Besides one unified version being desirable in the first place, the old > version in drivers/pci/iounmap.c contained a bug and could leak memory > mappings. The bug was that #ifdef ARCH_HAS_GENERIC_IOPORT_MAP should not > have guarded iounmap(p); in addition to the preceding code. > > To have only one version, it's necessary to create a helper function, > iomem_is_ioport(), that tells pci_iounmap() whether the passed address > points to an ioport or normal memory. > > iomem_is_ioport() can be provided through three different ways: > 1. The architecture itself provides it. > 2. As a default version in include/asm-generic/io.h for those > architectures that don't use CONFIG_GENERIC_IOMAP, but also don't > provide their own version of iomem_is_ioport(). > 3. As a default version in lib/iomap.c for those architectures that > define and use CONFIG_GENERIC_IOMAP (currently, only x86 really > uses the functions in lib/iomap.c) I would count 3 as a special case of 1 here. > Create a unified version of pci_iounmap() in drivers/pci/iomap.c. > Provide the function iomem_is_ioport() in include/asm-generic/io.h and > lib/iomap.c. > > Remove the CONFIG_GENERIC_IOMAP guard around > ARCH_WANTS_GENERIC_PCI_IOUNMAP so that configs that set > CONFIG_GENERIC_PCI_IOMAP without CONFIG_GENERIC_IOMAP still get the > function. > > Fixes: 316e8d79a095 ("pci_iounmap'2: Electric Boogaloo: try to make > sense of it all") > Suggested-by: Arnd Bergmann <arnd@xxxxxxxxxx> > Signed-off-by: Philipp Stanner <pstanner@xxxxxxxxxx> Looks good overall. It would be nice to go further than this and replace all the custom pci_iounmap() variants with custom iomem_is_ioport() implementations, but that can be a follow-up along with removing the incorrect or useless 'select GENERIC_IOMAP' parts. > return; > - iounmap(p); > + } > #endif > + iounmap(addr); > } I think the bugfix should be a separate patch so we can backport it to stable kernels. > +#ifndef CONFIG_GENERIC_IOMAP > +static inline bool iomem_is_ioport(void __iomem *addr) > +{ > + unsigned long port = (unsigned long __force)addr; > + > + // TODO: do we have to take IO_SPACE_LIMIT and PCI_IOBASE into account > + // similar as in ioport_map() ? > + > + if (port > MMIO_UPPER_LIMIT) > + return false; > + > + return true; > +} This has to have the exact logic that was present in the old pci_iounmap(). For the default version that is currently in lib/pci_iomap.c, this means something along the linens of static inline bool struct iomem_is_ioport(void __iomem *p) { #ifdef CONFIG_HAS_IOPORT uintptr_t start = (uintptr_t) PCI_IOBASE; uintptr_t addr = (uintptr_t) p; if (addr >= start && addr < start + IO_SPACE_LIMIT) return true; #endif return false; } > +#else /* CONFIG_GENERIC_IOMAP. Version from lib/iomap.c will be used. > */ > +bool iomem_is_ioport(void __iomem *addr); > +#define ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT I'm not sure what this macro is for, since it appears to do the opposite of what its name suggests: rather than provide the generic version of iomem_is_ioport(), it skips that and provides a custom one to go with lib/iomap.c Arnd