diff options
-rw-r--r-- | include/linux/fs.h | 6 | ||||
-rw-r--r-- | include/linux/migrate.h | 6 | ||||
-rw-r--r-- | mm/migrate.c | 70 |
3 files changed, 42 insertions, 40 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index c823a3815e24..e917403f4d58 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -376,7 +376,8 @@ struct address_space_operations { | |||
376 | struct page* (*get_xip_page)(struct address_space *, sector_t, | 376 | struct page* (*get_xip_page)(struct address_space *, sector_t, |
377 | int); | 377 | int); |
378 | /* migrate the contents of a page to the specified target */ | 378 | /* migrate the contents of a page to the specified target */ |
379 | int (*migratepage) (struct page *, struct page *); | 379 | int (*migratepage) (struct address_space *, |
380 | struct page *, struct page *); | ||
380 | }; | 381 | }; |
381 | 382 | ||
382 | struct backing_dev_info; | 383 | struct backing_dev_info; |
@@ -1772,7 +1773,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count); | |||
1772 | extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t); | 1773 | extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t); |
1773 | 1774 | ||
1774 | #ifdef CONFIG_MIGRATION | 1775 | #ifdef CONFIG_MIGRATION |
1775 | extern int buffer_migrate_page(struct page *, struct page *); | 1776 | extern int buffer_migrate_page(struct address_space *, |
1777 | struct page *, struct page *); | ||
1776 | #else | 1778 | #else |
1777 | #define buffer_migrate_page NULL | 1779 | #define buffer_migrate_page NULL |
1778 | #endif | 1780 | #endif |
diff --git a/include/linux/migrate.h b/include/linux/migrate.h index e8d3b08cc354..287c47b5e5df 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h | |||
@@ -6,12 +6,14 @@ | |||
6 | #ifdef CONFIG_MIGRATION | 6 | #ifdef CONFIG_MIGRATION |
7 | extern int isolate_lru_page(struct page *p, struct list_head *pagelist); | 7 | extern int isolate_lru_page(struct page *p, struct list_head *pagelist); |
8 | extern int putback_lru_pages(struct list_head *l); | 8 | extern int putback_lru_pages(struct list_head *l); |
9 | extern int migrate_page(struct page *, struct page *); | 9 | extern int migrate_page(struct address_space *, |
10 | struct page *, struct page *); | ||
10 | extern int migrate_pages(struct list_head *l, struct list_head *t, | 11 | extern int migrate_pages(struct list_head *l, struct list_head *t, |
11 | struct list_head *moved, struct list_head *failed); | 12 | struct list_head *moved, struct list_head *failed); |
12 | extern int migrate_pages_to(struct list_head *pagelist, | 13 | extern int migrate_pages_to(struct list_head *pagelist, |
13 | struct vm_area_struct *vma, int dest); | 14 | struct vm_area_struct *vma, int dest); |
14 | extern int fail_migrate_page(struct page *, struct page *); | 15 | extern int fail_migrate_page(struct address_space *, |
16 | struct page *, struct page *); | ||
15 | 17 | ||
16 | extern int migrate_prep(void); | 18 | extern int migrate_prep(void); |
17 | 19 | ||
diff --git a/mm/migrate.c b/mm/migrate.c index 8095c607a494..f65e69d94527 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -173,15 +173,11 @@ retry: | |||
173 | * 2 for pages with a mapping | 173 | * 2 for pages with a mapping |
174 | * 3 for pages with a mapping and PagePrivate set. | 174 | * 3 for pages with a mapping and PagePrivate set. |
175 | */ | 175 | */ |
176 | static int migrate_page_move_mapping(struct page *newpage, | 176 | static int migrate_page_move_mapping(struct address_space *mapping, |
177 | struct page *page) | 177 | struct page *newpage, struct page *page) |
178 | { | 178 | { |
179 | struct address_space *mapping = page_mapping(page); | ||
180 | struct page **radix_pointer; | 179 | struct page **radix_pointer; |
181 | 180 | ||
182 | if (!mapping) | ||
183 | return -EAGAIN; | ||
184 | |||
185 | write_lock_irq(&mapping->tree_lock); | 181 | write_lock_irq(&mapping->tree_lock); |
186 | 182 | ||
187 | radix_pointer = (struct page **)radix_tree_lookup_slot( | 183 | radix_pointer = (struct page **)radix_tree_lookup_slot( |
@@ -197,15 +193,8 @@ static int migrate_page_move_mapping(struct page *newpage, | |||
197 | 193 | ||
198 | /* | 194 | /* |
199 | * Now we know that no one else is looking at the page. | 195 | * Now we know that no one else is looking at the page. |
200 | * | ||
201 | * Certain minimal information about a page must be available | ||
202 | * in order for other subsystems to properly handle the page if they | ||
203 | * find it through the radix tree update before we are finished | ||
204 | * copying the page. | ||
205 | */ | 196 | */ |
206 | get_page(newpage); | 197 | get_page(newpage); |
207 | newpage->index = page->index; | ||
208 | newpage->mapping = page->mapping; | ||
209 | if (PageSwapCache(page)) { | 198 | if (PageSwapCache(page)) { |
210 | SetPageSwapCache(newpage); | 199 | SetPageSwapCache(newpage); |
211 | set_page_private(newpage, page_private(page)); | 200 | set_page_private(newpage, page_private(page)); |
@@ -262,7 +251,8 @@ static void migrate_page_copy(struct page *newpage, struct page *page) | |||
262 | ***********************************************************/ | 251 | ***********************************************************/ |
263 | 252 | ||
264 | /* Always fail migration. Used for mappings that are not movable */ | 253 | /* Always fail migration. Used for mappings that are not movable */ |
265 | int fail_migrate_page(struct page *newpage, struct page *page) | 254 | int fail_migrate_page(struct address_space *mapping, |
255 | struct page *newpage, struct page *page) | ||
266 | { | 256 | { |
267 | return -EIO; | 257 | return -EIO; |
268 | } | 258 | } |
@@ -274,13 +264,14 @@ EXPORT_SYMBOL(fail_migrate_page); | |||
274 | * | 264 | * |
275 | * Pages are locked upon entry and exit. | 265 | * Pages are locked upon entry and exit. |
276 | */ | 266 | */ |
277 | int migrate_page(struct page *newpage, struct page *page) | 267 | int migrate_page(struct address_space *mapping, |
268 | struct page *newpage, struct page *page) | ||
278 | { | 269 | { |
279 | int rc; | 270 | int rc; |
280 | 271 | ||
281 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ | 272 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ |
282 | 273 | ||
283 | rc = migrate_page_move_mapping(newpage, page); | 274 | rc = migrate_page_move_mapping(mapping, newpage, page); |
284 | 275 | ||
285 | if (rc) | 276 | if (rc) |
286 | return rc; | 277 | return rc; |
@@ -305,21 +296,18 @@ EXPORT_SYMBOL(migrate_page); | |||
305 | * if the underlying filesystem guarantees that no other references to "page" | 296 | * if the underlying filesystem guarantees that no other references to "page" |
306 | * exist. | 297 | * exist. |
307 | */ | 298 | */ |
308 | int buffer_migrate_page(struct page *newpage, struct page *page) | 299 | int buffer_migrate_page(struct address_space *mapping, |
300 | struct page *newpage, struct page *page) | ||
309 | { | 301 | { |
310 | struct address_space *mapping = page->mapping; | ||
311 | struct buffer_head *bh, *head; | 302 | struct buffer_head *bh, *head; |
312 | int rc; | 303 | int rc; |
313 | 304 | ||
314 | if (!mapping) | ||
315 | return -EAGAIN; | ||
316 | |||
317 | if (!page_has_buffers(page)) | 305 | if (!page_has_buffers(page)) |
318 | return migrate_page(newpage, page); | 306 | return migrate_page(mapping, newpage, page); |
319 | 307 | ||
320 | head = page_buffers(page); | 308 | head = page_buffers(page); |
321 | 309 | ||
322 | rc = migrate_page_move_mapping(newpage, page); | 310 | rc = migrate_page_move_mapping(mapping, newpage, page); |
323 | 311 | ||
324 | if (rc) | 312 | if (rc) |
325 | return rc; | 313 | return rc; |
@@ -448,9 +436,6 @@ redo: | |||
448 | goto next; | 436 | goto next; |
449 | } | 437 | } |
450 | 438 | ||
451 | newpage = lru_to_page(to); | ||
452 | lock_page(newpage); | ||
453 | |||
454 | /* | 439 | /* |
455 | * Establish swap ptes for anonymous pages or destroy pte | 440 | * Establish swap ptes for anonymous pages or destroy pte |
456 | * maps for files. | 441 | * maps for files. |
@@ -473,11 +458,18 @@ redo: | |||
473 | rc = -EPERM; | 458 | rc = -EPERM; |
474 | if (try_to_unmap(page, 1) == SWAP_FAIL) | 459 | if (try_to_unmap(page, 1) == SWAP_FAIL) |
475 | /* A vma has VM_LOCKED set -> permanent failure */ | 460 | /* A vma has VM_LOCKED set -> permanent failure */ |
476 | goto unlock_both; | 461 | goto unlock_page; |
477 | 462 | ||
478 | rc = -EAGAIN; | 463 | rc = -EAGAIN; |
479 | if (page_mapped(page)) | 464 | if (page_mapped(page)) |
480 | goto unlock_both; | 465 | goto unlock_page; |
466 | |||
467 | newpage = lru_to_page(to); | ||
468 | lock_page(newpage); | ||
469 | /* Prepare mapping for the new page.*/ | ||
470 | newpage->index = page->index; | ||
471 | newpage->mapping = page->mapping; | ||
472 | |||
481 | /* | 473 | /* |
482 | * Pages are properly locked and writeback is complete. | 474 | * Pages are properly locked and writeback is complete. |
483 | * Try to migrate the page. | 475 | * Try to migrate the page. |
@@ -494,7 +486,8 @@ redo: | |||
494 | * own migration function. This is the most common | 486 | * own migration function. This is the most common |
495 | * path for page migration. | 487 | * path for page migration. |
496 | */ | 488 | */ |
497 | rc = mapping->a_ops->migratepage(newpage, page); | 489 | rc = mapping->a_ops->migratepage(mapping, |
490 | newpage, page); | ||
498 | goto unlock_both; | 491 | goto unlock_both; |
499 | } | 492 | } |
500 | 493 | ||
@@ -524,7 +517,7 @@ redo: | |||
524 | */ | 517 | */ |
525 | if (!page_has_buffers(page) || | 518 | if (!page_has_buffers(page) || |
526 | try_to_release_page(page, GFP_KERNEL)) { | 519 | try_to_release_page(page, GFP_KERNEL)) { |
527 | rc = migrate_page(newpage, page); | 520 | rc = migrate_page(mapping, newpage, page); |
528 | goto unlock_both; | 521 | goto unlock_both; |
529 | } | 522 | } |
530 | 523 | ||
@@ -553,12 +546,17 @@ unlock_page: | |||
553 | unlock_page(page); | 546 | unlock_page(page); |
554 | 547 | ||
555 | next: | 548 | next: |
556 | if (rc == -EAGAIN) { | 549 | if (rc) { |
557 | retry++; | 550 | if (newpage) |
558 | } else if (rc) { | 551 | newpage->mapping = NULL; |
559 | /* Permanent failure */ | 552 | |
560 | list_move(&page->lru, failed); | 553 | if (rc == -EAGAIN) |
561 | nr_failed++; | 554 | retry++; |
555 | else { | ||
556 | /* Permanent failure */ | ||
557 | list_move(&page->lru, failed); | ||
558 | nr_failed++; | ||
559 | } | ||
562 | } else { | 560 | } else { |
563 | if (newpage) { | 561 | if (newpage) { |
564 | /* Successful migration. Return page to LRU */ | 562 | /* Successful migration. Return page to LRU */ |