diff options
author | Mel Gorman <mgorman@suse.de> | 2012-01-12 20:19:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 23:13:09 -0500 |
commit | b969c4ab9f182a6e1b2a0848be349f99714947b0 (patch) | |
tree | dc1c6e4375cfec7b15f13a37307eba8a9e07f40f /mm/migrate.c | |
parent | 7335084d446b83cbcb15da80497d03f0c1dc9e21 (diff) |
mm: compaction: determine if dirty pages can be migrated without blocking within ->migratepage
Asynchronous compaction is used when allocating transparent hugepages to
avoid blocking for long periods of time. Due to reports of stalling,
there was a debate on disabling synchronous compaction but this severely
impacted allocation success rates. Part of the reason was that many dirty
pages are skipped in asynchronous compaction by the following check;
if (PageDirty(page) && !sync &&
mapping->a_ops->migratepage != migrate_page)
rc = -EBUSY;
This skips over all mapping aops using buffer_migrate_page() even though
it is possible to migrate some of these pages without blocking. This
patch updates the ->migratepage callback with a "sync" parameter. It is
the responsibility of the callback to fail gracefully if migration would
block.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Reviewed-by: Rik van Riel <riel@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: Dave Jones <davej@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Andy Isaacson <adi@hexapodia.org>
Cc: Nai Xia <nai.xia@gmail.com>
Cc: Johannes Weiner <jweiner@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 129 |
1 files changed, 92 insertions, 37 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index fc391985899f..4e86f3bacb85 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -216,6 +216,55 @@ out: | |||
216 | pte_unmap_unlock(ptep, ptl); | 216 | pte_unmap_unlock(ptep, ptl); |
217 | } | 217 | } |
218 | 218 | ||
219 | #ifdef CONFIG_BLOCK | ||
220 | /* Returns true if all buffers are successfully locked */ | ||
221 | static bool buffer_migrate_lock_buffers(struct buffer_head *head, bool sync) | ||
222 | { | ||
223 | struct buffer_head *bh = head; | ||
224 | |||
225 | /* Simple case, sync compaction */ | ||
226 | if (sync) { | ||
227 | do { | ||
228 | get_bh(bh); | ||
229 | lock_buffer(bh); | ||
230 | bh = bh->b_this_page; | ||
231 | |||
232 | } while (bh != head); | ||
233 | |||
234 | return true; | ||
235 | } | ||
236 | |||
237 | /* async case, we cannot block on lock_buffer so use trylock_buffer */ | ||
238 | do { | ||
239 | get_bh(bh); | ||
240 | if (!trylock_buffer(bh)) { | ||
241 | /* | ||
242 | * We failed to lock the buffer and cannot stall in | ||
243 | * async migration. Release the taken locks | ||
244 | */ | ||
245 | struct buffer_head *failed_bh = bh; | ||
246 | put_bh(failed_bh); | ||
247 | bh = head; | ||
248 | while (bh != failed_bh) { | ||
249 | unlock_buffer(bh); | ||
250 | put_bh(bh); | ||
251 | bh = bh->b_this_page; | ||
252 | } | ||
253 | return false; | ||
254 | } | ||
255 | |||
256 | bh = bh->b_this_page; | ||
257 | } while (bh != head); | ||
258 | return true; | ||
259 | } | ||
260 | #else | ||
261 | static inline bool buffer_migrate_lock_buffers(struct buffer_head *head, | ||
262 | bool sync) | ||
263 | { | ||
264 | return true; | ||
265 | } | ||
266 | #endif /* CONFIG_BLOCK */ | ||
267 | |||
219 | /* | 268 | /* |
220 | * Replace the page in the mapping. | 269 | * Replace the page in the mapping. |
221 | * | 270 | * |
@@ -225,7 +274,8 @@ out: | |||
225 | * 3 for pages with a mapping and PagePrivate/PagePrivate2 set. | 274 | * 3 for pages with a mapping and PagePrivate/PagePrivate2 set. |
226 | */ | 275 | */ |
227 | static int migrate_page_move_mapping(struct address_space *mapping, | 276 | static int migrate_page_move_mapping(struct address_space *mapping, |
228 | struct page *newpage, struct page *page) | 277 | struct page *newpage, struct page *page, |
278 | struct buffer_head *head, bool sync) | ||
229 | { | 279 | { |
230 | int expected_count; | 280 | int expected_count; |
231 | void **pslot; | 281 | void **pslot; |
@@ -255,6 +305,19 @@ static int migrate_page_move_mapping(struct address_space *mapping, | |||
255 | } | 305 | } |
256 | 306 | ||
257 | /* | 307 | /* |
308 | * In the async migration case of moving a page with buffers, lock the | ||
309 | * buffers using trylock before the mapping is moved. If the mapping | ||
310 | * was moved, we later failed to lock the buffers and could not move | ||
311 | * the mapping back due to an elevated page count, we would have to | ||
312 | * block waiting on other references to be dropped. | ||
313 | */ | ||
314 | if (!sync && head && !buffer_migrate_lock_buffers(head, sync)) { | ||
315 | page_unfreeze_refs(page, expected_count); | ||
316 | spin_unlock_irq(&mapping->tree_lock); | ||
317 | return -EAGAIN; | ||
318 | } | ||
319 | |||
320 | /* | ||
258 | * Now we know that no one else is looking at the page. | 321 | * Now we know that no one else is looking at the page. |
259 | */ | 322 | */ |
260 | get_page(newpage); /* add cache reference */ | 323 | get_page(newpage); /* add cache reference */ |
@@ -409,13 +472,13 @@ EXPORT_SYMBOL(fail_migrate_page); | |||
409 | * Pages are locked upon entry and exit. | 472 | * Pages are locked upon entry and exit. |
410 | */ | 473 | */ |
411 | int migrate_page(struct address_space *mapping, | 474 | int migrate_page(struct address_space *mapping, |
412 | struct page *newpage, struct page *page) | 475 | struct page *newpage, struct page *page, bool sync) |
413 | { | 476 | { |
414 | int rc; | 477 | int rc; |
415 | 478 | ||
416 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ | 479 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ |
417 | 480 | ||
418 | rc = migrate_page_move_mapping(mapping, newpage, page); | 481 | rc = migrate_page_move_mapping(mapping, newpage, page, NULL, sync); |
419 | 482 | ||
420 | if (rc) | 483 | if (rc) |
421 | return rc; | 484 | return rc; |
@@ -432,28 +495,28 @@ EXPORT_SYMBOL(migrate_page); | |||
432 | * exist. | 495 | * exist. |
433 | */ | 496 | */ |
434 | int buffer_migrate_page(struct address_space *mapping, | 497 | int buffer_migrate_page(struct address_space *mapping, |
435 | struct page *newpage, struct page *page) | 498 | struct page *newpage, struct page *page, bool sync) |
436 | { | 499 | { |
437 | struct buffer_head *bh, *head; | 500 | struct buffer_head *bh, *head; |
438 | int rc; | 501 | int rc; |
439 | 502 | ||
440 | if (!page_has_buffers(page)) | 503 | if (!page_has_buffers(page)) |
441 | return migrate_page(mapping, newpage, page); | 504 | return migrate_page(mapping, newpage, page, sync); |
442 | 505 | ||
443 | head = page_buffers(page); | 506 | head = page_buffers(page); |
444 | 507 | ||
445 | rc = migrate_page_move_mapping(mapping, newpage, page); | 508 | rc = migrate_page_move_mapping(mapping, newpage, page, head, sync); |
446 | 509 | ||
447 | if (rc) | 510 | if (rc) |
448 | return rc; | 511 | return rc; |
449 | 512 | ||
450 | bh = head; | 513 | /* |
451 | do { | 514 | * In the async case, migrate_page_move_mapping locked the buffers |
452 | get_bh(bh); | 515 | * with an IRQ-safe spinlock held. In the sync case, the buffers |
453 | lock_buffer(bh); | 516 | * need to be locked now |
454 | bh = bh->b_this_page; | 517 | */ |
455 | 518 | if (sync) | |
456 | } while (bh != head); | 519 | BUG_ON(!buffer_migrate_lock_buffers(head, sync)); |
457 | 520 | ||
458 | ClearPagePrivate(page); | 521 | ClearPagePrivate(page); |
459 | set_page_private(newpage, page_private(page)); | 522 | set_page_private(newpage, page_private(page)); |
@@ -530,10 +593,13 @@ static int writeout(struct address_space *mapping, struct page *page) | |||
530 | * Default handling if a filesystem does not provide a migration function. | 593 | * Default handling if a filesystem does not provide a migration function. |
531 | */ | 594 | */ |
532 | static int fallback_migrate_page(struct address_space *mapping, | 595 | static int fallback_migrate_page(struct address_space *mapping, |
533 | struct page *newpage, struct page *page) | 596 | struct page *newpage, struct page *page, bool sync) |
534 | { | 597 | { |
535 | if (PageDirty(page)) | 598 | if (PageDirty(page)) { |
599 | if (!sync) | ||
600 | return -EBUSY; | ||
536 | return writeout(mapping, page); | 601 | return writeout(mapping, page); |
602 | } | ||
537 | 603 | ||
538 | /* | 604 | /* |
539 | * Buffers may be managed in a filesystem specific way. | 605 | * Buffers may be managed in a filesystem specific way. |
@@ -543,7 +609,7 @@ static int fallback_migrate_page(struct address_space *mapping, | |||
543 | !try_to_release_page(page, GFP_KERNEL)) | 609 | !try_to_release_page(page, GFP_KERNEL)) |
544 | return -EAGAIN; | 610 | return -EAGAIN; |
545 | 611 | ||
546 | return migrate_page(mapping, newpage, page); | 612 | return migrate_page(mapping, newpage, page, sync); |
547 | } | 613 | } |
548 | 614 | ||
549 | /* | 615 | /* |
@@ -579,29 +645,18 @@ static int move_to_new_page(struct page *newpage, struct page *page, | |||
579 | 645 | ||
580 | mapping = page_mapping(page); | 646 | mapping = page_mapping(page); |
581 | if (!mapping) | 647 | if (!mapping) |
582 | rc = migrate_page(mapping, newpage, page); | 648 | rc = migrate_page(mapping, newpage, page, sync); |
583 | else { | 649 | else if (mapping->a_ops->migratepage) |
584 | /* | 650 | /* |
585 | * Do not writeback pages if !sync and migratepage is | 651 | * Most pages have a mapping and most filesystems provide a |
586 | * not pointing to migrate_page() which is nonblocking | 652 | * migratepage callback. Anonymous pages are part of swap |
587 | * (swapcache/tmpfs uses migratepage = migrate_page). | 653 | * space which also has its own migratepage callback. This |
654 | * is the most common path for page migration. | ||
588 | */ | 655 | */ |
589 | if (PageDirty(page) && !sync && | 656 | rc = mapping->a_ops->migratepage(mapping, |
590 | mapping->a_ops->migratepage != migrate_page) | 657 | newpage, page, sync); |
591 | rc = -EBUSY; | 658 | else |
592 | else if (mapping->a_ops->migratepage) | 659 | rc = fallback_migrate_page(mapping, newpage, page, sync); |
593 | /* | ||
594 | * Most pages have a mapping and most filesystems | ||
595 | * should provide a migration function. Anonymous | ||
596 | * pages are part of swap space which also has its | ||
597 | * own migration function. This is the most common | ||
598 | * path for page migration. | ||
599 | */ | ||
600 | rc = mapping->a_ops->migratepage(mapping, | ||
601 | newpage, page); | ||
602 | else | ||
603 | rc = fallback_migrate_page(mapping, newpage, page); | ||
604 | } | ||
605 | 660 | ||
606 | if (rc) { | 661 | if (rc) { |
607 | newpage->mapping = NULL; | 662 | newpage->mapping = NULL; |