This function is setting page->mapping = swapper_space, but isn't actually adding the page to swapcache. This triggers soon-to-be-added BUGs in the radix tree code. So temporarily add these pages to swapcache for real. Also, make rw_swap_page_sync() go away if it has no callers. --- 25-akpm/mm/page_io.c | 28 ++++++++++++++++++++++++---- 1 files changed, 24 insertions(+), 4 deletions(-) diff -puN mm/page_io.c~rw_swap_page_sync-fix mm/page_io.c --- 25/mm/page_io.c~rw_swap_page_sync-fix 2004-04-03 03:00:10.555626856 -0800 +++ 25-akpm/mm/page_io.c 2004-04-03 03:00:10.558626400 -0800 @@ -137,9 +137,11 @@ struct address_space_operations swap_aop .set_page_dirty = __set_page_dirty_nobuffers, }; +#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK) + /* * A scruffy utility function to read or write an arbitrary swap page - * and wait on the I/O. + * and wait on the I/O. The caller must have a ref on the page. */ int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page) { @@ -151,8 +153,18 @@ int rw_swap_page_sync(int rw, swp_entry_ lock_page(page); BUG_ON(page->mapping); - page->mapping = &swapper_space; - page->index = entry.val; + ret = add_to_page_cache(page, &swapper_space, + entry.val, GFP_NOIO|__GFP_NOFAIL); + if (ret) { + unlock_page(page); + goto out; + } + + /* + * get one more reference to make page non-exclusive so + * remove_exclusive_swap_page won't mess with it. + */ + page_cache_get(page); if (rw == READ) { ret = swap_readpage(NULL, page); @@ -161,8 +173,16 @@ int rw_swap_page_sync(int rw, swp_entry_ ret = swap_writepage(page, &swap_wbc); wait_on_page_writeback(page); } - page->mapping = NULL; + + lock_page(page); + remove_from_page_cache(page); + unlock_page(page); + page_cache_release(page); + page_cache_release(page); /* For add_to_page_cache() */ + if (ret == 0 && (!PageUptodate(page) || PageError(page))) ret = -EIO; +out: return ret; } +#endif _