Commit dc2a1cbf7d862e9d0abea1d1b4c8712dfbb5a398
Committed by
Andi Kleen
1 parent
71f72525df
Exists in
master
and in
4 other branches
HWPOISON: introduce delete_from_lru_cache()
Introduce delete_from_lru_cache() to - clear PG_active, PG_unevictable to avoid complains at unpoison time - move the isolate_lru_page() call back to the handlers instead of the entrance of __memory_failure(), this is more hwpoison filter friendly Signed-off-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com>
Showing 1 changed file with 37 additions and 8 deletions Side-by-side Diff
mm/memory-failure.c
... | ... | @@ -350,6 +350,30 @@ |
350 | 350 | }; |
351 | 351 | |
352 | 352 | /* |
353 | + * XXX: It is possible that a page is isolated from LRU cache, | |
354 | + * and then kept in swap cache or failed to remove from page cache. | |
355 | + * The page count will stop it from being freed by unpoison. | |
356 | + * Stress tests should be aware of this memory leak problem. | |
357 | + */ | |
358 | +static int delete_from_lru_cache(struct page *p) | |
359 | +{ | |
360 | + if (!isolate_lru_page(p)) { | |
361 | + /* | |
362 | + * Clear sensible page flags, so that the buddy system won't | |
363 | + * complain when the page is unpoison-and-freed. | |
364 | + */ | |
365 | + ClearPageActive(p); | |
366 | + ClearPageUnevictable(p); | |
367 | + /* | |
368 | + * drop the page count elevated by isolate_lru_page() | |
369 | + */ | |
370 | + page_cache_release(p); | |
371 | + return 0; | |
372 | + } | |
373 | + return -EIO; | |
374 | +} | |
375 | + | |
376 | +/* | |
353 | 377 | * Error hit kernel page. |
354 | 378 | * Do nothing, try to be lucky and not touch this instead. For a few cases we |
355 | 379 | * could be more sophisticated. |
... | ... | @@ -393,6 +417,8 @@ |
393 | 417 | int ret = FAILED; |
394 | 418 | struct address_space *mapping; |
395 | 419 | |
420 | + delete_from_lru_cache(p); | |
421 | + | |
396 | 422 | /* |
397 | 423 | * For anonymous pages we're done the only reference left |
398 | 424 | * should be the one m_f() holds. |
399 | 425 | |
... | ... | @@ -522,14 +548,20 @@ |
522 | 548 | /* Trigger EIO in shmem: */ |
523 | 549 | ClearPageUptodate(p); |
524 | 550 | |
525 | - return DELAYED; | |
551 | + if (!delete_from_lru_cache(p)) | |
552 | + return DELAYED; | |
553 | + else | |
554 | + return FAILED; | |
526 | 555 | } |
527 | 556 | |
528 | 557 | static int me_swapcache_clean(struct page *p, unsigned long pfn) |
529 | 558 | { |
530 | 559 | delete_from_swap_cache(p); |
531 | 560 | |
532 | - return RECOVERED; | |
561 | + if (!delete_from_lru_cache(p)) | |
562 | + return RECOVERED; | |
563 | + else | |
564 | + return FAILED; | |
533 | 565 | } |
534 | 566 | |
535 | 567 | /* |
... | ... | @@ -746,7 +778,6 @@ |
746 | 778 | |
747 | 779 | int __memory_failure(unsigned long pfn, int trapno, int flags) |
748 | 780 | { |
749 | - unsigned long lru_flag; | |
750 | 781 | struct page_state *ps; |
751 | 782 | struct page *p; |
752 | 783 | int res; |
753 | 784 | |
... | ... | @@ -796,13 +827,11 @@ |
796 | 827 | */ |
797 | 828 | if (!PageLRU(p)) |
798 | 829 | lru_add_drain_all(); |
799 | - lru_flag = p->flags & lru; | |
800 | - if (isolate_lru_page(p)) { | |
830 | + if (!PageLRU(p)) { | |
801 | 831 | action_result(pfn, "non LRU", IGNORED); |
802 | 832 | put_page(p); |
803 | 833 | return -EBUSY; |
804 | 834 | } |
805 | - page_cache_release(p); | |
806 | 835 | |
807 | 836 | /* |
808 | 837 | * Lock the page and wait for writeback to finish. |
... | ... | @@ -825,7 +854,7 @@ |
825 | 854 | /* |
826 | 855 | * Torn down by someone else? |
827 | 856 | */ |
828 | - if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) { | |
857 | + if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) { | |
829 | 858 | action_result(pfn, "already truncated LRU", IGNORED); |
830 | 859 | res = 0; |
831 | 860 | goto out; |
... | ... | @@ -833,7 +862,7 @@ |
833 | 862 | |
834 | 863 | res = -EBUSY; |
835 | 864 | for (ps = error_states;; ps++) { |
836 | - if (((p->flags | lru_flag)& ps->mask) == ps->res) { | |
865 | + if ((p->flags & ps->mask) == ps->res) { | |
837 | 866 | res = page_action(ps, p, pfn); |
838 | 867 | break; |
839 | 868 | } |