Skip to contentSkip to conversation

fs/dax: check zero or empty entry before converting xarray entry

PATCH RESEND Superseded Seunguk Shin 2 participants 3 messages Jul 30 – Jul 31

Subsystems (3)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH RESEND v4 1/1 fs/dax: check zero or empty entry before converting xarray entry

dax_associate_entry(), dax_disassociate_entry(), and dax_busy_page() call dax_to_folio(entry) before checking whether entry is a zero or empty xarray entry.

That ordering is wrong because zero and empty entries are not folio entries. Commit 98c183a4fccf ("fs/dax: don't disassociate zero page entries") added guards in the associate and disassociate paths, but the guards still come after dax_to_folio(entry), and dax_busy_page() still has the same problem.

Move the zero/empty checks before dax_to_folio(entry) in all three helpers.

Fixes 38607c62b34b ("fs/dax: properly refcount fs dax pages")

---
Changes in v4:
- Rebase on current upstream
- Link to v3: https://lore.kernel.org/all/[email protected]/
Changes in v3:
- Rebase on current upstream
- Update the changelog for the current code state
- Link to v2: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Add Fixes and Reviewed-by tags.
- Rebase on the latest.
- Link to v1: https://lore.kernel.org/all/[email protected]/

---
 fs/dax.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
fs/dax.c +6 -3
index 6d175cd47a99..4bca6e2bc342 100644
@@ -480,11 +480,12 @@ static void dax_associate_entry(void *entry, struct address_space *mapping,
                                unsigned long address, bool shared)
 {
        unsigned long size = dax_entry_size(entry), index;
-       struct folio *folio = dax_to_folio(entry);
+       struct folio *folio;
 
        if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
                return;
 
+       folio = dax_to_folio(entry);
        index = linear_page_index(vma, address & ~(size - 1));
        if (shared && (folio->mapping || dax_folio_is_shared(folio))) {
                if (folio->mapping)
@@ -505,21 +506,23 @@ static void dax_associate_entry(void *entry, struct address_space *mapping,
 static void dax_disassociate_entry(void *entry, struct address_space *mapping,
                                bool trunc)
 {
-       struct folio *folio = dax_to_folio(entry);
+       struct folio *folio;
 
        if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
                return;
 
+       folio = dax_to_folio(entry);
        dax_folio_put(folio);
 }
 
 static struct page *dax_busy_page(void *entry)
 {
-       struct folio *folio = dax_to_folio(entry);
+       struct folio *folio;
 
        if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
                return NULL;
 
+       folio = dax_to_folio(entry);
        if (folio_ref_count(folio) - folio_mapcount(folio))
                return &folio->page;
        else

--
2.43.0

#1 lore raw
Quoted 9 lines · On Thu, 30 Jul 2026 14:12:55 +0100 Seunguk Shin <[email protected]> wrote:

dax_associate_entry(), dax_disassociate_entry(), and dax_busy_page() call dax_to_folio(entry) before checking whether entry is a zero or empty xarray entry.

That ordering is wrong because zero and empty entries are not folio entries. Commit 98c183a4fccf ("fs/dax: don't disassociate zero page entries") added guards in the associate and disassociate paths, but the guards still come after dax_to_folio(entry), and dax_busy_page() still has the same problem.

Are there any known userspace-visible runtime effects of this?

If so, please fully describe them in the changelog. If not, please also mention that.

This is important information for deciding which kernel(s) need the patch.

Quoted 1 line

Move the zero/empty checks before dax_to_folio(entry) in all three helpers.

Thanks.