Well, we don't want to add infrastructure to 2.4, so this basically goes into massive layering violations and open-codes the entire fault path in make_pages_present(). --- page_remove_rmap-wli/mm/memory.c | 168 ++++++++++++++++++++++++++++++++++++++- 1 files changed, 166 insertions(+), 2 deletions(-) diff -puN mm/memory.c~make_pages_present mm/memory.c --- page_remove_rmap/mm/memory.c~make_pages_present 2004-06-17 00:17:44.000000000 -0700 +++ page_remove_rmap-wli/mm/memory.c 2004-06-17 02:00:40.000000000 -0700 @@ -1893,10 +1893,151 @@ out: return pmd_offset(pgd, address); } +#define NR_GANG_FAULT 64 +#define NR_GANG_FAULT_BITS ((NR_GANG_FAULT+BITS_PER_LONG-1)/BITS_PER_LONG) + +static inline int gang_fault(struct vm_area_struct *vma, unsigned long vaddr, + struct address_space *mapping, unsigned long pgoff, + struct page **pages, int n) +{ + int i, err, ret = 0; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte, val; + DECLARE_BITMAP(mask, NR_GANG_FAULT) + = { [0 ... NR_GANG_FAULT_BITS-1] = 0 }; + + lock_pagecache_readonly(); + for (i = 0; i < n; ++i) { + struct page *page, **hash = page_hash(mapping, pgoff + i); + for (page = *hash; page; page = page->next_hash) { + if (page->mapping == mapping && + page->offset == pgoff +i) + break; + } + if (page) + page_cache_get(page); + pages[i] = page; + } + unlock_pagecache_readonly(); + for (i = 0; i < n; ++i) { + if (pages[i]) + continue; + if ((pages[i] = page_cache_alloc(mapping))) + __set_bit(i, mask); + else { + for (--i; i >= 0; --i) + page_cache_release(pages[i]); + return -ENOMEM; + } + } + lock_pagecache(); + for (i = 0; i < n; ++i) { + struct page *page, **hash; + + if (!test_bit(i, mask)) + continue; + hash = page_hash(mapping, pgoff + i); + for (page = *hash; page; page = page->next_hash) { + if (page->mapping == mapping && + page->offset == pgoff +i) + break; + } + if (!page) { + page = pages[i]; + ClearPageUptodate(page); + ClearPageError(page); + ClearPageDirty(page); + ClearPageReferenced(page); + ClearPageArch1(page); + ClearPageChecked(page); + LockPage(page); + page_cache_get(page); + page->index = pgoff + i; + page->mapping = mapping; + mapping->nrpages++; + list_add(&page->list, &mapping->clean_pages); + page->next_hash = *hash; + page->pprev_hash = hash; + if (*hash) + (*hash)->pprev_hash = &page->next_hash; + *hash = page; + if (page->buffers) + PAGE_BUG(page); + atomic_inc(&page_cache_size); + } else { + __free_page(pages[i]); + page_cache_get(page); + pages[i] = page; + } + } + unlock_pagecache(); + for (i = 0; i < n; ++i) { + if (!test_bit(i, mask)) + continue; + if ((err = mapping->a_ops->readpage(file, pages[i]))) { + if (!ret) + ret = err; + SetPageFresh(pages[i]); + } + } + if (ret) + goto out; + pgd = pgd_offset(vma->vm_mm, vaddr); + spin_lock(&vma->vm_mm->page_table_lock); + pmd = pmd_alloc(vma->vm_mm, pgd, vaddr); + if (!(pte = pte_alloc_map(vma->vm_mm, pmd, vaddr))) { + ret = -ENOMEM; + goto out; + } + for (i = 0; i < n; ++i) { + if (pte_none(*pte)) { + val = mk_pte(pages[i], vma->vm_page_prot); + vm_set_pte(pte, mk_pte(pages[i], vma->vm_page_prot)); + update_mmu_cache(vma, vaddr + PAGE_SIZE*i, val); + } else if (pte_present(*pte)) + page_cache_release(pages[i]); + else + BUG(); + if (i == n - 1) + break; + else if ((vaddr + PAGE_SIZE*(i + 1)) & ~PMD_MASK) + ++pte; + else { + pte_unmap(pte); + if ((vaddr + PAGE_SIZE*(i + 1)) & ~PGDIR_MASK) + ++pmd; + else { + ++pgd; + if (!(pmd = pmd_alloc(vma->vm_mm, pgd, vaddr + PAGE_SIZE*(i+1)))) + goto out_nopte; + } + if (!(pte = pte_alloc_map(vma->vm_mm, pmd, vaddr + PAGE_SIZE*(i+1)))) + goto out_nopte; + } + } + if (pte) + pte_unmap(pte); + spin_unlock(&vma->vm_mm->page_table_lock); + return ret; +out: + for (i = 0; i < n; ++i) + page_cache_release(pages[i]); + return ret; +out_nopte: + for (; i < n; ++i) + page_cache_release(pages[i]); + spin_unlock(&vma->vm_mm->page_table_lock); + return ret; +} + int make_pages_present(unsigned long addr, unsigned long end) { - int ret, len, write; - struct vm_area_struct * vma; + int ret; + unsigned long len, write, pgoff, idx, vaddr, n; + struct vm_area_struct *vma; + struct address_space *mapping; + struct page **pages; vma = find_vma(current->mm, addr); write = (vma->vm_flags & VM_WRITE) != 0; @@ -1905,6 +2046,29 @@ int make_pages_present(unsigned long add if (end > vma->vm_end) BUG(); len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE; + if (!vma->vm_file || !vma->vm_file->f_dentry || + !vma->vm_file->f_dentry->d_inode || + !vma->vm_file->f_dentry->d_inode->i_mapping || + !vma->vm_file->f_dentry->d_inode->i_mapping->host) + goto out_get_user; + if (!(vma->vm_flags & VM_SHARED)) + goto out_get_user; + if (!(pages = kmalloc(NR_GANG_FAULT*sizeof(struct page *), GFP_KERNEL))) + goto out_get_user; + mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + pgoff = vma->vm_pgoff + (addr - vma->vm_start)/PAGE_SIZE; + idx = pgoff; + vaddr = addr; + while (vaddr < end) { + n = min_t(int, (end - vaddr)/PAGE_SIZE, NR_GANG_FAULT); + if ((ret = gang_fault(vma, vaddr, mapping, pgoff, pages, n))) + break; + idx += NR_GANG_FAULT; + vaddr += NR_GANG_FAULT*PAGE_SIZE; + } + kfree(pages); + return ret; +out_get_user: ret = get_user_pages(current, current->mm, addr, len, write, 0, NULL, NULL); return ret == len ? 0 : -1; _