diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/migrate.c | 90 |
1 files changed, 39 insertions, 51 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index f65e69d94527..5a340f4ca212 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -349,6 +349,42 @@ int buffer_migrate_page(struct address_space *mapping, | |||
349 | } | 349 | } |
350 | EXPORT_SYMBOL(buffer_migrate_page); | 350 | EXPORT_SYMBOL(buffer_migrate_page); |
351 | 351 | ||
352 | static int fallback_migrate_page(struct address_space *mapping, | ||
353 | struct page *newpage, struct page *page) | ||
354 | { | ||
355 | /* | ||
356 | * Default handling if a filesystem does not provide | ||
357 | * a migration function. We can only migrate clean | ||
358 | * pages so try to write out any dirty pages first. | ||
359 | */ | ||
360 | if (PageDirty(page)) { | ||
361 | switch (pageout(page, mapping)) { | ||
362 | case PAGE_KEEP: | ||
363 | case PAGE_ACTIVATE: | ||
364 | return -EAGAIN; | ||
365 | |||
366 | case PAGE_SUCCESS: | ||
367 | /* Relock since we lost the lock */ | ||
368 | lock_page(page); | ||
369 | /* Must retry since page state may have changed */ | ||
370 | return -EAGAIN; | ||
371 | |||
372 | case PAGE_CLEAN: | ||
373 | ; /* try to migrate the page below */ | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Buffers may be managed in a filesystem specific way. | ||
379 | * We must have no buffers or drop them. | ||
380 | */ | ||
381 | if (page_has_buffers(page) && | ||
382 | !try_to_release_page(page, GFP_KERNEL)) | ||
383 | return -EAGAIN; | ||
384 | |||
385 | return migrate_page(mapping, newpage, page); | ||
386 | } | ||
387 | |||
352 | /* | 388 | /* |
353 | * migrate_pages | 389 | * migrate_pages |
354 | * | 390 | * |
@@ -478,7 +514,7 @@ redo: | |||
478 | if (!mapping) | 514 | if (!mapping) |
479 | goto unlock_both; | 515 | goto unlock_both; |
480 | 516 | ||
481 | if (mapping->a_ops->migratepage) { | 517 | if (mapping->a_ops->migratepage) |
482 | /* | 518 | /* |
483 | * Most pages have a mapping and most filesystems | 519 | * Most pages have a mapping and most filesystems |
484 | * should provide a migration function. Anonymous | 520 | * should provide a migration function. Anonymous |
@@ -488,56 +524,8 @@ redo: | |||
488 | */ | 524 | */ |
489 | rc = mapping->a_ops->migratepage(mapping, | 525 | rc = mapping->a_ops->migratepage(mapping, |
490 | newpage, page); | 526 | newpage, page); |
491 | goto unlock_both; | 527 | else |
492 | } | 528 | rc = fallback_migrate_page(mapping, newpage, page); |
493 | |||
494 | /* | ||
495 | * Default handling if a filesystem does not provide | ||
496 | * a migration function. We can only migrate clean | ||
497 | * pages so try to write out any dirty pages first. | ||
498 | */ | ||
499 | if (PageDirty(page)) { | ||
500 | switch (pageout(page, mapping)) { | ||
501 | case PAGE_KEEP: | ||
502 | case PAGE_ACTIVATE: | ||
503 | goto unlock_both; | ||
504 | |||
505 | case PAGE_SUCCESS: | ||
506 | unlock_page(newpage); | ||
507 | goto next; | ||
508 | |||
509 | case PAGE_CLEAN: | ||
510 | ; /* try to migrate the page below */ | ||
511 | } | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * Buffers are managed in a filesystem specific way. | ||
516 | * We must have no buffers or drop them. | ||
517 | */ | ||
518 | if (!page_has_buffers(page) || | ||
519 | try_to_release_page(page, GFP_KERNEL)) { | ||
520 | rc = migrate_page(mapping, newpage, page); | ||
521 | goto unlock_both; | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * On early passes with mapped pages simply | ||
526 | * retry. There may be a lock held for some | ||
527 | * buffers that may go away. Later | ||
528 | * swap them out. | ||
529 | */ | ||
530 | if (pass > 4) { | ||
531 | /* | ||
532 | * Persistently unable to drop buffers..... As a | ||
533 | * measure of last resort we fall back to | ||
534 | * swap_page(). | ||
535 | */ | ||
536 | unlock_page(newpage); | ||
537 | newpage = NULL; | ||
538 | rc = swap_page(page); | ||
539 | goto next; | ||
540 | } | ||
541 | 529 | ||
542 | unlock_both: | 530 | unlock_both: |
543 | unlock_page(newpage); | 531 | unlock_page(newpage); |