FAILED: patch "[PATCH] fuse: re-lock request before replacing page cache folio" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x a078484921052d0badd827fcc2770b5cfc1d4120
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026062231-impale-afar-8694@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a078484921052d0badd827fcc2770b5cfc1d4120 Mon Sep 17 00:00:00 2001
From: Joanne Koong <[email protected]>
Date: Mon, 18 May 2026 22:28:06 -0700
Subject: [PATCH] fuse: re-lock request before replacing page cache folio
fuse_try_move_folio() unlocks the request on entry but does not re-lock it on the success path. This means fuse_chan_abort() can end the request and free the fuse_io_args (eg fuse_readpages_end()) while the subsequent copy chain logic after fuse_try_move_folio() accesses the fuse_io_args, leading to use-after-free issues.
Fix this by calling lock_request() before replace_page_cache_folio(). This ensures the request is locked on the success path which will prevent the fuse_io_args from being freed while the later copying logic runs, and also ensures that the ap->folios[i]->mapping is never null since ap->folios[i] will always point to the newfolio after replace_page_cache_folio().
fs/fuse/dev.c +5 -14
@@ -1037,6 +1037,10 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliopif (WARN_ON (folio_test_mlocked (oldfolio))) goto out_fallback_unlock; + err =lock_request (cs->req); +if (err) + goto out_fallback_unlock; +replace_page_cache_folio (oldfolio, newfolio);folio_get (newfolio);
@@ -1050,20 +1054,7 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop*/ pipe_buf_release (cs->pipe, buf); - err =0 ; -spin_lock (&cs->req->waitq.lock); -if (test_bit (FR_ABORTED , &cs->req->flags)) - err = -ENOENT ; -else - *foliop = newfolio; -spin_unlock (&cs->req->waitq.lock); - -if (err) { -folio_unlock (newfolio); -folio_put (newfolio); - goto out_put_old; - } - + *foliop = newfolio;folio_unlock (oldfolio);/* Drop ref for ap->pages[] array */ folio_put (oldfolio);
Sasha Levin
maintainerPATCH 1/1 fuse: re-lock request before replacing page cache folio
From: Joanne Koong <[email protected]>
[ Upstream commit a078484921052d0badd827fcc2770b5cfc1d4120 ]
fuse_try_move_folio() unlocks the request on entry but does not re-lock it on the success path. This means fuse_chan_abort() can end the request and free the fuse_io_args (eg fuse_readpages_end()) while the subsequent copy chain logic after fuse_try_move_folio() accesses the fuse_io_args, leading to use-after-free issues.
Fix this by calling lock_request() before replace_page_cache_folio(). This ensures the request is locked on the success path which will prevent the fuse_io_args from being freed while the later copying logic runs, and also ensures that the ap->folios[i]->mapping is never null since ap->folios[i] will always point to the newfolio after replace_page_cache_folio().
--- fs/fuse/dev.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-)
fs/fuse/dev.c +5 -14
@@ -845,6 +845,10 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)if (WARN_ON (PageMlocked (oldpage))) goto out_fallback_unlock; + err =lock_request (cs->req); +if (err) + goto out_fallback_unlock; +replace_page_cache_page (oldpage, newpage);get_page (newpage);
@@ -858,20 +862,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)*/ pipe_buf_release (cs->pipe, buf); - err =0 ; -spin_lock (&cs->req->waitq.lock); -if (test_bit (FR_ABORTED , &cs->req->flags)) - err = -ENOENT ; -else - *pagep = newpage; -spin_unlock (&cs->req->waitq.lock); - -if (err) { -unlock_page (newpage); -put_page (newpage); - goto out_put_old; - } - + *pagep = newpage;unlock_page (oldpage);/* Drop ref for ap->pages[] array */ put_page (oldpage);
Signature · 1 line
2.53.0