Re: ioremap()/iounmap() problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 19 Jan 2009 06:56:54 -0700, Russell King - ARM Linux <linux@xxxxxxxxxxxxxxxx> wrote:

There are no L2 PTE tables for section and supersection mappings, so this
is irrelevent.  Section and supersection mappings live in the L1 page
table which persists for the lifetime of the task.

As such, ioremap/iounmap are only allocating and freeing a small structure
to account for the allocation - if things are so tight that 6-7 loops
causes that allocation to fail, you're not going to be able to run any
userspace programs.

This issue is the reason I have subscribed to the mailing list. I have discovered the problem and had a quick patch to solve it. Basically when I call ioremap() and then iounmap() (loading and unloading a module) successively, I get a different virtual address each time. Eventually, it causes an invalid pointer and causes and OOPS. The solution is not optimal but it may point to the actual problem. The call to ioremap() is a macro that eventually gets to a routine __arm_ioremap_pfn which is implemented in arch/arm/mm/ioremap.c. This function calls get_vm_area() which calls __get_vm_area_node() (both within mm/vmalloc.c). Finally, there is a routine called alloc_vmap_area() which allocates and initialized a struct vmap_area. The __iounmap() function (also implemented in arch/arm/mm/ioremap.c) never takes the struct vmap_area into account. Looking through the sources, it's not easy to get a pointer to that structure from a struct vm_struct pointer. So I went back to __arm_ioremap_pfn() and found a line that is completely baffling. I #ifdef'd it out to test and it completely solved the problem. Here is a simple patch to offending
area of code:

---
 arch/arm/mm/ioremap.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 18373f7..e7d2b24 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -297,9 +297,11 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
                area->flags |= VM_ARM_SECTION_MAPPING;
                err = remap_area_supersections(addr, pfn, size, type);
+#if 0
        } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
                area->flags |= VM_ARM_SECTION_MAPPING;
                err = remap_area_sections(addr, pfn, size, type);
+#endif
        } else
 #endif
                err = remap_area_pages(addr, pfn, size, type);
--
1.6.0.6

The statement:

	} else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {

is the strange one. I'm not what is being checked here except the PMD_MASK. But without that code, everything works 100%. I'm not sure what all the remap_area_sections() code does, but the cleanup definitely does not work, as the kernel OOPS will testify. There may be a better solution, but as far as I can tell, it's not really needed. Maybe
someone else will disagree.

Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux