]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Russ Anderson <rja@sgi.com> |
2 | Subject: mm: Avoid putting a bad page back on the LRU v8 | |
3 | References: 415829 | |
4 | Acked-by: schwab@suse.de | |
5 | ||
6 | Prevent a page with a physical memory error from being placed back | |
7 | on the LRU. A new page flag (PG_memerror) is added if | |
8 | CONFIG_PAGEFLAGS_EXTENDED is defined. | |
9 | ||
10 | Version 8 change: Removed hot path check for pages with memory | |
11 | errors on the free list. | |
12 | ||
13 | Signed-off-by: Russ Anderson <rja@sgi.com> | |
14 | Reviewed-by: Christoph Lameter <cl@linux-foundation.org> | |
15 | ||
16 | --- | |
17 | include/linux/page-flags.h | 15 ++++++++++++++- | |
18 | mm/migrate.c | 36 +++++++++++++++++++++++++++++++++++- | |
19 | 2 files changed, 49 insertions(+), 2 deletions(-) | |
20 | ||
21 | Index: linux/mm/migrate.c | |
22 | =================================================================== | |
23 | --- linux.orig/mm/migrate.c 2008-07-29 13:18:23.000000000 -0500 | |
24 | +++ linux/mm/migrate.c 2008-07-29 13:21:03.000000000 -0500 | |
25 | @@ -65,6 +65,7 @@ int isolate_lru_page(struct page *page, | |
26 | } | |
27 | return ret; | |
28 | } | |
29 | +EXPORT_SYMBOL(isolate_lru_page); | |
30 | ||
31 | /* | |
32 | * migrate_prep() needs to be called before we start compiling a list of pages | |
33 | @@ -82,6 +83,7 @@ int migrate_prep(void) | |
34 | ||
35 | return 0; | |
36 | } | |
37 | +EXPORT_SYMBOL(migrate_prep); | |
38 | ||
39 | static inline void move_to_lru(struct page *page) | |
40 | { | |
41 | @@ -116,6 +118,7 @@ int putback_lru_pages(struct list_head * | |
42 | } | |
43 | return count; | |
44 | } | |
45 | +EXPORT_SYMBOL(putback_lru_pages); | |
46 | ||
47 | /* | |
48 | * Restore a potential migration pte to a working pte entry | |
49 | @@ -741,7 +744,26 @@ unlock: | |
50 | * restored. | |
51 | */ | |
52 | list_del(&page->lru); | |
53 | - move_to_lru(page); | |
54 | + if (PageMemError(page)) { | |
55 | + if (rc == 0) | |
56 | + /* | |
57 | + * A page with a memory error that has | |
58 | + * been migrated will not be moved to | |
59 | + * the LRU. | |
60 | + */ | |
61 | + goto move_newpage; | |
62 | + else | |
63 | + /* | |
64 | + * The page failed to migrate and will not | |
65 | + * be added to the bad page list. Clearing | |
66 | + * the error bit will allow another attempt | |
67 | + * to migrate if it gets another correctable | |
68 | + * error. | |
69 | + */ | |
70 | + ClearPageMemError(page); | |
71 | + } | |
72 | + | |
73 | + move_to_lru(page); | |
74 | } | |
75 | ||
76 | move_newpage: | |
77 | @@ -813,6 +835,17 @@ int migrate_pages(struct list_head *from | |
78 | } | |
79 | } | |
80 | } | |
81 | + | |
82 | + if (rc != 0) | |
83 | + list_for_each_entry_safe(page, page2, from, lru) | |
84 | + if (PageMemError(page)) | |
85 | + /* | |
86 | + * The page failed to migrate. Clearing | |
87 | + * the error bit will allow another attempt | |
88 | + * to migrate if it gets another correctable | |
89 | + * error. | |
90 | + */ | |
91 | + ClearPageMemError(page); | |
92 | rc = 0; | |
93 | out: | |
94 | if (!swapwrite) | |
95 | @@ -825,6 +858,7 @@ out: | |
96 | ||
97 | return nr_failed + retry; | |
98 | } | |
99 | +EXPORT_SYMBOL(migrate_pages); | |
100 | ||
101 | #ifdef CONFIG_NUMA | |
102 | /* | |
103 | Index: linux/include/linux/page-flags.h | |
104 | =================================================================== | |
105 | --- linux.orig/include/linux/page-flags.h 2008-07-29 13:18:23.000000000 -0500 | |
106 | +++ linux/include/linux/page-flags.h 2008-07-29 13:21:03.000000000 -0500 | |
107 | @@ -84,6 +84,7 @@ enum pageflags { | |
108 | PG_private, /* If pagecache, has fs-private data */ | |
109 | PG_writeback, /* Page is under writeback */ | |
110 | #ifdef CONFIG_PAGEFLAGS_EXTENDED | |
111 | + PG_memerror, /* Page has a physical memory error */ | |
112 | PG_head, /* A head page */ | |
113 | PG_tail, /* A tail page */ | |
114 | #else | |
115 | @@ -147,15 +148,21 @@ static inline int TestSetPage##uname(str | |
116 | static inline int TestClearPage##uname(struct page *page) \ | |
117 | { return test_and_clear_bit(PG_##lname, &page->flags); } | |
118 | ||
119 | +#define PAGEFLAGMASK(uname, lname) \ | |
120 | +static inline int PAGEMASK_##uname(void) \ | |
121 | + { return (1 << PG_##lname); } | |
122 | ||
123 | #define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ | |
124 | - SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) | |
125 | + SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) \ | |
126 | + PAGEFLAGMASK(uname, lname) | |
127 | ||
128 | #define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ | |
129 | __SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname) | |
130 | ||
131 | #define PAGEFLAG_FALSE(uname) \ | |
132 | static inline int Page##uname(struct page *page) \ | |
133 | + { return 0; } \ | |
134 | +static inline int PAGEMASK_##uname(void) \ | |
135 | { return 0; } | |
136 | ||
137 | #define TESTSCFLAG(uname, lname) \ | |
138 | @@ -325,6 +332,12 @@ static inline void __ClearPageTail(struc | |
139 | } | |
140 | ||
141 | #endif /* !PAGEFLAGS_EXTENDED */ | |
142 | + | |
143 | +#ifdef CONFIG_PAGEFLAGS_EXTENDED | |
144 | +PAGEFLAG(MemError, memerror) | |
145 | +#else | |
146 | +PAGEFLAG_FALSE(MemError) | |
147 | +#endif | |
148 | ||
149 | #define PAGE_FLAGS (1 << PG_lru | 1 << PG_private | 1 << PG_locked | \ | |
150 | 1 << PG_buddy | 1 << PG_writeback | \ |