--- page/include/linux/swap.h.~1~ Mon Mar 6 00:47:28 2000 +++ page/include/linux/swap.h Mon Mar 6 22:40:26 2000 @@ -174,8 +174,11 @@ #define lru_cache_del(page) \ do { \ + if (!PageLocked(page)) \ + PAGE_BUG(page); \ spin_lock(&pagemap_lru_lock); \ list_del(&(page)->lru); \ + INIT_LIST_HEAD(&(page)->lru); \ nr_lru_pages--; \ spin_unlock(&pagemap_lru_lock); \ } while (0) --- page/mm/filemap.c.~1~ Sun Feb 27 06:19:45 2000 +++ page/mm/filemap.c Mon Mar 6 23:00:21 2000 @@ -107,11 +107,13 @@ curr = curr->next; /* We cannot invalidate a locked page */ - if (PageLocked(page)) + if (TryLockPage(page)) continue; lru_cache_del(page); + UnlockPage(page); + remove_page_from_inode_queue(page); remove_page_from_hash_queue(page); page->mapping = NULL; @@ -252,7 +254,11 @@ queued in any lru queue since we have just locked down the page so nobody else may SMP race with us running a lru_cache_del() (lru_cache_del() always run with the - page locked down ;). */ + page locked down ;). + We'll handle a potential lru_cache_del() between UnlockPage + and the spin_lock, checking if somebody removed the page_lru + from the forget list from under us. */ + list_add(page_lru, &forget); spin_unlock(&pagemap_lru_lock); /* avoid unscalable SMP locking */ @@ -330,9 +336,14 @@ /* even if the dispose list is local, a truncate_inode_page() may remove a page from its queue so always synchronize with the lru lock while accesing the - page->lru field */ + page->lru field. + NOTE: avoid re-adding the page to any lru list if it gone + away from the forget list from under us. */ spin_lock(&pagemap_lru_lock); - list_add(page_lru, dispose); + if (!list_empty(page_lru)) { + list_del(page_lru); + list_add(page_lru, dispose); + } continue; unlock_noput_continue: