Index: linux-2.6.17-rc1-mm3/mm/migrate.c =================================================================== --- linux-2.6.17-rc1-mm3.orig/mm/migrate.c 2006-04-26 02:16:24.424856550 -0700 +++ linux-2.6.17-rc1-mm3/mm/migrate.c 2006-04-26 19:38:31.874887434 -0700 @@ -273,8 +273,11 @@ * the page. */ if (!page->mapping || - page_mapcount(page) + nr_refs != page_count(page)) + page_mapcount(page) + nr_refs != page_count(page)) { + printk(KERN_ERR "Retry:page =%p mapping=%p nr_refs=%d page_count=%d mapcount=%d\n", + page, page->mapping, nr_refs, page_count(page), page_mapcount(page)); return -EAGAIN; + } /* * Establish migration ptes for anonymous pages or remove ptes @@ -295,8 +298,10 @@ /* * Retry if we were unable to remove all mappings. */ - if (page_mapcount(page)) + if (page_mapcount(page)) { + printk(KERN_ERR "Retry: page=%p mapcount = %d\n", page, page_mapcount(page)); return -EAGAIN; + } if (!mapping) { /* @@ -305,8 +310,10 @@ * removed the ptes. Now check if the kernel still has * pending references. */ - if (page_count(page) != nr_refs) + if (page_count(page) != nr_refs) { + printk(KERN_ERR "Anon Retry: page=%p pagecount=%d nr_refs=%d\n",page,page_count(page),nr_refs); return -EAGAIN; + } /* We are holding the only remaining reference */ newpage->index = page->index; @@ -326,6 +333,7 @@ if (!page_mapping(page) || page_count(page) != nr_refs || *radix_pointer != page) { write_unlock_irq(&mapping->tree_lock); + printk(KERN_ERR "mapping lock retry: page=%p page_count=%d nr_refs=%d\n", page, page_count(page),nr_refs); return -EAGAIN; } @@ -401,27 +409,46 @@ /* * Common logic to directly migrate a single page suitable for * pages that do not use PagePrivate. + * Unmapping the pte may make the page dirty. The caller must indicate + * if it is permissible to continue if that occurs. * * Pages are locked upon entry and exit. */ -int migrate_page(struct page *newpage, struct page *page) +static int __migrate_page(struct page *newpage, struct page *page, int allow_dirty) { int rc; BUG_ON(PageWriteback(page)); /* Writeback must be complete */ + printk(KERN_ERR "migrate_page: %p-%p mapping=%p\n", page, newpage, page_mapping(page)); rc = migrate_page_remove_references(newpage, page, page_mapping(page) ? 2 : 1); if (rc) { remove_migration_ptes(page, page); + printk(KERN_ERR "migrate_page failed: removing migration ptes from %p\n", page); return rc; } + if (PageDirty(page) && !allow_dirty) { + /* + * A pte was marking the page dirty. If we are not allowed to migrate dirty + * pages then we need to restart to consider the dirty state of the page. + */ + remove_migration_ptes(page, page); + return -EAGAIN; + } + migrate_page_copy(newpage, page); remove_migration_ptes(page, newpage); + printk(KERN_ERR "migrate_page: %p-%p done.\n", page, newpage); return 0; } + +int migrate_page(struct page *newpage, struct page *page) +{ + return __migrate_page(newpage, page, 1); +} EXPORT_SYMBOL(migrate_page); /* @@ -431,10 +458,15 @@ int fallback_migratepage(struct page *newpage, struct page *page, int (*writepage)(struct page *page, struct writeback_control *wbc)) { + printk(KERN_ERR "fallback_migratepages %p->%p\n", page, newpage); /* * The filesystem may still do something with the page if the page * is dirty. So we cannot migrate dirty pages but first need to * write them back. + * + * Note that the dirty information may be contained in the pte + * and we may only find out that the page is dirty when we + * unmap the ptes. */ if (PageDirty(page)) { struct writeback_control wbc = { @@ -446,6 +478,7 @@ .for_reclaim = 1 }; + printk(KERN_ERR "Page Dirty\n"); if (!writepage) /* No write method for the address space */ return -EINVAL; @@ -458,9 +491,11 @@ /* I/O Error writing */ return -EIO; + printk(KERN_ERR "Successful write triggered.\n"); if (PageWriteback(page)) /* Now a write is pending. Try again later */ return -EAGAIN; + printk(KERN_ERR "fall through to remove buffers\n"); } /* @@ -468,11 +503,18 @@ * So get rid of them. */ if (page_has_buffers(page)) { - if (!try_to_release_page(page, GFP_KERNEL)) + if (!try_to_release_page(page, GFP_KERNEL)) { + printk("Failed to remove buffers\n"); return -EAGAIN; + } } - return migrate_page(newpage, page); + printk(KERN_ERR "Continue at __migrate_page\n"); + /* + * Ok we can migrate the page. However, if it becomes dirty + * during unmapping then we need to restart page migration. + */ + return __migrate_page(newpage, page, 0); } static int call_migration_function(struct page *newpage, struct page *page, @@ -561,6 +603,7 @@ goto unlock_page; } + printk(KERN_ERR "Migration %p->%p attempt %d:\n", page, newpage, pass); newpage = lru_to_page(to); lock_page(newpage); rc = call_migration_function(newpage, page, page_mapping(page)); @@ -571,6 +614,7 @@ next: if (rc == -EAGAIN) { + printk(KERN_ERR "Migration Retry page %p Code=%d\n", page, rc); retry++; } else if (rc) { /* Permanent failure */ @@ -610,12 +654,15 @@ if (!page_has_buffers(page)) return migrate_page(newpage, page); + printk(KERN_ERR "buffer_migrate_page: %p-%p mapping=%p\n", page, newpage, page_mapping(page)); head = page_buffers(page); rc = migrate_page_remove_references(newpage, page, 3); - if (rc) + if (rc) { + printk(KERN_ERR "* buffer_migrate_page failed: %p-%p\n", page, newpage); return rc; + } bh = head; do { @@ -650,6 +697,7 @@ } while (bh != head); + printk(KERN_ERR "buffer_migrate_page complete %p-%p\n", page, newpage); return 0; } EXPORT_SYMBOL(buffer_migrate_page); Index: linux-2.6.17-rc1-mm3/fs/xfs/linux-2.6/xfs_aops.c =================================================================== --- linux-2.6.17-rc1-mm3.orig/fs/xfs/linux-2.6/xfs_aops.c 2006-04-18 10:58:33.313292000 -0700 +++ linux-2.6.17-rc1-mm3/fs/xfs/linux-2.6/xfs_aops.c 2006-04-26 19:02:41.180643440 -0700 @@ -1459,5 +1459,5 @@ .commit_write = generic_commit_write, .bmap = xfs_vm_bmap, .direct_IO = xfs_vm_direct_IO, - .migratepage = buffer_migrate_page, +// .migratepage = buffer_migrate_page, };