lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250223235719.66576-1-raphaelsc@scylladb.com>
Date: Sun, 23 Feb 2025 20:57:19 -0300
From: "Raphael S. Carvalho" <raphaelsc@...lladb.com>
To: linux-kernel@...r.kernel.org,
	linux-xfs@...r.kernel.org,
	linux-mm@...ck.org,
	linux-fsdevel@...r.kernel.org
Cc: djwong@...nel.org,
	Dave Chinner <david@...morbit.com>,
	hch@....de,
	willy@...radead.org,
	"Raphael S. Carvalho" <raphaelsc@...lladb.com>
Subject: [PATCH] mm: Fix error handling in __filemap_get_folio() with FGP_NOWAIT

original report:
https://lore.kernel.org/all/CAKhLTr1UL3ePTpYjXOx2AJfNk8Ku2EdcEfu+CH1sf3Asr=B-Dw@mail.gmail.com/T/

When doing buffered writes with FGP_NOWAIT, under memory pressure, the system
returned ENOMEM despite there was plenty of available memory. The user space
used io_uring interface, which in turn submits I/O with FGP_NOWAIT (the fast
path).

retsnoop pointed to iomap_get_folio:

00:34:16.180612 -> 00:34:16.180651 TID/PID 253786/253721
(reactor-1/combined_tests):

                    entry_SYSCALL_64_after_hwframe+0x76
                    do_syscall_64+0x82
                    __do_sys_io_uring_enter+0x265
                    io_submit_sqes+0x209
                    io_issue_sqe+0x5b
                    io_write+0xdd
                    xfs_file_buffered_write+0x84
                    iomap_file_buffered_write+0x1a6
    32us [-ENOMEM]  iomap_write_begin+0x408
iter=&{.inode=0xffff8c67aa031138,.len=4096,.flags=33,.iomap={.addr=0xffffffffffffffff,.length=4096,.type=1,.flags=3,.bdev=0x…
pos=0 len=4096 foliop=0xffffb32c296b7b80
!    4us [-ENOMEM]  iomap_get_folio
iter=&{.inode=0xffff8c67aa031138,.len=4096,.flags=33,.iomap={.addr=0xffffffffffffffff,.length=4096,.type=1,.flags=3,.bdev=0x…
pos=0 len=4096

This is likely a regression caused by 66dabbb65d67 ("mm: return an ERR_PTR
from __filemap_get_folio"), which performed the following changes:
    --- a/fs/iomap/buffered-io.c
    +++ b/fs/iomap/buffered-io.c
    @@ -468,19 +468,12 @@ EXPORT_SYMBOL_GPL(iomap_is_partially_uptodate);
    struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos)
    {
            unsigned fgp = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE | FGP_NOFS;
    -       struct folio *folio;

            if (iter->flags & IOMAP_NOWAIT)
                    fgp |= FGP_NOWAIT;

    -       folio = __filemap_get_folio(iter->inode->i_mapping, pos >> PAGE_SHIFT,
    +       return __filemap_get_folio(iter->inode->i_mapping, pos >> PAGE_SHIFT,
                            fgp, mapping_gfp_mask(iter->inode->i_mapping));
    -       if (folio)
    -               return folio;
    -
    -       if (iter->flags & IOMAP_NOWAIT)
    -               return ERR_PTR(-EAGAIN);
    -       return ERR_PTR(-ENOMEM);
    }

Essentially, that patch is moving error picking decision to
__filemap_get_folio, but it missed proper FGP_NOWAIT handling, so ENOMEM
is being escaped to user space. Had it correctly returned -EAGAIN with NOWAIT,
either io_uring or user space itself would be able to retry the request.
It's not enough to patch io_uring since the iomap interface is the one
responsible for it, and pwritev2(RWF_NOWAIT) and AIO interfaces must return
the proper error too.

The patch was tested with scylladb test suite (its original reproducer), and
the tests all pass now when memory is pressured.

Signed-off-by: Raphael S. Carvalho <raphaelsc@...lladb.com>
---
 mm/filemap.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index 804d7365680c..b06bd6eedaf7 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1986,8 +1986,15 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
 
 		if (err == -EEXIST)
 			goto repeat;
-		if (err)
+		if (err) {
+			/*
+			 * Presumably ENOMEM, either from when allocating or
+			 * adding folio (this one for xarray node)
+			 */
+			if (fgp_flags & FGP_NOWAIT)
+				err = -EAGAIN;
 			return ERR_PTR(err);
+		}
 		/*
 		 * filemap_add_folio locks the page, and for mmap
 		 * we expect an unlocked page.
-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ