linux/fs
Nick Piggin b827e496c8 mm: close page_mkwrite races
Change page_mkwrite to allow implementations to return with the page
locked, and also change it's callers (in page fault paths) to hold the
lock until the page is marked dirty.  This allows the filesystem to have
full control of page dirtying events coming from the VM.

Rather than simply hold the page locked over the page_mkwrite call, we
call page_mkwrite with the page unlocked and allow callers to return with
it locked, so filesystems can avoid LOR conditions with page lock.

The problem with the current scheme is this: a filesystem that wants to
associate some metadata with a page as long as the page is dirty, will
perform this manipulation in its ->page_mkwrite.  It currently then must
return with the page unlocked and may not hold any other locks (according
to existing page_mkwrite convention).

In this window, the VM could write out the page, clearing page-dirty.  The
filesystem has no good way to detect that a dirty pte is about to be
attached, so it will happily write out the page, at which point, the
filesystem may manipulate the metadata to reflect that the page is no
longer dirty.

It is not always possible to perform the required metadata manipulation in
->set_page_dirty, because that function cannot block or fail.  The
filesystem may need to allocate some data structure, for example.

And the VM cannot mark the pte dirty before page_mkwrite, because
page_mkwrite is allowed to fail, so we must not allow any window where the
page could be written to if page_mkwrite does fail.

This solution of holding the page locked over the 3 critical operations
(page_mkwrite, setting the pte dirty, and finally setting the page dirty)
closes out races nicely, preventing page cleaning for writeout being
initiated in that window.  This provides the filesystem with a strong
synchronisation against the VM here.

- Sage needs this race closed for ceph filesystem.
- Trond for NFS (http://bugzilla.kernel.org/show_bug.cgi?id=12913).
- I need it for fsblock.
- I suspect other filesystems may need it too (eg. btrfs).
- I have converted buffer.c to the new locking. Even simple block allocation
  under dirty pages might be susceptible to i_size changing under partial page
  at the end of file (we also have a buffer.c-side problem here, but it cannot
  be fixed properly without this patch).
- Other filesystems (eg. NFS, maybe btrfs) will need to change their
  page_mkwrite functions themselves.

[ This also moves page_mkwrite another step closer to fault, which should
  eventually allow page_mkwrite to be moved into ->fault, and thus avoiding a
  filesystem calldown and page lock/unlock cycle in __do_fault. ]

[akpm@linux-foundation.org: fix derefs of NULL ->mapping]
Cc: Sage Weil <sage@newdream.net>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-05-02 15:36:09 -07:00
..
9p vfs: simple_set_mnt() should return void 2009-03-27 14:44:03 -04:00
adfs fs/adfs: return f_fsid for statfs(2) 2009-04-02 19:05:08 -07:00
affs fs/affs: return f_fsid for statfs(2) 2009-04-02 19:05:08 -07:00
afs AFS: Guard afs_file_readpage_read_complete() definition with CONFIG_AFS_FSCACHE 2009-04-17 09:55:19 -07:00
autofs Fix autofs_expire() 2009-04-20 23:01:15 -04:00
autofs4 autofs4: fix incorrect return in autofs4_mount_busy() 2009-05-02 15:36:09 -07:00
befs befs: fix build on parisc 2009-04-08 10:21:43 -07:00
bfs fs/Kconfig: move bfs out 2009-01-22 13:15:57 +03:00
btrfs Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable 2009-04-27 11:16:33 -07:00
cachefiles CacheFiles: A cache that backs onto a mounted filesystem 2009-04-03 16:42:41 +01:00
cifs cifs: when renaming don't try to unlink negative dentry 2009-04-17 21:08:15 +00:00
coda constify dentry_operations: misc filesystems 2009-03-27 14:44:00 -04:00
configfs constify dentry_operations: configfs 2009-03-27 14:44:03 -04:00
cramfs fs/cramfs: return f_fsid for statfs(2) 2009-04-02 19:05:08 -07:00
debugfs debugfs: function to know if debugfs is initialized 2009-03-23 16:25:46 +01:00
devpts Merge code for single and multiple-instance mounts 2009-03-27 14:44:04 -04:00
dlm dlm: fix length calculation in compat code 2009-03-11 12:23:59 -05:00
ecryptfs eCryptfs: Fix min function comparison warning 2009-04-27 13:31:12 -05:00
efs fs/efs: return f_fsid for statfs(2) 2009-04-02 19:05:09 -07:00
exofs exofs: Documentation 2009-03-31 19:44:38 +03:00
exportfs Merge branch 'next' into for-linus 2008-12-25 11:40:09 +11:00
ext2 ext2: missing unlock in ext2_quota_write() 2009-04-27 16:49:52 +02:00
ext3 ext3: Try to avoid starting a transaction in writepage for data=writepage 2009-04-08 13:15:10 -04:00
ext4 ext4: Do not try to validate extents on special files 2009-04-24 18:45:35 -04:00
fat vfat: Note the NLS requirement 2009-04-17 09:32:11 -07:00
freevxfs fs/Kconfig: move vxfs out 2009-01-22 13:15:58 +03:00
fscache FS-Cache: Implement data I/O part of netfs API 2009-04-03 16:42:39 +01:00
fuse fuse: fix "direct_io" private mmap 2009-04-09 17:37:53 +02:00
gfs2 GFS2: Ensure that the inode goal block settings are updated 2009-04-23 10:07:37 +01:00
hfs hfs: fix memory leak when unmounting 2009-04-13 15:04:29 -07:00
hfsplus Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6 2009-04-02 21:09:10 -07:00
hostfs constify dentry_operations: misc filesystems 2009-03-27 14:44:00 -04:00
hpfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6 2009-04-02 21:09:10 -07:00
hppfs hppfs: hppfs_read_file() may return -ERROR 2009-04-02 19:04:53 -07:00
hugetlbfs hugetlbfs: return negative error code for bad mount option 2009-04-21 13:41:48 -07:00
isofs fs/isofs: return f_fsid for statfs(2) 2009-04-02 19:05:09 -07:00
jbd Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 2009-04-24 08:37:40 -07:00
jbd2 jbd2: use SWRITE_SYNC_PLUG when writing synchronous revoke records 2009-04-14 07:50:56 -04:00
jffs2 Merge git://git.infradead.org/mtd-2.6 2009-04-06 14:56:26 -07:00
jfs New helper - current_umask() 2009-03-31 23:00:26 -04:00
lockd Merge branch 'for-2.6.30' of git://linux-nfs.org/~bfields/linux 2009-04-06 13:25:56 -07:00
minix fs/minix: return f_fsid for statfs(2) 2009-04-02 19:05:09 -07:00
ncpfs ncpfs: use memdup_user() 2009-04-20 23:02:51 -04:00
nfs NFS: Fix the XDR iovec calculation in nfs3_xdr_setaclargs 2009-04-21 07:46:49 -07:00
nfs_common SUNRPC: nfsacl_encode/nfsacl_decode should be exported as GPL-only 2008-12-23 15:21:32 -05:00
nfsd Fix i_mutex vs. readdir handling in nfsd 2009-04-20 23:01:16 -04:00
nilfs2 nilfs2: fix possible mismatch of sufile counters on recovery 2009-04-13 09:53:52 +09:00
nls
notify fs: avoid I_NEW inodes 2009-03-27 14:44:05 -04:00
ntfs ntfs: remove private wrapper of endian helpers 2009-04-01 08:59:18 -07:00
ocfs2 ocfs2: fix i_mutex locking in ocfs2_splice_to_file() 2009-04-15 12:10:12 +02:00
omfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6 2009-04-02 21:09:10 -07:00
openpromfs zero i_uid/i_gid on inode allocation 2009-01-05 11:54:28 -05:00
partitions Merge branch 'tracing/core-v2' into tracing-for-linus 2009-04-02 00:49:02 +02:00
proc [S390] /proc/stat idle field for idle cpus 2009-04-23 13:58:17 +02:00
qnx4 fs/qnx4: return f_fsid for statfs(2) 2009-04-02 19:05:10 -07:00
quota quota: remove obsolete comments in fs/quota/Makefile 2009-04-27 16:49:52 +02:00
ramfs ramfs: fix double freeing s_fs_info on failed mount 2009-04-07 07:39:59 -07:00
reiserfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6 2009-04-02 21:09:10 -07:00
romfs ROMFS: Advance destination buffer pointer when reading from a blockdev 2009-04-24 13:28:31 -07:00
smbfs constify dentry_operations: misc filesystems 2009-03-27 14:44:00 -04:00
squashfs Merge branch 'kmemtrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip 2009-04-06 13:30:00 -07:00
sysfs sysfs: use memdup_user() 2009-04-20 23:02:50 -04:00
sysv fs/sysv: return f_fsid for statfs(2) 2009-04-02 19:05:10 -07:00
ubifs Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6 2009-04-06 15:00:19 -07:00
udf udf: Don't write integrity descriptor too often 2009-04-02 13:36:28 +02:00
ufs fs/ufs: return f_fsid for statfs(2) 2009-04-02 19:05:10 -07:00
xfs xfs: use memdup_user() 2009-04-20 23:02:51 -04:00
aio.c aio: lookup_ioctx can return the wrong value when looking up a bogus context 2009-03-19 15:57:18 -07:00
anon_inodes.c constify dentry_operations: rest 2009-03-27 14:44:03 -04:00
attr.c vfs: Use lowercase names of quota functions 2009-03-26 02:18:35 +01:00
bad_inode.c kill ->dir_notify() 2008-12-31 18:07:43 -05:00
binfmt_aout.c sanitize ifdefs in binfmt_aout 2009-01-03 11:45:54 -08:00
binfmt_elf_fdpic.c bin_elf_fdpic: check the return value of clear_user 2009-04-02 19:05:01 -07:00
binfmt_elf.c Trim includes in binfmt_elf 2009-03-31 23:00:27 -04:00
binfmt_em86.c
binfmt_flat.c FLAT: Don't attempt to expand the userspace stack to fill the space allocated 2009-01-08 12:04:47 +00:00
binfmt_misc.c fs/binfmt_misc.c: add terminating newline to /proc/sys/fs/binfmt_misc/status 2009-01-06 15:59:19 -08:00
binfmt_script.c
binfmt_som.c Don't crap into descriptor table in binfmt_som 2009-03-31 23:00:28 -04:00
bio-integrity.c block: add private bio_set for bio integrity allocations 2009-03-24 12:35:17 +01:00
bio.c bio: fix memcpy corruption in bio_copy_user_iov() 2009-04-28 20:24:29 +02:00
block_dev.c Cleanup after commit 585d3bc06f 2009-04-01 07:07:16 -04:00
buffer.c mm: close page_mkwrite races 2009-05-02 15:36:09 -07:00
char_dev.c fs: fix name overwrite in __register_chrdev_region() 2009-01-06 15:59:13 -08:00
compat_binfmt_elf.c
compat_ioctl.c fs/compat_ioctl: fix build when !BLOCK 2009-04-20 23:01:16 -04:00
compat.c do_execve() must not clear fs->in_exec if it was set by another thread 2009-04-24 07:39:45 -07:00
dcache.c No need for crossing to mountpoint in audit_tag_tree() 2009-04-20 23:01:15 -04:00
dcookies.c [CVE-2009-0029] System call wrapper special cases 2009-01-14 14:15:18 +01:00
direct-io.c dio: Remove code handling bio_alloc failure with __GFP_WAIT 2009-04-15 12:10:13 +02:00
drop_caches.c vfs: skip I_CLEAR state inodes 2009-04-02 19:04:48 -07:00
eventfd.c epoll keyed wakeups: make eventfd use keyed wakeups 2009-04-01 08:59:20 -07:00
eventpoll.c epoll keyed wakeups: teach epoll about hints coming with the wakeup key 2009-04-01 08:59:20 -07:00
exec.c check_unsafe_exec: s/lock_task_sighand/rcu_read_lock/ 2009-04-24 07:39:45 -07:00
fcntl.c Fix a lockdep warning in fasync_helper() 2009-03-30 08:00:24 -06:00
fifo.c
file_table.c trivial: remove unused variable 'path' in alloc_file() 2009-03-30 15:22:03 +02:00
file.c
filesystems.c fs: Mark get_filesystem_list() as __init function. 2009-04-20 23:02:52 -04:00
fs_struct.c Get rid of indirect include of fs_struct.h 2009-03-31 23:00:27 -04:00
fs-writeback.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2009-04-03 15:24:35 -07:00
generic_acl.c New helper - current_umask() 2009-03-31 23:00:26 -04:00
inode.c splice: add helpers for locking pipe inode 2009-04-15 12:10:12 +02:00
internal.h New locking/refcounting for fs_struct 2009-03-31 23:00:26 -04:00
ioctl.c Rationalize fasync return values 2009-03-16 08:34:35 -06:00
ioprio.c [CVE-2009-0029] System call wrappers part 28 2009-01-14 14:15:30 +01:00
Kconfig nilfs2: update makefile and Kconfig 2009-04-07 08:31:16 -07:00
Kconfig.binfmt CORE_DUMP_DEFAULT_ELF_HEADERS depends on ELF_CORE 2009-01-09 16:54:41 -08:00
libfs.c kmemtrace, fs: uninline simple_transaction_set() 2009-04-03 12:09:09 +02:00
locks.c [CVE-2009-0029] System call wrappers part 16 2009-01-14 14:15:25 +01:00
Makefile nilfs2: update makefile and Kconfig 2009-04-07 08:31:16 -07:00
mbcache.c
mpage.c Remove two unneeded exports and make two symbols static in fs/mpage.c 2009-04-01 07:38:54 -04:00
namei.c Fix i_mutex vs. readdir handling in nfsd 2009-04-20 23:01:16 -04:00
namespace.c Touch all affected namespaces on propagation of mount 2009-04-20 23:01:15 -04:00
nfsctl.c [CVE-2009-0029] System call wrappers part 27 2009-01-14 14:15:29 +01:00
no-block.c
open.c Get rid of indirect include of fs_struct.h 2009-03-31 23:00:27 -04:00
pipe.c splice: add helpers for locking pipe inode 2009-04-15 12:10:12 +02:00
pnode.c
pnode.h
posix_acl.c CRED: Wrap task credential accesses in the filesystem subsystem 2008-11-14 10:39:05 +11:00
read_write.c Make non-compat preadv/pwritev use native register size 2009-04-04 14:20:34 -07:00
read_write.h
readdir.c [CVE-2009-0029] System call wrappers part 32 2009-01-14 14:15:31 +01:00
select.c [CVE-2009-0029] System call wrappers part 32 2009-01-14 14:15:31 +01:00
seq_file.c cpumask: fix seq_bitmap_*() functions. 2009-03-30 22:05:11 +10:30
signalfd.c [CVE-2009-0029] System call wrappers part 31 2009-01-14 14:15:31 +01:00
splice.c splice: fix new kernel-doc warnings 2009-04-17 07:38:07 -07:00
stack.c
stat.c kill vfs_stat_fd / vfs_lstat_fd 2009-04-20 23:02:52 -04:00
super.c namespaces: move proc_net_get_sb to a generic fs/super.c helper 2009-04-07 08:31:09 -07:00
sync.c Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6 2009-03-27 14:48:34 -07:00
timerfd.c timerfd: add flags check 2009-02-18 15:37:53 -08:00
utimes.c [CVE-2009-0029] System call wrappers part 30 2009-01-14 14:15:30 +01:00
xattr_acl.c
xattr.c xattr: use memdup_user() 2009-04-20 23:02:50 -04:00