diff -ur linux.orig/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h --- linux.orig/include/asm-i386/kmap_types.h Wed May 2 11:48:14 2001 +++ linux/include/asm-i386/kmap_types.h Wed May 2 13:32:28 2001 @@ -6,6 +6,8 @@ KM_BOUNCE_WRITE, KM_SKB_DATA, KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, KM_TYPE_NR }; diff -ur linux.orig/include/linux/highmem.h linux/include/linux/highmem.h --- linux.orig/include/linux/highmem.h Mon Mar 26 18:48:11 2001 +++ linux/include/linux/highmem.h Wed May 2 13:45:38 2001 @@ -45,8 +45,9 @@ /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { - clear_user_page(kmap(page), vaddr); - kunmap(page); + void *addr = kmap_atomic(page, KM_USER0); + clear_user_page(addr, vaddr); + kunmap_atomic(addr, KM_USER0); } static inline void clear_highpage(struct page *page) @@ -85,11 +86,11 @@ { char *vfrom, *vto; - vfrom = kmap(from); - vto = kmap(to); + vfrom = kmap_atomic(from, KM_USER0); + vto = kmap_atomic(to, KM_USER1); copy_user_page(vto, vfrom, vaddr); - kunmap(from); - kunmap(to); + kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vto, KM_USER1); } static inline void copy_highpage(struct page *to, struct page *from) diff -ur linux.orig/mm/filemap.c linux/mm/filemap.c --- linux.orig/mm/filemap.c Wed May 2 11:48:15 2001 +++ linux/mm/filemap.c Wed May 2 12:31:21 2001 @@ -1799,7 +1799,12 @@ if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) { struct page *page = pte_page(pte); flush_tlb_page(vma, address); + /* yuck. we have to drop the spinlock as set_page_dirty + * can end up blocking. -ben + */ + spin_unlock(&vma->vm_mm->page_table_lock); set_page_dirty(page); + spin_lock(&vma->vm_mm->page_table_lock); } return 0; } diff -ur linux.orig/mm/memory.c linux/mm/memory.c --- linux.orig/mm/memory.c Wed May 2 11:48:14 2001 +++ linux/mm/memory.c Wed May 2 13:42:20 2001 @@ -238,8 +238,10 @@ cont_copy_pte_range: set_pte(dst_pte, pte); cont_copy_pte_range_noset: address += PAGE_SIZE; - if (address >= end) - goto out_unlock; + if (address >= end) { + spin_unlock(&src->page_table_lock); + goto out; + } src_pte++; dst_pte++; } while ((unsigned long)src_pte & PTE_TABLE_MASK); @@ -249,8 +251,6 @@ dst_pmd++; } while ((unsigned long)src_pmd & PMD_TABLE_MASK); } -out_unlock: - spin_unlock(&src->page_table_lock); out: spin_unlock(&dst->page_table_lock); return 0; @@ -453,7 +453,7 @@ if (err) return err; - down_write(&mm->mmap_sem); + down_read(&mm->mmap_sem); err = -EFAULT; iobuf->locked = 0; @@ -524,12 +524,12 @@ } spin_unlock(&mm->page_table_lock); - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); dprintk ("map_user_kiobuf: end OK\n"); return 0; out_unlock: - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); unmap_kiobuf(iobuf); dprintk ("map_user_kiobuf: end %d\n", err); return err; @@ -869,7 +869,6 @@ static inline void break_cow(struct vm_area_struct * vma, struct page * old_page, struct page * new_page, unsigned long address, pte_t *page_table) { - copy_cow_page(old_page,new_page,address); flush_page_to_ram(new_page); flush_cache_page(vma, address); establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); @@ -921,7 +920,7 @@ if (!VALID_PAGE(old_page)) goto bad_wp_page; - if (old_page == ZERO_PAGE(address)) + if (old_page == ZERO_PAGE(address) || PageReserved(old_page)) goto copy; /* @@ -963,6 +962,13 @@ set_pte(page_table, pte); spin_unlock(&mm->page_table_lock); new_page = alloc_page(GFP_HIGHUSER); + + /* Speculatively copy the page while not holding + * the page table lock. Make threads happy. -ben + */ + if (new_page) + copy_cow_page(old_page, new_page, address); + spin_lock(&mm->page_table_lock); if (!new_page) return -1; @@ -1203,6 +1209,8 @@ /* Allocate our own private page. */ spin_unlock(&mm->page_table_lock); page = alloc_page(GFP_HIGHUSER); + if (page) + clear_user_highpage(page, addr); spin_lock(&mm->page_table_lock); if (!page) return -1; @@ -1211,7 +1219,6 @@ return 1; } mm->rss++; - clear_user_highpage(page, addr); flush_page_to_ram(page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); } diff -ur linux.orig/mm/vmscan.c linux/mm/vmscan.c --- linux.orig/mm/vmscan.c Wed May 2 11:48:16 2001 +++ linux/mm/vmscan.c Wed May 2 13:50:29 2001 @@ -66,6 +66,7 @@ if (PageSwapCache(page)) { entry.val = page->index; if (pte_dirty(pte)) + /* FIXME: THIS MAY BLOCK on non-ext2 like fses */ set_page_dirty(page); set_swap_pte: swap_duplicate(entry); @@ -103,6 +104,7 @@ * to its own backing store. */ if (page->mapping) { + /* FIXME: THIS MAY BLOCK on non-ext2 like fses */ set_page_dirty(page); goto drop_pte; } @@ -119,6 +121,7 @@ /* Add it to the swap cache and mark it dirty */ add_to_swap_cache(page, entry); + /* FIXME: THIS MAY BLOCK on non-ext2 like fses */ set_page_dirty(page); goto set_swap_pte;