[SPARC64]: Don't clobber alt-global %g4 on window fixups.
[safe/jmp/linux-2.6] / mm / memory.c
index e65f8fc..85e80a5 100644 (file)
@@ -82,6 +82,16 @@ EXPORT_SYMBOL(num_physpages);
 EXPORT_SYMBOL(high_memory);
 EXPORT_SYMBOL(vmalloc_earlyreserve);
 
+int randomize_va_space __read_mostly = 1;
+
+static int __init disable_randmaps(char *s)
+{
+       randomize_va_space = 0;
+       return 0;
+}
+__setup("norandmaps", disable_randmaps);
+
+
 /*
  * If a p?d_bad entry is found while walking page tables, report
  * the error, before resetting entry to p?d_none.  Usually (but
@@ -349,6 +359,11 @@ void print_bad_pte(struct vm_area_struct *vma, pte_t pte, unsigned long vaddr)
        dump_stack();
 }
 
+static inline int is_cow_mapping(unsigned int flags)
+{
+       return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
+}
+
 /*
  * This function gets the "struct page" associated with a pte.
  *
@@ -377,7 +392,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
                unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
                if (pfn == vma->vm_pgoff + off)
                        return NULL;
-               if (vma->vm_flags & VM_SHARED)
+               if (!is_cow_mapping(vma->vm_flags))
                        return NULL;
        }
 
@@ -439,7 +454,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
         * If it's a COW mapping, write protect it both
         * in the parent and the child
         */
-       if ((vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE) {
+       if (is_cow_mapping(vm_flags)) {
                ptep_set_wrprotect(src_mm, addr, src_pte);
                pte = *src_pte;
        }
@@ -569,7 +584,7 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
         * readonly mappings. The tradeoff is that copy_page_range is more
         * efficient than faulting.
         */
-       if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_PFNMAP))) {
+       if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_PFNMAP|VM_INSERTPAGE))) {
                if (!vma->anon_vma)
                        return 0;
        }
@@ -608,11 +623,12 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                        (*zap_work)--;
                        continue;
                }
+
+               (*zap_work) -= PAGE_SIZE;
+
                if (pte_present(ptent)) {
                        struct page *page;
 
-                       (*zap_work) -= PAGE_SIZE;
-
                        page = vm_normal_page(vma, addr, ptent);
                        if (unlikely(details) && page) {
                                /*
@@ -1004,7 +1020,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                        continue;
                }
 
-               if (!vma || (vma->vm_flags & VM_IO)
+               if (!vma || (vma->vm_flags & (VM_IO | VM_PFNMAP))
                                || !(vm_flags & vma->vm_flags))
                        return i ? : -EFAULT;
 
@@ -1223,55 +1239,12 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *
                return -EFAULT;
        if (!page_count(page))
                return -EINVAL;
+       vma->vm_flags |= VM_INSERTPAGE;
        return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
 }
 EXPORT_SYMBOL(vm_insert_page);
 
 /*
- * Somebody does a pfn remapping that doesn't actually work as a vma.
- *
- * Do it as individual pages instead, and warn about it. It's bad form,
- * and very inefficient.
- */
-static int incomplete_pfn_remap(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end,
-               unsigned long pfn, pgprot_t prot)
-{
-       static int warn = 10;
-       struct page *page;
-       int retval;
-
-       if (!(vma->vm_flags & VM_INCOMPLETE)) {
-               if (warn) {
-                       warn--;
-                       printk("%s does an incomplete pfn remapping", current->comm);
-                       dump_stack();
-               }
-       }
-       vma->vm_flags |= VM_INCOMPLETE | VM_IO | VM_RESERVED;
-
-       if (start < vma->vm_start || end > vma->vm_end)
-               return -EINVAL;
-
-       if (!pfn_valid(pfn))
-               return -EINVAL;
-
-       page = pfn_to_page(pfn);
-       if (!PageReserved(page))
-               return -EINVAL;
-
-       retval = 0;
-       while (start < end) {
-               retval = insert_page(vma->vm_mm, start, page, prot);
-               if (retval < 0)
-                       break;
-               start += PAGE_SIZE;
-               page++;
-       }
-       return retval;
-}
-
-/*
  * maps a range of physical memory into the requested pages. the old
  * mappings are removed. any references to nonexistent pages results
  * in null mappings (currently treated as "copy-on-access")
@@ -1363,9 +1336,9 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
         * behaviour that some programs depend on. We mark the "original"
         * un-COW'ed pages by matching them up with "vma->vm_pgoff".
         */
-       if (!(vma->vm_flags & VM_SHARED)) {
+       if (is_cow_mapping(vma->vm_flags)) {
                if (addr != vma->vm_start || end != vma->vm_end)
-                       return incomplete_pfn_remap(vma, addr, end, pfn, prot);
+                       return -EINVAL;
                vma->vm_pgoff = pfn;
        }
 
@@ -1536,7 +1509,7 @@ gotten:
                update_mmu_cache(vma, address, entry);
                lazy_mmu_prot_update(entry);
                lru_cache_add_active(new_page);
-               page_add_anon_rmap(new_page, vma, address);
+               page_add_new_anon_rmap(new_page, vma, address);
 
                /* Free the old page.. */
                new_page = old_page;
@@ -1808,9 +1781,32 @@ out_big:
 out_busy:
        return -ETXTBSY;
 }
-
 EXPORT_SYMBOL(vmtruncate);
 
+int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end)
+{
+       struct address_space *mapping = inode->i_mapping;
+
+       /*
+        * If the underlying filesystem is not going to provide
+        * a way to truncate a range of blocks (punch a hole) -
+        * we should return failure right now.
+        */
+       if (!inode->i_op || !inode->i_op->truncate_range)
+               return -ENOSYS;
+
+       mutex_lock(&inode->i_mutex);
+       down_write(&inode->i_alloc_sem);
+       unmap_mapping_range(mapping, offset, (end - offset), 1);
+       truncate_inode_pages_range(mapping, offset, end);
+       inode->i_op->truncate_range(inode, offset, end);
+       up_write(&inode->i_alloc_sem);
+       mutex_unlock(&inode->i_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(vmtruncate_range);
+
 /* 
  * Primitive swap readahead code. We simply read an aligned block of
  * (1 << page_cluster) entries in the swap area. This method is chosen
@@ -1886,6 +1882,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out;
 
        entry = pte_to_swp_entry(orig_pte);
+again:
        page = lookup_swap_cache(entry);
        if (!page) {
                swapin_readahead(entry, address, vma);
@@ -1909,6 +1906,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
 
        mark_page_accessed(page);
        lock_page(page);
+       if (!PageSwapCache(page)) {
+               /* Page migration has occured */
+               unlock_page(page);
+               page_cache_release(page);
+               goto again;
+       }
 
        /*
         * Back out if somebody else already faulted in this pte.
@@ -1992,8 +1995,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        goto release;
                inc_mm_counter(mm, anon_rss);
                lru_cache_add_active(page);
-               SetPageReferenced(page);
-               page_add_anon_rmap(page, vma, address);
+               page_add_new_anon_rmap(page, vma, address);
        } else {
                /* Map the ZERO_PAGE - vm_page_prot is readonly */
                page = ZERO_PAGE(address);
@@ -2124,7 +2126,7 @@ retry:
                if (anon) {
                        inc_mm_counter(mm, anon_rss);
                        lru_cache_add_active(new_page);
-                       page_add_anon_rmap(new_page, vma, address);
+                       page_add_new_anon_rmap(new_page, vma, address);
                } else {
                        inc_mm_counter(mm, file_rss);
                        page_add_file_rmap(new_page);
@@ -2283,6 +2285,8 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
 }
 
+EXPORT_SYMBOL_GPL(__handle_mm_fault);
+
 #ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.