diff options
-rw-r--r-- | mm/migrate.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index be3f141e53a4..2803a6698dd6 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -168,19 +168,19 @@ retry: | |||
168 | /* | 168 | /* |
169 | * Remove references for a page and establish the new page with the correct | 169 | * Remove references for a page and establish the new page with the correct |
170 | * basic settings to be able to stop accesses to the page. | 170 | * basic settings to be able to stop accesses to the page. |
171 | * | ||
172 | * The number of remaining references must be: | ||
173 | * 1 for anonymous pages without a mapping | ||
174 | * 2 for pages with a mapping | ||
175 | * 3 for pages with a mapping and PagePrivate set. | ||
171 | */ | 176 | */ |
172 | static int migrate_page_remove_references(struct page *newpage, | 177 | static int migrate_page_remove_references(struct page *newpage, |
173 | struct page *page, int nr_refs) | 178 | struct page *page) |
174 | { | 179 | { |
175 | struct address_space *mapping = page_mapping(page); | 180 | struct address_space *mapping = page_mapping(page); |
176 | struct page **radix_pointer; | 181 | struct page **radix_pointer; |
177 | 182 | ||
178 | /* | 183 | if (!mapping) |
179 | * Avoid doing any of the following work if the page count | ||
180 | * indicates that the page is in use or truncate has removed | ||
181 | * the page. | ||
182 | */ | ||
183 | if (!mapping || page_mapcount(page) + nr_refs != page_count(page)) | ||
184 | return -EAGAIN; | 184 | return -EAGAIN; |
185 | 185 | ||
186 | /* | 186 | /* |
@@ -218,7 +218,8 @@ static int migrate_page_remove_references(struct page *newpage, | |||
218 | &mapping->page_tree, | 218 | &mapping->page_tree, |
219 | page_index(page)); | 219 | page_index(page)); |
220 | 220 | ||
221 | if (!page_mapping(page) || page_count(page) != nr_refs || | 221 | if (!page_mapping(page) || |
222 | page_count(page) != 2 + !!PagePrivate(page) || | ||
222 | *radix_pointer != page) { | 223 | *radix_pointer != page) { |
223 | write_unlock_irq(&mapping->tree_lock); | 224 | write_unlock_irq(&mapping->tree_lock); |
224 | return -EAGAIN; | 225 | return -EAGAIN; |
@@ -309,7 +310,7 @@ int migrate_page(struct page *newpage, struct page *page) | |||
309 | 310 | ||
310 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ | 311 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ |
311 | 312 | ||
312 | rc = migrate_page_remove_references(newpage, page, 2); | 313 | rc = migrate_page_remove_references(newpage, page); |
313 | 314 | ||
314 | if (rc) | 315 | if (rc) |
315 | return rc; | 316 | return rc; |
@@ -348,7 +349,7 @@ int buffer_migrate_page(struct page *newpage, struct page *page) | |||
348 | 349 | ||
349 | head = page_buffers(page); | 350 | head = page_buffers(page); |
350 | 351 | ||
351 | rc = migrate_page_remove_references(newpage, page, 3); | 352 | rc = migrate_page_remove_references(newpage, page); |
352 | 353 | ||
353 | if (rc) | 354 | if (rc) |
354 | return rc; | 355 | return rc; |