Binary files 2.4.0-test10-pre3/ID and rawio-1/ID differ diff -urN 2.4.0-test10-pre3/drivers/char/raw.c rawio-1/drivers/char/raw.c --- 2.4.0-test10-pre3/drivers/char/raw.c Thu Oct 12 03:04:42 2000 +++ rawio-1/drivers/char/raw.c Sun Oct 15 17:00:07 2000 @@ -310,11 +310,6 @@ err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize); if (err) break; -#if 0 - err = lock_kiovec(1, &iobuf, 1); - if (err) - break; -#endif for (i=0; i < blocks; i++) b[i] = blocknr++; diff -urN 2.4.0-test10-pre3/fs/buffer.c rawio-1/fs/buffer.c --- 2.4.0-test10-pre3/fs/buffer.c Sat Oct 14 19:00:17 2000 +++ rawio-1/fs/buffer.c Sun Oct 15 16:32:22 2000 @@ -1923,6 +1923,7 @@ } spin_unlock(&unused_list_lock); + wake_up(&buffer_wait); return iosize; } @@ -2061,6 +2062,7 @@ __put_unused_buffer_head(bh[i]); } spin_unlock(&unused_list_lock); + wake_up(&buffer_wait); goto finished; } diff -urN 2.4.0-test10-pre3/include/linux/mm.h rawio-1/include/linux/mm.h --- 2.4.0-test10-pre3/include/linux/mm.h Sun Oct 15 17:49:26 2000 +++ rawio-1/include/linux/mm.h Sun Oct 15 17:51:11 2000 @@ -408,7 +408,7 @@ extern void mem_init(void); extern void show_mem(void); extern void si_meminfo(struct sysinfo * val); -extern void swapin_readahead(swp_entry_t); +extern void swapin_readaround(swp_entry_t); /* mmap.c */ extern void merge_segments(struct mm_struct *, unsigned long, unsigned long); diff -urN 2.4.0-test10-pre3/include/linux/pagemap.h rawio-1/include/linux/pagemap.h --- 2.4.0-test10-pre3/include/linux/pagemap.h Sun Oct 15 17:38:48 2000 +++ rawio-1/include/linux/pagemap.h Sun Oct 15 17:49:28 2000 @@ -77,6 +77,11 @@ #define find_lock_page(mapping, index) \ __find_lock_page(mapping, index, page_hash(mapping, index)) +extern int __check_page(struct address_space * mapping, unsigned long index, + struct page **hash); +#define check_page(mapping, index) \ + __check_page(mapping, index, page_hash(mapping, index)) + extern void __add_page_to_hash_queue(struct page * page, struct page **p); extern void add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long index); diff -urN 2.4.0-test10-pre3/ipc/shm.c rawio-1/ipc/shm.c --- 2.4.0-test10-pre3/ipc/shm.c Thu Oct 12 03:04:50 2000 +++ rawio-1/ipc/shm.c Sun Oct 15 17:51:15 2000 @@ -1414,7 +1414,7 @@ page = lookup_swap_cache(entry); if (!page) { lock_kernel(); - swapin_readahead(entry); + swapin_readaround(entry); page = read_swap_cache(entry); unlock_kernel(); if (!page) diff -urN 2.4.0-test10-pre3/mm/filemap.c rawio-1/mm/filemap.c --- 2.4.0-test10-pre3/mm/filemap.c Sat Oct 14 19:00:18 2000 +++ rawio-1/mm/filemap.c Sun Oct 15 17:47:41 2000 @@ -254,10 +254,23 @@ * up kswapd. */ age_page_up(page); + + /* Oh, I feel bad with this horror. */ if (inactive_shortage() > inactive_target / 2 && free_shortage()) wakeup_kswapd(0); not_found: return page; +} + +int __check_page(struct address_space * mapping, unsigned long index, struct page ** hash) +{ + struct page * page; + + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, index, *hash); + spin_unlock(&pagecache_lock); + + return page != NULL; } /* diff -urN 2.4.0-test10-pre3/mm/memory.c rawio-1/mm/memory.c --- 2.4.0-test10-pre3/mm/memory.c Thu Oct 12 03:04:50 2000 +++ rawio-1/mm/memory.c Sun Oct 15 17:51:20 2000 @@ -385,7 +385,7 @@ /* * Do a quick page-table lookup for a single page. */ -static struct page * follow_page(unsigned long address) +static struct page * follow_page(unsigned long address, int write) { pgd_t *pgd; pmd_t *pmd; @@ -395,7 +395,8 @@ if (pmd) { pte_t * pte = pte_offset(pmd, address); if (pte && pte_present(*pte)) - return pte_page(*pte); + if (!write || pte_write(*pte)) + return pte_page(*pte); } return NULL; @@ -427,8 +428,12 @@ struct mm_struct * mm; struct vm_area_struct * vma = 0; struct page * map; + int doublepage = 0; + int repeat = 0; int i; - int datain = (rw == READ); + int write = (rw == READ); /* if we read from disk + it means we write + to memory */ /* Make sure the iobuf is not already mapped somewhere. */ if (iobuf->nr_pages) @@ -443,10 +448,11 @@ if (err) return err; + repeat: down(&mm->mmap_sem); err = -EFAULT; - iobuf->locked = 0; + iobuf->locked = 1; iobuf->offset = va & ~PAGE_MASK; iobuf->length = len; @@ -457,8 +463,9 @@ */ while (ptr < end) { if (!vma || ptr >= vma->vm_end) { - vma = find_vma(current->mm, ptr); - if (!vma) + refind: + vma = find_vma(mm, ptr); + if (!vma) goto out_unlock; if (vma->vm_start > ptr) { if (!(vma->vm_flags & VM_GROWSDOWN)) @@ -466,25 +473,35 @@ if (expand_stack(vma, ptr)) goto out_unlock; } - if (((datain) && (!(vma->vm_flags & VM_WRITE))) || - (!(vma->vm_flags & VM_READ))) { - err = -EACCES; - goto out_unlock; + err = -EACCES; + if (write) { + if (!(vma->vm_flags & VM_WRITE)) + goto out_unlock; + } else { + if (!(vma->vm_flags & VM_READ)) + goto out_unlock; } + err = -EFAULT; } - if (handle_mm_fault(current->mm, vma, ptr, datain) <= 0) - goto out_unlock; spin_lock(&mm->page_table_lock); - map = follow_page(ptr); - if (!map) { + if (!(map = follow_page(ptr, write))) { + char * user_ptr = (char *) ptr; + char c; spin_unlock(&mm->page_table_lock); - dprintk (KERN_ERR "Missing page in map_user_kiobuf\n"); - goto out_unlock; + up(&mm->mmap_sem); + if (get_user(c, user_ptr)) + goto out; + if (write && put_user(c, user_ptr)) + goto out; + down(&mm->mmap_sem); + goto refind; } map = get_page_map(map); - if (map) + if (map) { + if (TryLockPage(map)) + goto retry; atomic_inc(&map->count); - else + } else printk (KERN_INFO "Mapped page missing [%d]\n", i); spin_unlock(&mm->page_table_lock); iobuf->maplist[i] = map; @@ -499,9 +516,39 @@ out_unlock: up(&mm->mmap_sem); + out: unmap_kiobuf(iobuf); dprintk ("map_user_kiobuf: end %d\n", err); return err; + + retry: + + /* + * Undo the locking so far, wait on the page we got to, and try again. + */ + unmap_kiobuf(iobuf); + up(&mm->mmap_sem); + + /* + * Did the release also unlock the page we got stuck on? + */ + if (!PageLocked(map)) { + /* If so, we may well have the page mapped twice in the + * IO address range. Bad news. Of course, it _might_ + * just be a coincidence, but if it happens more than + * once, chances are we have a double-mapped page. */ + if (++doublepage >= 3) { + return -EINVAL; + } + } + + /* + * Try again... + */ + wait_on_page(map); + if (++repeat < 16) + goto repeat; + return -EAGAIN; } @@ -594,9 +641,9 @@ if (++doublepage >= 3) return -EINVAL; + } else /* Try again... */ wait_on_page(page); - } if (++repeat < 16) goto repeat; @@ -1027,11 +1074,12 @@ * because it doesn't cost us any seek time. We also make sure to queue * the 'original' request together with the readahead ones... */ -void swapin_readahead(swp_entry_t entry) +void swapin_readaround(swp_entry_t entry) { int i, num; struct page *new_page; unsigned long offset; + swp_entry_t readaround_entry; /* * Get the number of handles we should do readahead io to. Also, @@ -1046,8 +1094,17 @@ swap_free(SWP_ENTRY(SWP_TYPE(entry), offset++)); break; } - /* Ok, do the async read-ahead now */ - new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0); + readaround_entry = SWP_ENTRY(SWP_TYPE(entry), offset); + new_page = NULL; + /* + * Nobody can insert a page in the swap_cache without + * holding the big kernel lock. FIXME: swap_shm will SMP + * race because it runs add_to_swap_cache without the big + * kernel lock held. + */ + if (!check_page(&swapper_space, readaround_entry.val)) + /* Ok, do the async read-ahead now */ + new_page = read_swap_cache_async(readaround_entry, 0); if (new_page != NULL) page_cache_release(new_page); swap_free(SWP_ENTRY(SWP_TYPE(entry), offset)); @@ -1064,7 +1121,7 @@ if (!page) { lock_kernel(); - swapin_readahead(entry); + swapin_readaround(entry); page = read_swap_cache(entry); unlock_kernel(); if (!page)