|
@@ -314,17 +314,29 @@ again:
|
|
|
#endif
|
|
|
|
|
|
lock_page(page_head);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If page_head->mapping is NULL, then it cannot be a PageAnon
|
|
|
+ * page; but it might be the ZERO_PAGE or in the gate area or
|
|
|
+ * in a special mapping (all cases which we are happy to fail);
|
|
|
+ * or it may have been a good file page when get_user_pages_fast
|
|
|
+ * found it, but truncated or holepunched or subjected to
|
|
|
+ * invalidate_complete_page2 before we got the page lock (also
|
|
|
+ * cases which we are happy to fail). And we hold a reference,
|
|
|
+ * so refcount care in invalidate_complete_page's remove_mapping
|
|
|
+ * prevents drop_caches from setting mapping to NULL beneath us.
|
|
|
+ *
|
|
|
+ * The case we do have to guard against is when memory pressure made
|
|
|
+ * shmem_writepage move it from filecache to swapcache beneath us:
|
|
|
+ * an unlikely race, but we do need to retry for page_head->mapping.
|
|
|
+ */
|
|
|
if (!page_head->mapping) {
|
|
|
+ int shmem_swizzled = PageSwapCache(page_head);
|
|
|
unlock_page(page_head);
|
|
|
put_page(page_head);
|
|
|
- /*
|
|
|
- * ZERO_PAGE pages don't have a mapping. Avoid a busy loop
|
|
|
- * trying to find one. RW mapping would have COW'd (and thus
|
|
|
- * have a mapping) so this page is RO and won't ever change.
|
|
|
- */
|
|
|
- if ((page_head == ZERO_PAGE(address)))
|
|
|
- return -EFAULT;
|
|
|
- goto again;
|
|
|
+ if (shmem_swizzled)
|
|
|
+ goto again;
|
|
|
+ return -EFAULT;
|
|
|
}
|
|
|
|
|
|
/*
|