diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 142 |
1 files changed, 72 insertions, 70 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 1c25040693d2..49e71ddb6792 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -120,15 +120,6 @@ int putback_lru_pages(struct list_head *l) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | /* | 122 | /* |
123 | * Non migratable page | ||
124 | */ | ||
125 | int fail_migrate_page(struct page *newpage, struct page *page) | ||
126 | { | ||
127 | return -EIO; | ||
128 | } | ||
129 | EXPORT_SYMBOL(fail_migrate_page); | ||
130 | |||
131 | /* | ||
132 | * swapout a single page | 123 | * swapout a single page |
133 | * page is locked upon entry, unlocked on exit | 124 | * page is locked upon entry, unlocked on exit |
134 | */ | 125 | */ |
@@ -297,6 +288,17 @@ void migrate_page_copy(struct page *newpage, struct page *page) | |||
297 | } | 288 | } |
298 | EXPORT_SYMBOL(migrate_page_copy); | 289 | EXPORT_SYMBOL(migrate_page_copy); |
299 | 290 | ||
291 | /************************************************************ | ||
292 | * Migration functions | ||
293 | ***********************************************************/ | ||
294 | |||
295 | /* Always fail migration. Used for mappings that are not movable */ | ||
296 | int fail_migrate_page(struct page *newpage, struct page *page) | ||
297 | { | ||
298 | return -EIO; | ||
299 | } | ||
300 | EXPORT_SYMBOL(fail_migrate_page); | ||
301 | |||
300 | /* | 302 | /* |
301 | * Common logic to directly migrate a single page suitable for | 303 | * Common logic to directly migrate a single page suitable for |
302 | * pages that do not use PagePrivate. | 304 | * pages that do not use PagePrivate. |
@@ -330,6 +332,67 @@ int migrate_page(struct page *newpage, struct page *page) | |||
330 | EXPORT_SYMBOL(migrate_page); | 332 | EXPORT_SYMBOL(migrate_page); |
331 | 333 | ||
332 | /* | 334 | /* |
335 | * Migration function for pages with buffers. This function can only be used | ||
336 | * if the underlying filesystem guarantees that no other references to "page" | ||
337 | * exist. | ||
338 | */ | ||
339 | int buffer_migrate_page(struct page *newpage, struct page *page) | ||
340 | { | ||
341 | struct address_space *mapping = page->mapping; | ||
342 | struct buffer_head *bh, *head; | ||
343 | int rc; | ||
344 | |||
345 | if (!mapping) | ||
346 | return -EAGAIN; | ||
347 | |||
348 | if (!page_has_buffers(page)) | ||
349 | return migrate_page(newpage, page); | ||
350 | |||
351 | head = page_buffers(page); | ||
352 | |||
353 | rc = migrate_page_remove_references(newpage, page, 3); | ||
354 | |||
355 | if (rc) | ||
356 | return rc; | ||
357 | |||
358 | bh = head; | ||
359 | do { | ||
360 | get_bh(bh); | ||
361 | lock_buffer(bh); | ||
362 | bh = bh->b_this_page; | ||
363 | |||
364 | } while (bh != head); | ||
365 | |||
366 | ClearPagePrivate(page); | ||
367 | set_page_private(newpage, page_private(page)); | ||
368 | set_page_private(page, 0); | ||
369 | put_page(page); | ||
370 | get_page(newpage); | ||
371 | |||
372 | bh = head; | ||
373 | do { | ||
374 | set_bh_page(bh, newpage, bh_offset(bh)); | ||
375 | bh = bh->b_this_page; | ||
376 | |||
377 | } while (bh != head); | ||
378 | |||
379 | SetPagePrivate(newpage); | ||
380 | |||
381 | migrate_page_copy(newpage, page); | ||
382 | |||
383 | bh = head; | ||
384 | do { | ||
385 | unlock_buffer(bh); | ||
386 | put_bh(bh); | ||
387 | bh = bh->b_this_page; | ||
388 | |||
389 | } while (bh != head); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | EXPORT_SYMBOL(buffer_migrate_page); | ||
394 | |||
395 | /* | ||
333 | * migrate_pages | 396 | * migrate_pages |
334 | * | 397 | * |
335 | * Two lists are passed to this function. The first list | 398 | * Two lists are passed to this function. The first list |
@@ -529,67 +592,6 @@ next: | |||
529 | } | 592 | } |
530 | 593 | ||
531 | /* | 594 | /* |
532 | * Migration function for pages with buffers. This function can only be used | ||
533 | * if the underlying filesystem guarantees that no other references to "page" | ||
534 | * exist. | ||
535 | */ | ||
536 | int buffer_migrate_page(struct page *newpage, struct page *page) | ||
537 | { | ||
538 | struct address_space *mapping = page->mapping; | ||
539 | struct buffer_head *bh, *head; | ||
540 | int rc; | ||
541 | |||
542 | if (!mapping) | ||
543 | return -EAGAIN; | ||
544 | |||
545 | if (!page_has_buffers(page)) | ||
546 | return migrate_page(newpage, page); | ||
547 | |||
548 | head = page_buffers(page); | ||
549 | |||
550 | rc = migrate_page_remove_references(newpage, page, 3); | ||
551 | |||
552 | if (rc) | ||
553 | return rc; | ||
554 | |||
555 | bh = head; | ||
556 | do { | ||
557 | get_bh(bh); | ||
558 | lock_buffer(bh); | ||
559 | bh = bh->b_this_page; | ||
560 | |||
561 | } while (bh != head); | ||
562 | |||
563 | ClearPagePrivate(page); | ||
564 | set_page_private(newpage, page_private(page)); | ||
565 | set_page_private(page, 0); | ||
566 | put_page(page); | ||
567 | get_page(newpage); | ||
568 | |||
569 | bh = head; | ||
570 | do { | ||
571 | set_bh_page(bh, newpage, bh_offset(bh)); | ||
572 | bh = bh->b_this_page; | ||
573 | |||
574 | } while (bh != head); | ||
575 | |||
576 | SetPagePrivate(newpage); | ||
577 | |||
578 | migrate_page_copy(newpage, page); | ||
579 | |||
580 | bh = head; | ||
581 | do { | ||
582 | unlock_buffer(bh); | ||
583 | put_bh(bh); | ||
584 | bh = bh->b_this_page; | ||
585 | |||
586 | } while (bh != head); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | EXPORT_SYMBOL(buffer_migrate_page); | ||
591 | |||
592 | /* | ||
593 | * Migrate the list 'pagelist' of pages to a certain destination. | 595 | * Migrate the list 'pagelist' of pages to a certain destination. |
594 | * | 596 | * |
595 | * Specify destination with either non-NULL vma or dest_node >= 0 | 597 | * Specify destination with either non-NULL vma or dest_node >= 0 |