diff options
author | Andrew Morton <akpm@linux-foundation.org> | 2025-03-16 22:04:39 -0700 |
---|---|---|
committer | Andrew Morton <akpm@linux-foundation.org> | 2025-03-16 22:04:39 -0700 |
commit | 833ea1277f8e04bc05248a077ec1d41f5aa6dc70 (patch) | |
tree | 3b96debff9db612f2a683bdb7918fddfcc14385c /mm/filemap.c | |
parent | 80e54e84911a923c40d7bee33a34c1b4be148d7a (diff) | |
parent | 800f1059c99e2b39899bdc67a7593a7bea6375d8 (diff) |
Merge branch 'mm-hotfixes-stable' into mm-stable in order to pick up memcg
and DAMON changes which are required by mm-stable material.
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 2974691fdfad..6e3d27993b67 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1986,8 +1986,19 @@ no_page: if (err == -EEXIST) goto repeat; - if (err) + if (err) { + /* + * When NOWAIT I/O fails to allocate folios this could + * be due to a nonblocking memory allocation and not + * because the system actually is out of memory. + * Return -EAGAIN so that there caller retries in a + * blocking fashion instead of propagating -ENOMEM + * to the application. + */ + if ((fgp_flags & FGP_NOWAIT) && err == -ENOMEM) + err = -EAGAIN; return ERR_PTR(err); + } /* * filemap_add_folio locks the page, and for mmap * we expect an unlocked page. @@ -4169,17 +4180,6 @@ retry: bytes = min(chunk - offset, bytes); balance_dirty_pages_ratelimited(mapping); - /* - * Bring in the user page that we will copy from _first_. - * Otherwise there's a nasty deadlock on copying from the - * same page as we're writing to, without it being marked - * up-to-date. - */ - if (unlikely(fault_in_iov_iter_readable(i, bytes) == bytes)) { - status = -EFAULT; - break; - } - if (fatal_signal_pending(current)) { status = -EINTR; break; @@ -4197,6 +4197,12 @@ retry: if (mapping_writably_mapped(mapping)) flush_dcache_folio(folio); + /* + * Faults here on mmap()s can recurse into arbitrary + * filesystem code. Lots of locks are held that can + * deadlock. Use an atomic copy to avoid deadlocking + * in page fault handling. + */ copied = copy_folio_from_iter_atomic(folio, offset, bytes, i); flush_dcache_folio(folio); @@ -4222,6 +4228,16 @@ retry: bytes = copied; goto retry; } + + /* + * 'folio' is now unlocked and faults on it can be + * handled. Ensure forward progress by trying to + * fault it in now. + */ + if (fault_in_iov_iter_readable(i, bytes) == bytes) { + status = -EFAULT; + break; + } } else { pos += status; written += status; |