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);

Reply via email to