]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
vfs: fix data corruption when blocksize < pagesize for mmaped data
authorJan Kara <jack@suse.cz>
Thu, 2 Oct 2014 01:49:18 +0000 (21:49 -0400)
committerJiri Slaby <jslaby@suse.cz>
Thu, 13 Nov 2014 18:02:11 +0000 (19:02 +0100)
commit3976690344783e5da7438e52fc2cd16529ddc1b5
tree5ac19b009257b46879d01b9bef1ad6fe2bce96f7
parent4f111bbc16e4d6c657c8f53f50d7a9cfa7f37e4f
vfs: fix data corruption when blocksize < pagesize for mmaped data

commit 90a8020278c1598fafd071736a0846b38510309c upstream.

->page_mkwrite() is used by filesystems to allocate blocks under a page
which is becoming writeably mmapped in some process' address space. This
allows a filesystem to return a page fault if there is not enough space
available, user exceeds quota or similar problem happens, rather than
silently discarding data later when writepage is called.

However VFS fails to call ->page_mkwrite() in all the cases where
filesystems need it when blocksize < pagesize. For example when
blocksize = 1024, pagesize = 4096 the following is problematic:
  ftruncate(fd, 0);
  pwrite(fd, buf, 1024, 0);
  map = mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0);
  map[0] = 'a';       ----> page_mkwrite() for index 0 is called
  ftruncate(fd, 10000); /* or even pwrite(fd, buf, 1, 10000) */
  mremap(map, 1024, 10000, 0);
  map[4095] = 'a';    ----> no page_mkwrite() called

At the moment ->page_mkwrite() is called, filesystem can allocate only
one block for the page because i_size == 1024. Otherwise it would create
blocks beyond i_size which is generally undesirable. But later at
->writepage() time, we also need to store data at offset 4095 but we
don't have block allocated for it.

This patch introduces a helper function filesystems can use to have
->page_mkwrite() called at all the necessary moments.

Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
fs/buffer.c
include/linux/mm.h
mm/truncate.c