Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.4.13-ac8 /mm/mmap.c

Filename:/mm/mmap.c
Lines Added:191
Lines Deleted:312
Also changed in: (Previous) 2.4.13-ac7  2.4.13-ac6  2.4.13-ac5  2.4.13-ac4  2.4.13-ac3  2.4.13-ac1 
(Following) 2.4.14  2.4.18-pre3-ac1  2.4.18-pre3-ac2  2.4.18-pre7-ac1  2.4.18-pre7-ac2  2.4.18-pre7-ac3 

Location
[  2.4.13-ac8
  [  mm
     o  mmap.c

Patch

diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/mmap.c linux.ac/mm/mmap.c
--- linux.vanilla/mm/mmap.c   Thu Oct 11 13:52:14 2001
+++ linux.ac/mm/mmap.c   Wed Oct 10 01:48:38 2001
@@ -13,16 +13,11 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
-/*
- * WARNING: the debugging will use recursive algorithms so never enable this
- * unless you know what you are doing.
- */
-#undef DEBUG_MM_RB
+static inline void attempt_merge_next(struct mm_struct *mm, struct vm_area_struct *vma);
 
 /* description of effects of mapping type and prot in current implementation.
  * this is due to the limited x86 page protection hardware.  The expected
@@ -45,6 +40,7 @@
 };
 
 int sysctl_overcommit_memory;
+int max_map_count = DEFAULT_MAX_MAP_COUNT;
 
 /* Check that a process has enough memory to allocate a
  * new virtual mapping.
@@ -62,13 +58,14 @@
     */
 
    unsigned long free;
-   
+
         /* Sometimes we want to use more memory than we have. */
    if (sysctl_overcommit_memory)
        return 1;
 
-   /* The page cache contains buffer pages these days.. */
-   free = atomic_read(&page_cache_size);
+   free = atomic_read(&buffermem_pages);
+   free += atomic_read(&page_cache_size);
+   free -= atomic_read(&shmem_nrpages);
    free += nr_free_pages();
    free += nr_swap_pages;
 
@@ -174,10 +171,6 @@
    if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
       goto out;
 
-   /* Check if we have enough memory.. */
-   if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
-      goto out;
-
    /* Ok, looks good - let it rip. */
    if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
       goto out;
@@ -211,193 +204,14 @@
 #undef _trans
 }
 
-#ifdef DEBUG_MM_RB
-static int browse_rb(rb_node_t * rb_node) {
-   int i = 0;
-   if (rb_node) {
-      i++;
-      i += browse_rb(rb_node->rb_left);
-      i += browse_rb(rb_node->rb_right);
-   }
-   return i;
-}
-
-static void validate_mm(struct mm_struct * mm) {
-   int bug = 0;
-   int i = 0;
-   struct vm_area_struct * tmp = mm->mmap;
-   while (tmp) {
-      tmp = tmp->vm_next;
-      i++;
-   }
-   if (i != mm->map_count)
-      printk("map_count %d vm_next %d\n", mm->map_count, i), bug = 1;
-   i = browse_rb(mm->mm_rb.rb_node);
-   if (i != mm->map_count)
-      printk("map_count %d rb %d\n", mm->map_count, i), bug = 1;
-   if (bug)
-      BUG();
-}
-#else
-#define validate_mm(mm) do { } while (0)
-#endif
-
-static struct vm_area_struct * find_vma_prepare(struct mm_struct * mm, unsigned long addr,
-                  struct vm_area_struct ** pprev,
-                  rb_node_t *** rb_link, rb_node_t ** rb_parent)
-{
-   struct vm_area_struct * vma;
-   rb_node_t ** __rb_link, * __rb_parent, * rb_prev;
-
-   __rb_link = &mm->mm_rb.rb_node;
-   rb_prev = __rb_parent = NULL;
-   vma = NULL;
-
-   while (*__rb_link) {
-      struct vm_area_struct *vma_tmp;
-
-      __rb_parent = *__rb_link;
-      vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb);
-
-      if (vma_tmp->vm_end > addr) {
-         vma = vma_tmp;
-         if (vma_tmp->vm_start <= addr)
-            return vma;
-         __rb_link = &__rb_parent->rb_left;
-      } else {
-         rb_prev = __rb_parent;
-         __rb_link = &__rb_parent->rb_right;
-      }
-   }
-
-   *pprev = NULL;
-   if (rb_prev)
-      *pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
-   *rb_link = __rb_link;
-   *rb_parent = __rb_parent;
-   return vma;
-}
-
-static inline void __vma_link_list(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev,
-               rb_node_t * rb_parent)
-{
-   if (prev) {
-      vma->vm_next = prev->vm_next;
-      prev->vm_next = vma;
-   } else {
-      mm->mmap = vma;
-      if (rb_parent)
-         vma->vm_next = rb_entry(rb_parent, struct vm_area_struct, vm_rb);
-      else
-         vma->vm_next = NULL;
-   }
-}
-
-static inline void __vma_link_rb(struct mm_struct * mm, struct vm_area_struct * vma,
-             rb_node_t ** rb_link, rb_node_t * rb_parent)
-{
-   rb_link_node(&vma->vm_rb, rb_parent, rb_link);
-   rb_insert_color(&vma->vm_rb, &mm->mm_rb);
-}
-
-static inline void __vma_link_file(struct vm_area_struct * vma)
-{
-   struct file * file;
-
-   file = vma->vm_file;
-   if (file) {
-      struct inode * inode = file->f_dentry->d_inode;
-      struct address_space *mapping = inode->i_mapping;
-      struct vm_area_struct **head;
-
-      if (vma->vm_flags & VM_DENYWRITE)
-         atomic_dec(&inode->i_writecount);
-
-      head = &mapping->i_mmap;
-      if (vma->vm_flags & VM_SHARED)
-         head = &mapping->i_mmap_shared;
-      
-      /* insert vma into inode's share list */
-      if((vma->vm_next_share = *head) != NULL)
-         (*head)->vm_pprev_share = &vma->vm_next_share;
-      *head = vma;
-      vma->vm_pprev_share = head;
-   }
-}
-
-static void __vma_link(struct mm_struct * mm, struct vm_area_struct * vma,  struct vm_area_struct * prev,
-             rb_node_t ** rb_link, rb_node_t * rb_parent)
-{
-   __vma_link_list(mm, vma, prev, rb_parent);
-   __vma_link_rb(mm, vma, rb_link, rb_parent);
-   __vma_link_file(vma);
-}
-
-static inline void vma_link(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev,
-             rb_node_t ** rb_link, rb_node_t * rb_parent)
-{
-   lock_vma_mappings(vma);
-   spin_lock(&mm->page_table_lock);
-   __vma_link(mm, vma, prev, rb_link, rb_parent);
-   spin_unlock(&mm->page_table_lock);
-   unlock_vma_mappings(vma);
-
-   mm->map_count++;
-   validate_mm(mm);
-}
-
-static int vma_merge(struct mm_struct * mm, struct vm_area_struct * prev,
-           rb_node_t * rb_parent, unsigned long addr, unsigned long end, unsigned long vm_flags)
-{
-   spinlock_t * lock = &mm->page_table_lock;
-   if (!prev) {
-      prev = rb_entry(rb_parent, struct vm_area_struct, vm_rb);
-      goto merge_next;
-   }
-   if (prev->vm_end == addr && can_vma_merge(prev, vm_flags)) {
-      struct vm_area_struct * next;
-
-      spin_lock(lock);
-      prev->vm_end = end;
-      next = prev->vm_next;
-      if (next && prev->vm_end == next->vm_start && can_vma_merge(next, vm_flags)) {
-         prev->vm_end = next->vm_end;
-         __vma_unlink(mm, next, prev);
-         spin_unlock(lock);
-
-         mm->map_count--;
-         kmem_cache_free(vm_area_cachep, next);
-         return 1;
-      }
-      spin_unlock(lock);
-      return 1;
-   }
-
-   prev = prev->vm_next;
-   if (prev) {
- merge_next:
-      if (!can_vma_merge(prev, vm_flags))
-         return 0;
-      if (end == prev->vm_start) {
-         spin_lock(lock);
-         prev->vm_start = addr;
-         spin_unlock(lock);
-         return 1;
-      }
-   }
-
-   return 0;
-}
-
 unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
    unsigned long prot, unsigned long flags, unsigned long pgoff)
 {
    struct mm_struct * mm = current->mm;
-   struct vm_area_struct * vma, * prev;
+   struct vm_area_struct * vma;
    unsigned int vm_flags;
    int correct_wcount = 0;
    int error;
-   rb_node_t ** rb_link, * rb_parent;
 
    if (file && (!file->f_op || !file->f_op->mmap))
       return -ENODEV;
@@ -413,7 +227,7 @@
       return -EINVAL;
 
    /* Too many mappings? */
-   if (mm->map_count > MAX_MAP_COUNT)
+   if (mm->map_count > max_map_count)
       return -ENOMEM;
 
    /* Obtain the address to map to. we verify (or select) it and ensure
@@ -479,13 +293,8 @@
 
    /* Clear old maps */
    error = -ENOMEM;
-munmap_back:
-   vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
-   if (vma && vma->vm_start < addr + len) {
-      if (do_munmap(mm, addr, len))
-         return -ENOMEM;
-      goto munmap_back;
-   }
+   if (do_munmap(mm, addr, len))
+      return -ENOMEM;
 
    /* Check against address space limit. */
    if ((mm->total_vm << PAGE_SHIFT) + len
@@ -499,9 +308,14 @@
       return -ENOMEM;
 
    /* Can we just expand an old anonymous mapping? */
-   if (!file && !(vm_flags & VM_SHARED) && rb_parent)
-      if (vma_merge(mm, prev, rb_parent, addr, addr + len, vm_flags))
+   if (addr && !file && !(vm_flags & VM_SHARED)) {
+      vma = find_vma(mm, addr-1);
+      if (vma && vma->vm_end == addr && !vma->vm_file && 
+          vma->vm_flags == vm_flags) {
+         vma->vm_end = addr + len;
          goto out;
+      }
+   }
 
    /* Determine the object being mapped and call the appropriate
     * specific mapper. the address has already been validated, but
@@ -523,9 +337,6 @@
    vma->vm_raend = 0;
 
    if (file) {
-      error = -EINVAL;
-      if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
-         goto free_vma;
       if (vm_flags & VM_DENYWRITE) {
          error = deny_write_access(file);
          if (error)
@@ -550,16 +361,21 @@
     */
    addr = vma->vm_start;
 
-   vma_link(mm, vma, prev, rb_link, rb_parent);
+   insert_vm_struct(mm, vma);
    if (correct_wcount)
       atomic_inc(&file->f_dentry->d_inode->i_writecount);
 
-out:   
+out:
    mm->total_vm += len >> PAGE_SHIFT;
    if (vm_flags & VM_LOCKED) {
       mm->locked_vm += len >> PAGE_SHIFT;
       make_pages_present(addr, addr + len);
    }
+
+   /* Can we merge this anonymous mapping with the one following it? */
+   if (!file && !(vm_flags & VM_SHARED))
+      attempt_merge_next(mm, vma);
+
    return addr;
 
 unmap_and_free_vma:
@@ -567,7 +383,6 @@
       atomic_inc(&file->f_dentry->d_inode->i_writecount);
    vma->vm_file = NULL;
    fput(file);
-
    /* Undo any partial mapping done by a device driver. */
    zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
 free_vma:
@@ -600,8 +415,11 @@
       if (TASK_SIZE - len >= addr &&
           (!vma || addr + len <= vma->vm_start))
          return addr;
+      if (addr > TASK_UNMAPPED_BASE)
+         addr = 0;
    }
-   addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
+   if (!addr)
+      addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
 
    for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
       /* At this point:  (!vma || addr < vma->vm_end). */
@@ -632,6 +450,10 @@
    return arch_get_unmapped_area(file, addr, len, pgoff, flags);
 }
 
+#define vm_avl_empty   (struct vm_area_struct *) NULL
+
+#include "mmap_avl.c"
+
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
 {
@@ -642,23 +464,26 @@
       /* (Cache hit rate is typically around 35%.) */
       vma = mm->mmap_cache;
       if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
-         rb_node_t * rb_node;
-
-         rb_node = mm->mm_rb.rb_node;
-         vma = NULL;
-
-         while (rb_node) {
-            struct vm_area_struct * vma_tmp;
-
-            vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
-
-            if (vma_tmp->vm_end > addr) {
-               vma = vma_tmp;
-               if (vma_tmp->vm_start <= addr)
+         if (!mm->mmap_avl) {
+            /* Go through the linear list. */
+            vma = mm->mmap;
+            while (vma && vma->vm_end <= addr)
+               vma = vma->vm_next;
+         } else {
+            /* Then go through the AVL tree quickly. */
+            struct vm_area_struct * tree = mm->mmap_avl;
+            vma = NULL;
+            for (;;) {
+               if (tree == vm_avl_empty)
                   break;
-               rb_node = rb_node->rb_left;
-            } else
-               rb_node = rb_node->rb_right;
+               if (tree->vm_end > addr) {
+                  vma = tree;
+                  if (tree->vm_start <= addr)
+                     break;
+                  tree = tree->vm_avl_left;
+               } else
+                  tree = tree->vm_avl_right;
+            }
          }
          if (vma)
             mm->mmap_cache = vma;
@@ -672,42 +497,47 @@
                   struct vm_area_struct **pprev)
 {
    if (mm) {
-      /* Go through the RB tree quickly. */
-      struct vm_area_struct * vma;
-      rb_node_t * rb_node, * rb_last_right, * rb_prev;
-      
-      rb_node = mm->mm_rb.rb_node;
-      rb_last_right = rb_prev = NULL;
-      vma = NULL;
-
-      while (rb_node) {
-         struct vm_area_struct * vma_tmp;
-
-         vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
-
-         if (vma_tmp->vm_end > addr) {
-            vma = vma_tmp;
-            rb_prev = rb_last_right;
-            if (vma_tmp->vm_start <= addr)
+      if (!mm->mmap_avl) {
+         /* Go through the linear list. */
+         struct vm_area_struct * prev = NULL;
+         struct vm_area_struct * vma = mm->mmap;
+         while (vma && vma->vm_end <= addr) {
+            prev = vma;
+            vma = vma->vm_next;
+         }
+         *pprev = prev;
+         return vma;
+      } else {
+         /* Go through the AVL tree quickly. */
+         struct vm_area_struct * vma = NULL;
+         struct vm_area_struct * last_turn_right = NULL;
+         struct vm_area_struct * prev = NULL;
+         struct vm_area_struct * tree = mm->mmap_avl;
+         for (;;) {
+            if (tree == vm_avl_empty)
                break;
-            rb_node = rb_node->rb_left;
-         } else {
-            rb_last_right = rb_node;
-            rb_node = rb_node->rb_right;
+            if (tree->vm_end > addr) {
+               vma = tree;
+               prev = last_turn_right;
+               if (tree->vm_start <= addr)
+                  break;
+               tree = tree->vm_avl_left;
+            } else {
+               last_turn_right = tree;
+               tree = tree->vm_avl_right;
+            }
          }
-      }
-      if (vma) {
-         if (vma->vm_rb.rb_left) {
-            rb_prev = vma->vm_rb.rb_left;
-            while (rb_prev->rb_right)
-               rb_prev = rb_prev->rb_right;
+         if (vma) {
+            if (vma->vm_avl_left != vm_avl_empty) {
+               prev = vma->vm_avl_left;
+               while (prev->vm_avl_right != vm_avl_empty)
+                  prev = prev->vm_avl_right;
+            }
+            if ((prev ? prev->vm_next : mm->mmap) != vma)
+               printk("find_vma_prev: tree inconsistent with list\n");
+            *pprev = prev;
+            return vma;
          }
-         *pprev = NULL;
-         if (rb_prev)
-            *pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
-         if ((rb_prev ? (*pprev)->vm_next : mm->mmap) != vma)
-            BUG();
-         return vma;
       }
    }
    *pprev = NULL;
@@ -782,16 +612,11 @@
 
    /* Work out to one of the ends. */
    if (end == area->vm_end) {
-      /*
-       * here area isn't visible to the semaphore-less readers
-       * so we don't need to update it under the spinlock.
-       */
       area->vm_end = addr;
       lock_vma_mappings(area);
       spin_lock(&mm->page_table_lock);
    } else if (addr == area->vm_start) {
       area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;
-      /* same locking considerations of the above case */
       area->vm_start = end;
       lock_vma_mappings(area);
       spin_lock(&mm->page_table_lock);
@@ -882,6 +707,8 @@
     * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.
     */
    start_index = pgd_index(first);
+   if (start_index < FIRST_USER_PGD_NR)
+      start_index = FIRST_USER_PGD_NR;
    end_index = pgd_index(last);
    if (end_index > start_index) {
       clear_page_tables(mm, start_index, end_index - start_index);
@@ -919,7 +746,7 @@
 
    /* If we'll make "hole", check the vm areas limit */
    if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len)
-       && mm->map_count >= MAX_MAP_COUNT)
+       && mm->map_count >= max_map_count)
       return -ENOMEM;
 
    /*
@@ -937,7 +764,8 @@
       *npp = mpnt->vm_next;
       mpnt->vm_next = free;
       free = mpnt;
-      rb_erase(&mpnt->vm_rb, &mm->mm_rb);
+      if (mm->mmap_avl)
+         avl_remove(mpnt, &mm->mmap_avl);
    }
    mm->mmap_cache = NULL;   /* Kill the cache. */
    spin_unlock(&mm->page_table_lock);
@@ -976,7 +804,6 @@
       if (file)
          atomic_inc(&file->f_dentry->d_inode->i_writecount);
    }
-   validate_mm(mm);
 
    /* Release the extra vma struct if it wasn't used */
    if (extra)
@@ -1006,9 +833,8 @@
 unsigned long do_brk(unsigned long addr, unsigned long len)
 {
    struct mm_struct * mm = current->mm;
-   struct vm_area_struct * vma, * prev;
-   unsigned long flags;
-   rb_node_t ** rb_link, * rb_parent;
+   struct vm_area_struct * vma;
+   unsigned long flags, retval;
 
    len = PAGE_ALIGN(len);
    if (!len)
@@ -1027,20 +853,16 @@
    /*
     * Clear old maps.  this also does some error checking for us
     */
- munmap_back:
-   vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
-   if (vma && vma->vm_start < addr + len) {
-      if (do_munmap(mm, addr, len))
-         return -ENOMEM;
-      goto munmap_back;
-   }
+   retval = do_munmap(mm, addr, len);
+   if (retval != 0)
+      return retval;
 
    /* Check against address space limits *after* clearing old maps... */
    if ((mm->total_vm << PAGE_SHIFT) + len
        > current->rlim[RLIMIT_AS].rlim_cur)
       return -ENOMEM;
 
-   if (mm->map_count > MAX_MAP_COUNT)
+   if (mm->map_count > max_map_count)
       return -ENOMEM;
 
    if (!vm_enough_memory(len >> PAGE_SHIFT))
@@ -1050,10 +872,16 @@
             MAP_FIXED|MAP_PRIVATE) | mm->def_flags;
 
    flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
-
+   
    /* Can we just expand an old anonymous mapping? */
-   if (rb_parent && vma_merge(mm, prev, rb_parent, addr, addr + len, flags))
-      goto out;
+   if (addr) {
+      struct vm_area_struct * vma = find_vma(mm, addr-1);
+      if (vma && vma->vm_end == addr && !vma->vm_file && 
+          vma->vm_flags == flags) {
+         vma->vm_end = addr + len;
+         goto out;
+      }
+   }   
 
    /*
     * create a vma struct for an anonymous mapping
@@ -1072,7 +900,7 @@
    vma->vm_file = NULL;
    vma->vm_private_data = NULL;
 
-   vma_link(mm, vma, prev, rb_link, rb_parent);
+   insert_vm_struct(mm, vma);
 
 out:
    mm->total_vm += len >> PAGE_SHIFT;
@@ -1083,20 +911,14 @@
    return addr;
 }
 
-/* Build the RB tree corresponding to the VMA list. */
-void build_mmap_rb(struct mm_struct * mm)
+/* Build the AVL tree corresponding to the VMA list. */
+void build_mmap_avl(struct mm_struct * mm)
 {
    struct vm_area_struct * vma;
-   rb_node_t ** rb_link, * rb_parent;
 
-   mm->mm_rb = RB_ROOT;
-   rb_link = &mm->mm_rb.rb_node;
-   rb_parent = NULL;
-   for (vma = mm->mmap; vma; vma = vma->vm_next) {
-      __vma_link_rb(mm, vma, rb_link, rb_parent);
-      rb_parent = &vma->vm_rb;
-      rb_link = &rb_parent->rb_right;
-   }
+   mm->mmap_avl = NULL;
+   for (vma = mm->mmap; vma; vma = vma->vm_next)
+      avl_insert(vma, &mm->mmap_avl);
 }
 
 /* Release all mmaps. */
@@ -1107,8 +929,7 @@
    release_segments(mm);
    spin_lock(&mm->page_table_lock);
    mpnt = mm->mmap;
-   mm->mmap = mm->mmap_cache = NULL;
-   mm->mm_rb = RB_ROOT;
+   mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
    mm->rss = 0;
    spin_unlock(&mm->page_table_lock);
    mm->total_vm = 0;
@@ -1137,7 +958,7 @@
 
    /* This is just debugging */
    if (mm->map_count)
-      BUG();
+      printk("exit_mmap: map count is %d\n", mm->map_count);
 
    clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
 }
@@ -1146,27 +967,85 @@
  * and into the inode's i_mmap ring.  If vm_file is non-NULL
  * then the i_shared_lock must be held here.
  */
-void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
+void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
 {
-   struct vm_area_struct * __vma, * prev;
-   rb_node_t ** rb_link, * rb_parent;
+   struct vm_area_struct **pprev;
+   struct file * file;
+
+   if (!mm->mmap_avl) {
+      pprev = &mm->mmap;
+      while (*pprev && (*pprev)->vm_start <= vmp->vm_start)
+         pprev = &(*pprev)->vm_next;
+   } else {
+      struct vm_area_struct *prev, *next;
+      avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
+      pprev = (prev ? &prev->vm_next : &mm->mmap);
+      if (*pprev != next)
+         printk("insert_vm_struct: tree inconsistent with list\n");
+   }
+   vmp->vm_next = *pprev;
+   *pprev = vmp;
 
-   __vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent);
-   if (__vma && __vma->vm_start < vma->vm_end)
-      BUG();
-   __vma_link(mm, vma, prev, rb_link, rb_parent);
    mm->map_count++;
-   validate_mm(mm);
+   if (mm->map_count >= AVL_MIN_MAP_COUNT && !mm->mmap_avl)
+      build_mmap_avl(mm);
+
+   file = vmp->vm_file;
+   if (file) {
+      struct inode * inode = file->f_dentry->d_inode;
+      struct address_space *mapping = inode->i_mapping;
+      struct vm_area_struct **head;
+
+      if (vmp->vm_flags & VM_DENYWRITE)
+         atomic_dec(&inode->i_writecount);
+
+      head = &mapping->i_mmap;
+      if (vmp->vm_flags & VM_SHARED)
+         head = &mapping->i_mmap_shared;
+      
+      /* insert vmp into inode's share list */
+      if((vmp->vm_next_share = *head) != NULL)
+         (*head)->vm_pprev_share = &vmp->vm_next_share;
+      *head = vmp;
+      vmp->vm_pprev_share = head;
+   }
+}
+
+void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
+{
+   lock_vma_mappings(vmp);
+   spin_lock(¤t->mm->page_table_lock);
+   __insert_vm_struct(mm, vmp);
+   spin_unlock(¤t->mm->page_table_lock);
+   unlock_vma_mappings(vmp);
 }
 
-void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
+static inline void attempt_merge_next(struct mm_struct *mm, struct vm_area_struct *vma)
 {
-   struct vm_area_struct * __vma, * prev;
-   rb_node_t ** rb_link, * rb_parent;
+   struct vm_area_struct *next = vma->vm_next;
+   if (next && vma->vm_end == next->vm_start && !next->vm_file && 
+       vma->vm_flags == next->vm_flags) {
+      spin_lock(&mm->page_table_lock);
+      vma->vm_next = next->vm_next;
+      if (mm->mmap_avl)
+         avl_remove(next, &mm->mmap_avl);
+      vma->vm_end = next->vm_end;
+      mm->mmap_cache = vma;   /* Kill the cache. */
+      mm->map_count--;
+      spin_unlock(&mm->page_table_lock);
+
+      kmem_cache_free(vm_area_cachep, next);
+   }
+}
+
+void merge_anon_vmas(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+   struct vm_area_struct *vma;
+   if (start)
+      start--;
 
-   __vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent);
-   if (__vma && __vma->vm_start < vma->vm_end)
-      BUG();
-   vma_link(mm, vma, prev, rb_link, rb_parent);
-   validate_mm(mm);
+   for (vma = find_vma(mm, start); vma && vma->vm_start <= end;
+        vma = vma->vm_next)
+      if (!vma->vm_file && !(vma->vm_flags & VM_SHARED))
+         attempt_merge_next(mm, vma);
 }


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.