Hello, since for me , the VM deadlocks were introduced only after test8-rielvm2, i diff'd a bit between test8-rielvm2 and test9-pre5. It gave me a little patch that made me run mmap002 without locking up, so probably some people could use this little patch as a temporarily fix for the recent VM-related deadlocks. Maybe with a temp. fix we don't have to hurry that much , and people ain't getting that nervous and might get a clue on the real bug. The vm, now a bit older , still works really okay for me (much better than 'old' 2.4 vm). Please take in account i am a clueless non-kernel-hacker, and the patch might contain some absurd things, i don't know. I hope this helps a bit... Greets, Frank Dekervel
--- linux-t9p5/fs/buffer.c Sat Sep 23 00:32:55 2000 +++ linux-t8riel2/fs/buffer.c Sat Sep 23 00:35:04 2000 @@ -410,9 +410,8 @@ */ #define _hashfn(dev,block) \ ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \ + (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << +(bh_hash_shift - 12)))) +#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)] - (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \ - ((block) << (bh_hash_shift - 12)))) -#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)] static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head) { @@ -706,9 +705,9 @@ static void refill_freelist(int size) { if (!grow_buffers(size)) { + //wakeup_bdflush(1); balance_dirty(NODEV); + wakeup_kswapd(1); - wakeup_kswapd(0); /* We can't wait because of __GFP_IO */ - schedule(); } } @@ -864,14 +863,15 @@ dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); +// tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT; dirty *= 200; soft_dirty_limit = tot * bdf_prm.b_un.nfract; hard_dirty_limit = soft_dirty_limit * 2; /* First, check for the "real" dirty limit. */ + if (dirty > soft_dirty_limit || inactive_shortage()) { + if (dirty > hard_dirty_limit) - if (dirty > soft_dirty_limit) { - if (dirty > hard_dirty_limit || inactive_shortage()) return 1; return 0; } @@ -1393,19 +1393,6 @@ } /* - * NOTE! All mapped/uptodate combinations are valid: - * - * Mapped Uptodate Meaning - * - * No No "unknown" - must do get_block() - * No Yes "hole" - zero-filled - * Yes No "allocated" - allocated on disk, not read in - * Yes Yes "valid" - allocated and up-to-date in memory. - * - * "Dirty" is valid only with the last case (mapped+uptodate). - */ - -/* * block_write_full_page() is SMP-safe - currently it's still * being called with the kernel lock held, but the code is ready. */ @@ -1497,10 +1484,6 @@ goto out; if (buffer_new(bh)) { unmap_underlying_metadata(bh); - if (Page_Uptodate(page)) { - set_bit(BH_Uptodate, &bh->b_state); - continue; - } if (block_end > to) memset(kaddr+to, 0, block_end-to); if (block_start < from) @@ -1510,10 +1493,6 @@ continue; } } - if (Page_Uptodate(page)) { - set_bit(BH_Uptodate, &bh->b_state); - continue; - } if (!buffer_uptodate(bh) && (block_start < from || block_end > to)) { ll_rw_block(READ, 1, &bh); @@ -1608,10 +1587,8 @@ continue; if (!buffer_mapped(bh)) { + if (iblock < lblock) + get_block(inode, iblock, bh, 0); - if (iblock < lblock) { - if (get_block(inode, iblock, bh, 0)) - continue; - } if (!buffer_mapped(bh)) { if (!kaddr) kaddr = kmap(page); @@ -1796,25 +1773,15 @@ err = 0; if (!buffer_mapped(bh)) { - /* Hole? Nothing to do */ - if (buffer_uptodate(bh)) - goto unlock; get_block(inode, iblock, bh, 0); - /* Still unmapped? Nothing to do */ if (!buffer_mapped(bh)) goto unlock; } - - /* Ok, it's mapped. Make sure it's up-to-date */ - if (Page_Uptodate(page)) - set_bit(BH_Uptodate, &bh->b_state); - if (!buffer_uptodate(bh)) { err = -EIO; bh->b_end_io = end_buffer_io_sync; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); - /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) goto unlock; } @@ -2292,9 +2259,7 @@ { struct buffer_head * tmp, * bh = page->buffers; int index = BUFSIZE_INDEX(bh->b_size); - int loop = 0; -cleaned_buffers_try_again: spin_lock(&lru_list_lock); write_lock(&hash_table_lock); spin_lock(&free_list[index].lock); @@ -2340,14 +2305,8 @@ spin_unlock(&free_list[index].lock); write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); + if (wait) - if (wait) { sync_page_buffers(bh, wait); - /* We waited synchronously, so we can free the buffers. */ - if (wait > 1 && !loop) { - loop = 1; - goto cleaned_buffers_try_again; - } - } return 0; } --- linux-t9p5/fs/proc/proc_misc.c Sat Sep 23 00:32:55 2000 +++ linux-t8riel2/fs/proc/proc_misc.c Sat Sep 23 00:35:04 2000 @@ -160,10 +160,10 @@ "MemFree: %8lu kB\n" "MemShared: %8lu kB\n" "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "Active: %8lu kB\n" + "Inact_dirty: %8lu kB\n" + "Inact_clean: %8lu kB\n" - "Cached: %8u kB\n" - "Active: %8u kB\n" - "Inact_dirty: %8u kB\n" - "Inact_clean: %8u kB\n" "Inact_target: %8lu kB\n" "HighTotal: %8lu kB\n" "HighFree: %8lu kB\n" @@ -336,14 +336,14 @@ for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) { + int active = kstat.dk_drive_rio[major][disk] + - int active = kstat.dk_drive[major][disk] + kstat.dk_drive_rblk[major][disk] + + kstat.dk_drive_wio[major][disk] + kstat.dk_drive_wblk[major][disk]; if (active) len += sprintf(page + len, + "(%u,%u):(%u,%u,%u,%u) ", - "(%u,%u):(%u,%u,%u,%u,%u) ", major, disk, - kstat.dk_drive[major][disk], kstat.dk_drive_rio[major][disk], kstat.dk_drive_rblk[major][disk], kstat.dk_drive_wio[major][disk], --- linux-t9p5/mm/swap.c Sat Sep 23 00:32:59 2000 +++ linux-t8riel2/mm/swap.c Sat Sep 23 00:35:05 2000 @@ -161,19 +161,14 @@ * Don't touch it if it's not on the active list. * (some pages aren't on any list at all) */ + if (PageActive(page) && (page_count(page) == 1 || page->buffers) && - if (PageActive(page) && (page_count(page) <= 2 || page->buffers) && !page_ramdisk(page)) { /* * We can move the page to the inactive_dirty list * if we know there is backing store available. - * - * We also move pages here that we cannot free yet, - * but may be able to free later - because most likely - * we're holding an extra reference on the page which - * will be dropped right after deactivate_page(). */ + if (page->buffers) { - if (page->buffers || page_count(page) == 2) { del_page_from_active_list(page); add_page_to_inactive_dirty_list(page); /* @@ -186,7 +181,8 @@ add_page_to_inactive_clean_list(page); } /* + * ELSE: no backing store available, leave it on + * the active list. - * OK, we cannot free the page. Leave it alone. */ } } --- linux-t9p5/mm/vmscan.c Sat Sep 23 00:32:59 2000 +++ linux-t8riel2/mm/vmscan.c Sat Sep 23 00:35:05 2000 @@ -103,8 +103,8 @@ UnlockPage(page); vma->vm_mm->rss--; flush_tlb_page(vma, address); + page_cache_release(page); deactivate_page(page); - page_cache_release(page); goto out_failed; } @@ -572,9 +572,6 @@ maxlaunder = 0; cleaned_pages = 0; - if (!(gfp_mask & __GFP_IO)) - return 0; - dirty_page_rescan: spin_lock(&pagemap_lru_lock); maxscan = nr_inactive_dirty_pages; @@ -684,26 +681,19 @@ if (freed_page && !free_shortage()) break; continue; - } else if (page->mapping && !PageDirty(page)) { - /* - * If a page had an extra reference in - * deactivate_page(), we will find it here. - * Now the page is really freeable, so we - * move it to the inactive_clean list. - */ - UnlockPage(page); - del_page_from_inactive_dirty_list(page); - add_page_to_inactive_clean_list(page); - cleaned_pages++; } else { /* + * Somebody else freed the bufferheads for us? + * This really shouldn't happen, but we check + * for it anyway. - * OK, we don't know what to do with the page. - * It's no use keeping it here, so we move it to - * the active list. */ + printk("VM: page_launder, found pre-cleaned page ?!\n"); UnlockPage(page); + if (page->mapping && !PageDirty(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_inactive_clean_list(page); + cleaned_pages++; + } - del_page_from_inactive_dirty_list(page); - add_page_to_active_list(page); } } spin_unlock(&pagemap_lru_lock); @@ -727,6 +717,8 @@ maxlaunder = MAX_LAUNDER; /* Kflushd takes care of the rest. */ wakeup_bdflush(0); + current->policy |= SCHED_YIELD; + schedule(); goto dirty_page_rescan; } @@ -746,7 +738,7 @@ { struct list_head * page_lru; struct page * page; + int maxscan; - int maxscan, page_active = 0; int ret = 0; /* Take the lock while messing with the list... */ @@ -766,17 +758,17 @@ /* Do aging on the pages. */ if (PageTestandClearReferenced(page)) { age_page_up_nolock(page); + goto must_be_active; - page_active = 1; } else { age_page_down_nolock(page); - page_active = 0; } /* * If the page is still on the active list, move it * to the other end of the list. Otherwise it was * deactivated by age_page_down and we exit successfully. */ + if (PageActive(page)) { +must_be_active: - if (page_active || PageActive(page)) { list_del(page_lru); list_add(page_lru, &active_list); } else { @@ -873,8 +865,10 @@ do { made_progress = 0; + if (!inactive_shortage() && !free_shortage()) + goto done; + if (current->need_resched) { - __set_current_state(TASK_RUNNING); schedule(); } @@ -920,14 +914,6 @@ } /* - * If we either have enough free memory, or if - * page_launder() will be able to make enough - * free memory, then stop. - */ - if (!inactive_shortage() || !free_shortage()) - goto done; - - /* * Only switch to a lower "priority" if we * didn't make any useful progress in the * last loop. @@ -972,14 +958,10 @@ * the inode and dentry cache whenever we do this. */ if (free_shortage() || inactive_shortage()) { + ret += shrink_dcache_memory(6, gfp_mask); + ret += shrink_icache_memory(6, gfp_mask); - if (gfp_mask & __GFP_IO) { - ret += shrink_dcache_memory(6, gfp_mask); - ret += shrink_icache_memory(6, gfp_mask); - } ret += refill_inactive(gfp_mask, user); - } else { - ret = 1; } return ret; @@ -1077,7 +1059,8 @@ * We go to sleep for one second, but if it's needed * we'll be woken up earlier... */ + if (!free_shortage() || + inactive_shortage() <= inactive_target / 3) - if (!free_shortage() || !inactive_shortage()) interruptible_sleep_on_timeout(&kswapd_wait, HZ); } } @@ -1090,8 +1073,7 @@ return; if (!block) { + wake_up(&kswapd_wait); - if (waitqueue_active(&kswapd_wait)) - wake_up(&kswapd_wait); return; } @@ -1128,13 +1110,12 @@ */ int try_to_free_pages(unsigned int gfp_mask) { - int ret = 1; - if (gfp_mask & __GFP_WAIT) { + balance_dirty(NODEV); + wakeup_kswapd(1); - ret = do_try_to_free_pages(gfp_mask, 1); } + return 1; - return ret; } DECLARE_WAIT_QUEUE_HEAD(kreclaimd_wait);