NFS: fix folio dereference before NULL check in nfs_inode_remove_request()

nfs_inode_remove_request() obtains the folio for the head request via
nfs_page_to_folio(), which returns NULL when the PG_FOLIO flag is not
set on req->wb_head.

The presence of the "if (likely(folio))" check shows the code already
assumes folio can be NULL. However, folio was dereferenced before that
check:

        folio = nfs_page_to_folio(req->wb_head);
        mapping = folio->mapping;                       /* deref */

        spin_lock(&mapping->i_private_lock);
        if (likely(folio)) {                            /* too late */

folio->mapping is read (and mapping->i_private_lock is taken, and
folio_end_dropbehind(folio) is called outside the check) before folio
is validated, so a NULL folio would crash before the guard is ever
reached, rendering the check useless.

Move the folio->mapping read, the i_private_lock section and the
folio_end_dropbehind() call inside the "if (likely(folio))" block so
the folio is only dereferenced after it has been confirmed non-NULL.
The behaviour is unchanged when folio is non-NULL.

Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Jiangshan Yi 2026-07-02 09:50:14 +08:00 committed by Trond Myklebust
parent b4dd7f8159
commit 59075fb8b7

View File

@ -739,17 +739,18 @@ static void nfs_inode_remove_request(struct nfs_page *req)
nfs_page_group_lock(req);
if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
struct folio *folio = nfs_page_to_folio(req->wb_head);
struct address_space *mapping = folio->mapping;
spin_lock(&mapping->i_private_lock);
if (likely(folio)) {
struct address_space *mapping = folio->mapping;
spin_lock(&mapping->i_private_lock);
folio->private = NULL;
folio_clear_private(folio);
clear_bit(PG_MAPPED, &req->wb_head->wb_flags);
}
spin_unlock(&mapping->i_private_lock);
spin_unlock(&mapping->i_private_lock);
folio_end_dropbehind(folio);
folio_end_dropbehind(folio);
}
}
nfs_page_group_unlock(req);