Index: linux-2.6.14-rc5-mm1/mm/vmscan.c =================================================================== --- linux-2.6.14-rc5-mm1.orig/mm/vmscan.c 2005-11-04 14:55:53.000000000 -0800 +++ linux-2.6.14-rc5-mm1/mm/vmscan.c 2005-11-05 15:07:57.000000000 -0800 @@ -1873,3 +1873,81 @@ asmlinkage long sys_set_zone_reclaim(uns return 0; } + +LIST_HEAD(bad_list); + +int remap_bad_memory(unsigned long address, unsigned long length, int mode, char *message) +{ + struct page *page, *start, *end; + struct zone *zone; + LIST_HEAD(lru_pages); + int rc = 0; + + start = virt_to_page(address & ~PAGE_MASK); + end = virt_to_page(PAGE_ALIGN(address +length)); + zone = page_zone(page); + + spin_lock_irq(zone->lru_lock); + for (page = start; page < end; page++) { + int r; +redo: + r = __isolate_lru_page(zone, page); + + if (r == 1) { + /* Page on the LRU */ + list_add(&page->lru, lru_pages); + continue; + } + + if (page_count(page) == 0) { + /* Free page. Take it off the free lists */ + continue; + } + + if (r) { + /* + * Possible transient situation with page being freed but + * page_count(page) is no longer zero. + */ + schedule(); + goto redo; + } + + /* + * Page in use but not on the LRU. + * Cannot queue this page because ->lru + * may be in use for other purposes. + */ + if (PageSlab(page)) { + /* Try to do a slab reclaim if we can */ + /* continue; */ + } + + /* Unfreeable page. Sorry we have to bail out. */ + rc = -EIO; + break; + } + spin_unlock_irq(&zone->lru_lock); + + if (!rc) { + int r; + + list_splice(&bad_list, &lru_pages); + + if (mode) { + r = zap_pages(&lru_pages); + if (r) + rc = -EIO; + } else { + /* + * Simply swap out the pages + */ + r = migrate_pages(&lru_pages, NULL); + if (r) + rc = -EAGAIN; + } + } + putback_lru_pages(lru_pages); + return rc; +} +