This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / um / kernel / physmem.c
index 3253bc0..258e158 100644 (file)
@@ -1,14 +1,13 @@
-/*
+/* 
  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
 #include "linux/mm.h"
-#include "linux/rbtree.h"
+#include "linux/ghash.h"
 #include "linux/slab.h"
 #include "linux/vmalloc.h"
 #include "linux/bootmem.h"
-#include "linux/module.h"
 #include "asm/types.h"
 #include "asm/pgtable.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "init.h"
 
+#if 0
+static pgd_t physmem_pgd[PTRS_PER_PGD];
+
+static struct phys_desc *lookup_mapping(void *addr)
+{
+       pgd = &physmem_pgd[pgd_index(addr)];
+       if(pgd_none(pgd))
+               return(NULL);
+
+       pmd = pmd_offset(pgd, addr);
+       if(pmd_none(pmd))
+               return(NULL);
+
+       pte = pte_offset_kernel(pmd, addr);
+       return((struct phys_desc *) pte_val(pte));
+}
+
+static struct add_mapping(void *addr, struct phys_desc *new)
+{
+}
+#endif
+
+#define PHYS_HASHSIZE (8192)
+
+struct phys_desc;
+
+DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
+
 struct phys_desc {
-       struct rb_node rb;
+       struct virtmem_ptrs virt_ptrs;
        int fd;
        __u64 offset;
        void *virt;
@@ -29,48 +56,21 @@ struct phys_desc {
        struct list_head list;
 };
 
-static struct rb_root phys_mappings = RB_ROOT;
+struct virtmem_table virtmem_hash;
 
-static struct rb_node **find_rb(void *virt)
+static int virt_cmp(void *virt1, void *virt2)
 {
-       struct rb_node **n = &phys_mappings.rb_node;
-       struct phys_desc *d;
-
-       while(*n != NULL){
-               d = rb_entry(*n, struct phys_desc, rb);
-               if(d->virt == virt)
-                       return(n);
-
-               if(d->virt > virt)
-                       n = &(*n)->rb_left;
-               else
-                       n = &(*n)->rb_right;
-       }
-
-       return(n);
+       return(virt1 != virt2);
 }
 
-static struct phys_desc *find_phys_mapping(void *virt)
+static int virt_hash(void *virt)
 {
-       struct rb_node **n = find_rb(virt);
-
-       if(*n == NULL)
-               return(NULL);
-
-       return(rb_entry(*n, struct phys_desc, rb));
+       unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
+       return(addr % PHYS_HASHSIZE);
 }
 
-static void insert_phys_mapping(struct phys_desc *desc)
-{
-       struct rb_node **n = find_rb(desc->virt);
-
-       if(*n != NULL)
-               panic("Physical remapping for %p already present",
-                     desc->virt);
-
-       rb_link_node(&desc->rb, (*n)->rb_parent, n);
-       rb_insert_color(&desc->rb, &phys_mappings);
-}
+DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, 
+        virt_hash);
 
 LIST_HEAD(descriptor_mappings);
 
@@ -106,7 +106,7 @@ static struct desc_mapping *descriptor_mapping(int fd)
        if(desc == NULL)
                return(NULL);
 
-       *desc = ((struct desc_mapping)
+       *desc = ((struct desc_mapping) 
                { .fd =         fd,
                  .list =       LIST_HEAD_INIT(desc->list),
                  .pages =      LIST_HEAD_INIT(desc->pages) });
@@ -122,27 +122,32 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
        unsigned long phys;
        int err;
 
+       phys = __pa(virt);
+       desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+       if(desc != NULL){
+               if((virt != desc->virt) || (fd != desc->fd) || 
+                  (offset != desc->offset))
+                       panic("Address 0x%p is already substituted\n", virt);
+               return(0);
+       }
+
        fd_maps = descriptor_mapping(fd);
        if(fd_maps == NULL)
                return(-ENOMEM);
 
-       phys = __pa(virt);
-       desc = find_phys_mapping(virt);
-       if(desc != NULL)
-               panic("Address 0x%p is already substituted\n", virt);
-
        err = -ENOMEM;
        desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
        if(desc == NULL)
                goto out;
 
-       *desc = ((struct phys_desc)
-               { .fd =                 fd,
+       *desc = ((struct phys_desc) 
+               { .virt_ptrs =  { NULL, NULL },
+                 .fd =         fd,
                  .offset =             offset,
                  .virt =               virt,
                  .phys =               __pa(virt),
                  .list =               LIST_HEAD_INIT(desc->list) });
-       insert_phys_mapping(desc);
+       insert_virtmem_hash(&virtmem_hash, desc);
 
        list_add(&desc->list, &fd_maps->pages);
 
@@ -151,7 +156,7 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
        if(!err)
                goto out;
 
-       rb_erase(&desc->rb, &phys_mappings);
+       remove_virtmem_hash(&virtmem_hash, desc);
        kfree(desc);
  out:
        return(err);
@@ -164,7 +169,7 @@ static void remove_mapping(struct phys_desc *desc)
        void *virt = desc->virt;
        int err;
 
-       rb_erase(&desc->rb, &phys_mappings);
+       remove_virtmem_hash(&virtmem_hash, desc);
        list_del(&desc->list);
        kfree(desc);
 
@@ -179,7 +184,7 @@ int physmem_remove_mapping(void *virt)
        struct phys_desc *desc;
 
        virt = (void *) ((unsigned long) virt & PAGE_MASK);
-       desc = find_phys_mapping(virt);
+       desc = find_virtmem_hash(&virtmem_hash, virt);
        if(desc == NULL)
                return(0);
 
@@ -200,6 +205,9 @@ void physmem_forget_descriptor(int fd)
        if(desc == NULL)
                return;
 
+       if(!list_empty(&desc->pages))
+               printk("Still have mapped pages on fd %d\n", fd);
+
        list_for_each_safe(ele, next, &desc->pages){
                page = list_entry(ele, struct phys_desc, list);
                offset = page->offset;
@@ -221,10 +229,6 @@ void physmem_forget_descriptor(int fd)
        kfree(desc);
 }
 
-EXPORT_SYMBOL(physmem_forget_descriptor);
-EXPORT_SYMBOL(physmem_remove_mapping);
-EXPORT_SYMBOL(physmem_subst_mapping);
-
 void arch_free_page(struct page *page, int order)
 {
        void *virt;
@@ -236,11 +240,16 @@ void arch_free_page(struct page *page, int order)
        }
 }
 
-int is_remapped(void *virt)
+int is_remapped(const void *virt, int fd, __u64 offset)
 {
-       struct phys_desc *desc = find_phys_mapping(virt);
+       struct phys_desc *desc;
 
-       return(desc != NULL);
+       desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+       if(desc == NULL)
+               return(0);
+       if(offset != desc->offset)
+               printk("offset mismatch\n");
+       return(find_virtmem_hash(&virtmem_hash, (void *) virt) != NULL);
 }
 
 /* Changed during early boot */
@@ -279,7 +288,7 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
 
        if(kmalloc_ok){
                map = kmalloc(total_len, GFP_KERNEL);
-               if(map == NULL)
+               if(map == NULL) 
                        map = vmalloc(total_len);
        }
        else map = alloc_bootmem_low_pages(total_len);
@@ -328,12 +337,12 @@ static unsigned long kmem_top = 0;
 
 unsigned long get_kmem_end(void)
 {
-       if(kmem_top == 0)
+       if(kmem_top == 0) 
                kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
        return(kmem_top);
 }
 
-void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
+void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
                int r, int w, int x)
 {
        __u64 offset;
@@ -341,14 +350,9 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
 
        fd = phys_mapping(phys, &offset);
        err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
-       if(err) {
-               if(err == -ENOMEM)
-                       printk("try increasing the host's "
-                              "/proc/sys/vm/max_map_count to <physical "
-                              "memory size>/4096\n");
+       if(err)
                panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
                      "err = %d\n", virt, fd, offset, len, r, w, x, err);
-       }
 }
 
 #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
@@ -364,7 +368,7 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
        physmem_fd = create_mem_file(len + highmem);
 
        offset = uml_reserved - uml_physmem;
-       err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
+       err = os_map_memory((void *) uml_reserved, physmem_fd, offset, 
                            len - offset, 1, 1, 0);
        if(err < 0){
                os_print_error(err, "Mapping memory");
@@ -378,7 +382,8 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
 
 int phys_mapping(unsigned long phys, __u64 *offset_out)
 {
-       struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
+       struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, 
+                                                  __va(phys & PAGE_MASK));
        int fd = -1;
 
        if(desc != NULL){
@@ -391,9 +396,9 @@ int phys_mapping(unsigned long phys, __u64 *offset_out)
        }
        else if(phys < __pa(end_iomem)){
                struct iomem_region *region = iomem_regions;
-
+       
                while(region != NULL){
-                       if((phys >= region->phys) &&
+                       if((phys >= region->phys) && 
                           (phys < region->phys + region->size)){
                                fd = region->fd;
                                *offset_out = phys - region->phys;
@@ -429,7 +434,7 @@ __uml_setup("mem=", uml_mem_setup,
 unsigned long find_iomem(char *driver, unsigned long *len_out)
 {
        struct iomem_region *region = iomem_regions;
-
+       
        while(region != NULL){
                if(!strcmp(region->driver, driver)){
                        *len_out = region->size;
@@ -447,7 +452,7 @@ int setup_iomem(void)
        int err;
 
        while(region != NULL){
-               err = os_map_memory((void *) iomem_start, region->fd, 0,
+               err = os_map_memory((void *) iomem_start, region->fd, 0, 
                                    region->size, 1, 1, 0);
                if(err)
                        printk("Mapping iomem region for driver '%s' failed, "