|
@@ -1415,14 +1415,24 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
|
|
|
|
|
|
if (PageDirty(page)) {
|
|
if (PageDirty(page)) {
|
|
struct address_space *mapping;
|
|
struct address_space *mapping;
|
|
|
|
+ bool migrate_dirty;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Only pages without mappings or that have a
|
|
* Only pages without mappings or that have a
|
|
* ->migratepage callback are possible to migrate
|
|
* ->migratepage callback are possible to migrate
|
|
- * without blocking
|
|
|
|
|
|
+ * without blocking. However, we can be racing with
|
|
|
|
+ * truncation so it's necessary to lock the page
|
|
|
|
+ * to stabilise the mapping as truncation holds
|
|
|
|
+ * the page lock until after the page is removed
|
|
|
|
+ * from the page cache.
|
|
*/
|
|
*/
|
|
|
|
+ if (!trylock_page(page))
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
mapping = page_mapping(page);
|
|
mapping = page_mapping(page);
|
|
- if (mapping && !mapping->a_ops->migratepage)
|
|
|
|
|
|
+ migrate_dirty = mapping && mapping->a_ops->migratepage;
|
|
|
|
+ unlock_page(page);
|
|
|
|
+ if (!migrate_dirty)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|