Merge branch 'akpm' (patches from Andrew)
[linux-2.6-microblaze.git] / mm / vmalloc.c
index 5dcb65d..d77830f 100644 (file)
 #include "internal.h"
 #include "pgalloc-track.h"
 
+#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+static unsigned int __ro_after_init ioremap_max_page_shift = BITS_PER_LONG - 1;
+
+static int __init set_nohugeiomap(char *str)
+{
+       ioremap_max_page_shift = PAGE_SHIFT;
+       return 0;
+}
+early_param("nohugeiomap", set_nohugeiomap);
+#else /* CONFIG_HAVE_ARCH_HUGE_VMAP */
+static const unsigned int ioremap_max_page_shift = PAGE_SHIFT;
+#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
+
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC
 static bool __ro_after_init vmap_allow_huge = true;
 
@@ -298,15 +311,14 @@ static int vmap_range_noflush(unsigned long addr, unsigned long end,
        return err;
 }
 
-int vmap_range(unsigned long addr, unsigned long end,
-                       phys_addr_t phys_addr, pgprot_t prot,
-                       unsigned int max_page_shift)
+int ioremap_page_range(unsigned long addr, unsigned long end,
+               phys_addr_t phys_addr, pgprot_t prot)
 {
        int err;
 
-       err = vmap_range_noflush(addr, end, phys_addr, prot, max_page_shift);
+       err = vmap_range_noflush(addr, end, phys_addr, pgprot_nx(prot),
+                                ioremap_max_page_shift);
        flush_cache_vmap(addr, end);
-
        return err;
 }
 
@@ -787,6 +799,28 @@ unsigned long vmalloc_nr_pages(void)
        return atomic_long_read(&nr_vmalloc_pages);
 }
 
+static struct vmap_area *find_vmap_area_exceed_addr(unsigned long addr)
+{
+       struct vmap_area *va = NULL;
+       struct rb_node *n = vmap_area_root.rb_node;
+
+       while (n) {
+               struct vmap_area *tmp;
+
+               tmp = rb_entry(n, struct vmap_area, rb_node);
+               if (tmp->va_end > addr) {
+                       va = tmp;
+                       if (tmp->va_start <= addr)
+                               break;
+
+                       n = n->rb_left;
+               } else
+                       n = n->rb_right;
+       }
+
+       return va;
+}
+
 static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
        struct rb_node *n = vmap_area_root.rb_node;
@@ -3287,9 +3321,14 @@ long vread(char *buf, char *addr, unsigned long count)
                count = -(unsigned long) addr;
 
        spin_lock(&vmap_area_lock);
-       va = __find_vmap_area((unsigned long)addr);
+       va = find_vmap_area_exceed_addr((unsigned long)addr);
        if (!va)
                goto finished;
+
+       /* no intersects with alive vmap_area */
+       if ((unsigned long)addr + count <= va->va_start)
+               goto finished;
+
        list_for_each_entry_from(va, &vmap_area_list, list) {
                if (!count)
                        break;