Skip to content

fs: fix race between llseek SEEK_END and write

Eiichi Tsukata cluster-devel linux-btrfs linux-ext4 linux-f2fs-devel linux-fsdevel linux-unionfs 1 version In review

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 Latest4 patches 6 repliesIn review

Patches in v1 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/4vfs: fix race between llseek SEEK_END and writefs/btrfs/file.c fs/fuse/file.c fs/gfs2/file.c +2 more+42 -70 replies
2/4ext4: fix race between llseek SEEK_END and writefs/ext4/file.c+10 -00 replies
3/4f2fs: fix race between llseek SEEK_END and writefs/f2fs/file.c+1 -52 replies
4/4overlayfs: fix race between llseek SEEK_END and writefs/overlayfs/file.c+20 -30 replies

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

Cover letter [PATCH v1 0/4] fs: fix race between llseek SEEK_END and write

Some file systems (including ext4, xfs, ramfs ...) have the following problem as I've described in the commit message of the 1/4 patch.

The commit ef3d0fd27e90 ("vfs: do (nearly) lockless generic_file_llseek") removed almost all locks in llseek() including SEEK_END. It based on the idea that write() updates size atomically. But in fact, write() can be divided into two or more parts in generic_perform_write() when pos straddles over the PAGE_SIZE, which results in updating size multiple times in one write(). It means that llseek() can see the size being updated during write().

This race changes behavior of some applications. 'tail' is one of those applications. It reads range [pos, pos_end] where pos_end is obtained via llseek() SEEK_END. Sometimes, a read line could be broken.

reproducer:

    $ while true; do echo 123456 >> out; done
    $ while true; do tail out | grep -v 123456 ; done

example output(take 30 secs):

    12345
    1
    1234
    1
    12
    1234

Note: Some file systems which indivisually implements llseek() and hold
inode mutex lock in it are not affected. ex:) btrfs, ocfs2

Patch 1: re-implements inode lock for SEEK_END in generic_file_llseek() Patch 2 to 4: implement inode lock for SEEK_END in each file systems

Eiichi Tsukata (4):
vfs: fix race between llseek SEEK_END and write
ext4: fix race between llseek SEEK_END and write
f2fs: fix race between llseek SEEK_END and write
overlayfs: fix race between llseek SEEK_END and write

 fs/btrfs/file.c     |  2 +-
 fs/ext4/file.c      | 10 ++++++++++
 fs/f2fs/file.c      |  6 +-----
 fs/fuse/file.c      |  5 +++--
 fs/gfs2/file.c      |  3 ++-
 fs/overlayfs/file.c | 23 ++++++++++++++++++++---
 fs/read_write.c     | 37 ++++++++++++++++++++++++++++++++++---
 include/linux/fs.h  |  2 ++
 8 files changed, 73 insertions(+), 15 deletions(-)
Signature · 1 line
2.19.1