[PATCH] backing a little bit out of Rik v. riel's vm

From: Frank Dekervel (Frank.dekervel@student.kuleuven.ac.be)
Date: Fri Sep 22 2000 - 18:39:43 EST


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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Sep 23 2000 - 21:00:28 EST