Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
From: Mike Rapoport
Date: Tue Oct 27 2026 - 04:17:15 EST
On Tue, Oct 27, 2026 at 12:17:24AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@xxxxxxxxxxxxxx>
>
> Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
> read(), write() and lseek() on a shared open file description of a regular
> file serialize on ->f_pos_lock. The flag that asks for it,
> FMODE_ATOMIC_POS, is set in do_dentry_open(). A memfd is a regular file
> too, but its struct file comes from alloc_file_pseudo() and never passes
> through do_dentry_open(), so it does not get the flag:
>
> CPU0 CPU1
> write(memfd, "a", 1) write(memfd, "b", 1)
> pos = file->f_pos (= 0)
> pos = file->f_pos (= 0)
> vfs_write(..., &pos)
> vfs_write(..., &pos)
> file->f_pos = pos (= 1)
> file->f_pos = pos (= 1)
>
> One of the two bytes is overwritten. Two threads writing 100000 bytes
> each, one at a time, to a memfd end up with a file that is far shorter than
> 200000 bytes, while the same program on a tmpfs file never loses a byte.
>
> Set the flag when the memfd is created. As for any other regular file the
> lock is only taken if the file is reachable in more than one way, and
> nothing a memfd does in read or write waits for another operation on the
> same file. This cannot be done for all alloc_file_pseudo() files: anon
> inode files such as eventfd are S_IFREG as well, and a blocked read holding
> ->f_pos_lock would lock out the write that is supposed to wake it.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
> ---
> mm/memfd.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 7d2da23157003..6f5fbce74f21e 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -484,6 +484,8 @@ struct file *memfd_alloc_file(const char *name, unsigned int flags)
> }
>
> file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
> + /* a regular file like any other: POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
> + file->f_mode |= FMODE_ATOMIC_POS;
> file->f_flags |= O_LARGEFILE;
>
> if (flags & MFD_NOEXEC_SEAL) {
>
> --
> 2.43.0
>
--
Sincerely yours,
Mike.