Commit 0e40de03 authored by Matthew Wilcox's avatar Matthew Wilcox

dax: Fix huge page faults

Using xas_load() with a PMD-sized xa_state would work if either a
PMD-sized entry was present or a PTE sized entry was present in the
first 64 entries (of the 512 PTEs in a PMD on x86).  If there was no
PTE in the first 64 entries, grab_mapping_entry() would believe there
were no entries present, allocate a PMD-sized entry and overwrite the
PTE in the page cache.

Use xas_find_conflict() instead which turns out to simplify
both get_unlocked_entry() and grab_mapping_entry().  Also remove a
WARN_ON_ONCE from grab_mapping_entry() as it will have already triggered
in get_unlocked_entry().

Fixes: cfc93c6c ("dax: Convert dax_insert_pfn_mkwrite to XArray")
Signed-off-by: default avatarMatthew Wilcox <willy@infradead.org>
parent fda490d3
...@@ -216,9 +216,8 @@ static void *get_unlocked_entry(struct xa_state *xas) ...@@ -216,9 +216,8 @@ static void *get_unlocked_entry(struct xa_state *xas)
ewait.wait.func = wake_exceptional_entry_func; ewait.wait.func = wake_exceptional_entry_func;
for (;;) { for (;;) {
entry = xas_load(xas); entry = xas_find_conflict(xas);
if (!entry || xa_is_internal(entry) || if (!entry || WARN_ON_ONCE(!xa_is_value(entry)) ||
WARN_ON_ONCE(!xa_is_value(entry)) ||
!dax_is_locked(entry)) !dax_is_locked(entry))
return entry; return entry;
...@@ -458,11 +457,9 @@ static void *grab_mapping_entry(struct xa_state *xas, ...@@ -458,11 +457,9 @@ static void *grab_mapping_entry(struct xa_state *xas,
retry: retry:
xas_lock_irq(xas); xas_lock_irq(xas);
entry = get_unlocked_entry(xas); entry = get_unlocked_entry(xas);
if (xa_is_internal(entry))
goto fallback;
if (entry) { if (entry) {
if (WARN_ON_ONCE(!xa_is_value(entry))) { if (!xa_is_value(entry)) {
xas_set_err(xas, EIO); xas_set_err(xas, EIO);
goto out_unlock; goto out_unlock;
} }
...@@ -1641,8 +1638,7 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order) ...@@ -1641,8 +1638,7 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order)
/* Did we race with someone splitting entry or so? */ /* Did we race with someone splitting entry or so? */
if (!entry || if (!entry ||
(order == 0 && !dax_is_pte_entry(entry)) || (order == 0 && !dax_is_pte_entry(entry)) ||
(order == PMD_ORDER && (xa_is_internal(entry) || (order == PMD_ORDER && !dax_is_pmd_entry(entry))) {
!dax_is_pmd_entry(entry)))) {
put_unlocked_entry(&xas, entry); put_unlocked_entry(&xas, entry);
xas_unlock_irq(&xas); xas_unlock_irq(&xas);
trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf, trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment