--- linux-2.5.25-rmap/./include/linux/mm.h Mon Jul 8 15:37:35 2002 +++ linux-2.5.25-rmap-opt/./include/linux/mm.h Tue Jul 9 13:28:32 2002 @@ -157,8 +157,11 @@ updated asynchronously */ struct list_head lru; /* Pageout list, eg. active_list; protected by pagemap_lru_lock !! */ - struct pte_chain * pte_chain; /* Reverse pte mapping pointer. + union { + struct pte_chain * pte_chain; /* Reverse pte mapping pointer. * protected by PG_chainlock */ + pte_t * pte_direct; + }; unsigned long private; /* mapping-private opaque data */ /* --- linux-2.5.25-rmap/./include/linux/page-flags.h Mon Jul 8 15:37:35 2002 +++ linux-2.5.25-rmap-opt/./include/linux/page-flags.h Tue Jul 9 10:31:28 2002 @@ -66,6 +66,7 @@ #define PG_writeback 13 /* Page is under writeback */ #define PG_nosave 15 /* Used for system suspend/resume */ #define PG_chainlock 16 /* lock bit for ->pte_chain */ +#define PG_direct 17 /* ->pte_chain points directly at pte */ /* * Global page accounting. One instance per CPU. @@ -216,6 +217,12 @@ #define TestSetPageNosave(page) test_and_set_bit(PG_nosave, &(page)->flags) #define ClearPageNosave(page) clear_bit(PG_nosave, &(page)->flags) #define TestClearPageNosave(page) test_and_clear_bit(PG_nosave, &(page)->flags) + +#define PageDirect(page) test_bit(PG_direct, &(page)->flags) +#define SetPageDirect(page) set_bit(PG_direct, &(page)->flags) +#define TestSetPageDirect(page) test_and_set_bit(PG_direct, &(page)->flags) +#define ClearPageDirect(page) clear_bit(PG_direct, &(page)->flags) +#define TestClearPageDirect(page) test_and_clear_bit(PG_direct, &(page)->flags) /* * inlines for acquisition and release of PG_chainlock --- linux-2.5.25-rmap/./mm/rmap.c Mon Jul 8 15:37:35 2002 +++ linux-2.5.25-rmap-opt/./mm/rmap.c Tue Jul 9 12:46:07 2002 @@ -71,10 +71,15 @@ if (TestClearPageReferenced(page)) referenced++; - /* Check all the page tables mapping this page. */ - for (pc = page->pte_chain; pc; pc = pc->next) { - if (ptep_test_and_clear_young(pc->ptep)) + if (PageDirect(page)) { + if (ptep_test_and_clear_young(page->pte_direct)) referenced++; + } else { + /* Check all the page tables mapping this page. */ + for (pc = page->pte_chain; pc; pc = pc->next) { + if (ptep_test_and_clear_young(pc->ptep)) + referenced++; + } } return referenced; } @@ -108,22 +113,39 @@ pte_chain_lock(page); { struct pte_chain * pc; - for (pc = page->pte_chain; pc; pc = pc->next) { - if (pc->ptep == ptep) + if (PageDirect(page)) { + if (page->pte_direct == ptep) BUG(); + } else { + for (pc = page->pte_chain; pc; pc = pc->next) { + if (pc->ptep == ptep) + BUG(); + } } } pte_chain_unlock(page); #endif - pte_chain = pte_chain_alloc(); - pte_chain_lock(page); - /* Hook up the pte_chain to the page. */ - pte_chain->ptep = ptep; - pte_chain->next = page->pte_chain; - page->pte_chain = pte_chain; + if (PageDirect(page)) { + /* Convert a direct pointer into a pte_chain */ + pte_chain = pte_chain_alloc(); + pte_chain->ptep = page->pte_direct; + pte_chain->next = NULL; + page->pte_chain = pte_chain; + ClearPageDirect(page); + } + if (page->pte_chain) { + /* Hook up the pte_chain to the page. */ + pte_chain = pte_chain_alloc(); + pte_chain->ptep = ptep; + pte_chain->next = page->pte_chain; + page->pte_chain = pte_chain; + } else { + page->pte_direct = ptep; + SetPageDirect(page); + } pte_chain_unlock(page); } @@ -149,18 +171,38 @@ return; pte_chain_lock(page); - for (pc = page->pte_chain; pc; prev_pc = pc, pc = pc->next) { - if (pc->ptep == ptep) { - pte_chain_free(pc, prev_pc, page); + + if (PageDirect(page)) { + if (page->pte_direct == ptep) { + page->pte_direct = NULL; + ClearPageDirect(page); goto out; } + } else { + for (pc = page->pte_chain; pc; prev_pc = pc, pc = pc->next) { + if (pc->ptep == ptep) { + pte_chain_free(pc, prev_pc, page); + /* Check whether we can convert to direct */ + pc = page->pte_chain; + if (!pc->next) { + page->pte_direct = pc->ptep; + SetPageDirect(page); + pte_chain_free(pc, NULL, NULL); + } + goto out; + } + } } #ifdef DEBUG_RMAP /* Not found. This should NEVER happen! */ printk(KERN_ERR "page_remove_rmap: pte_chain %p not present.\n", ptep); printk(KERN_ERR "page_remove_rmap: only found: "); - for (pc = page->pte_chain; pc; pc = pc->next) - printk("%p ", pc->ptep); + if (PageDirect(page)) { + printk("%p ", page->pte_direct); + } else { + for (pc = page->pte_chain; pc; pc = pc->next) + printk("%p ", pc->ptep); + } printk("\n"); printk(KERN_ERR "page_remove_rmap: driver cleared PG_reserved ?\n"); #endif @@ -270,22 +312,42 @@ if (!page->mapping) BUG(); - for (pc = page->pte_chain; pc; pc = next_pc) { - next_pc = pc->next; - switch (try_to_unmap_one(page, pc->ptep)) { + if (PageDirect(page)) { + switch (ret = try_to_unmap_one(page, page->pte_direct)) { case SWAP_SUCCESS: - /* Free the pte_chain struct. */ - pte_chain_free(pc, prev_pc, page); - break; + page->pte_direct = NULL; + ClearPageDirect(page); + return ret; case SWAP_AGAIN: - /* Skip this pte, remembering status. */ - prev_pc = pc; - ret = SWAP_AGAIN; - continue; case SWAP_FAIL: - return SWAP_FAIL; case SWAP_ERROR: - return SWAP_ERROR; + return ret; + } + } else { + for (pc = page->pte_chain; pc; pc = next_pc) { + next_pc = pc->next; + switch (try_to_unmap_one(page, pc->ptep)) { + case SWAP_SUCCESS: + /* Free the pte_chain struct. */ + pte_chain_free(pc, prev_pc, page); + break; + case SWAP_AGAIN: + /* Skip this pte, remembering status. */ + prev_pc = pc; + ret = SWAP_AGAIN; + continue; + case SWAP_FAIL: + return SWAP_FAIL; + case SWAP_ERROR: + return SWAP_ERROR; + } + } + /* Check whether we can convert to direct pte pointer */ + pc = page->pte_chain; + if (pc && !pc->next) { + page->pte_direct = pc->ptep; + SetPageDirect(page); + pte_chain_free(pc, NULL, NULL); } }