linux/fs
Nick Piggin d00806b183 mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.

Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.

The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache.  Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.

The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.

Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).

Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size.  do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size).  The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data.  Valid mappings to the same
place will see a different page.

Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit.  He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight.  However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit.  Scalability is not an issue.

This patch implements this latter approach.  ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so).  do_no_page only unlocks the page after setting up the mapping
completely.  invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).

This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 10:04:41 -07:00
..
9p 9p: fix debug compilation error 2007-07-16 16:03:25 -05:00
adfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
affs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
afs AFS: drop explicit extern 2007-07-16 09:05:43 -07:00
autofs Replace pid_t in autofs with struct pid reference 2007-05-11 08:29:36 -07:00
autofs4 Fix some coding-style errors in autofs 2007-05-11 08:29:36 -07:00
befs Remove SLAB_CTOR_CONSTRUCTOR 2007-05-17 05:23:04 -07:00
bfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
cifs Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6 2007-07-19 00:38:57 +00:00
coda wrong order of arguments of ->readdir() 2007-07-15 16:40:51 -07:00
configfs configfs: config item dependancies. 2007-07-10 17:18:59 -07:00
cramfs mm: make read_cache_page synchronous 2007-05-07 12:12:51 -07:00
debugfs debugfs: remove rmdir() non-empty complaint 2007-07-18 15:49:48 -07:00
devpts devpts: add fsnotify create event 2007-05-08 11:14:59 -07:00
dlm configfs: Convert subsystem semaphore to mutex 2007-07-10 17:10:56 -07:00
ecryptfs Couple fixes to fs/ecryptfs/inode.c 2007-07-17 10:23:08 -07:00
efs knfsd: exportfs: remove iget abuse 2007-07-17 10:23:06 -07:00
exportfs knfsd: exportfs: split out reconnecting a dentry from find_exported_dentry 2007-07-17 10:23:06 -07:00
ext2 Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
ext3 Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
ext4 ext4: extent macros cleanup 2007-07-18 09:09:15 -04:00
fat knfsd: exportfs: add exportfs.h header 2007-07-17 10:23:06 -07:00
freevxfs vxfs warning fixes 2007-07-16 09:05:41 -07:00
fuse sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
gfs2 mm: fix fault vs invalidate race for linear mappings 2007-07-19 10:04:41 -07:00
hfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
hfsplus Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
hostfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
hpfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
hppfs [PATCH] Mark struct super_operations const 2007-02-12 09:48:47 -08:00
hugetlbfs hugetlbfs: handle empty options string 2007-07-16 09:05:46 -07:00
isofs knfsd: exportfs: add exportfs.h header 2007-07-17 10:23:06 -07:00
jbd is_power_of_2(): jbd 2007-07-16 09:05:48 -07:00
jbd2 jbd2: Move jbd2-debug file to debugfs 2007-07-18 08:50:18 -04:00
jffs2 Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
jfs Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
lockd knfsd: lockd: nfsd4: use same grace period for lockd and nfsd4 2007-07-17 10:23:07 -07:00
minix sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
msdos [PATCH] mark struct inode_operations const 2 2007-02-12 09:48:46 -08:00
ncpfs mm: fix fault vs invalidate race for linear mappings 2007-07-19 10:04:41 -07:00
nfs locks: make posix_test_lock() interface more consistent 2007-07-18 19:17:19 -04:00
nfs_common [PATCH] nfs_common endianness annotations 2006-10-20 10:26:41 -07:00
nfsd locks: rename lease functions to reflect locks.c conventions 2007-07-18 19:14:12 -04:00
nls NLS: Remove obsolete Makefile entries 2007-07-16 09:05:52 -07:00
ntfs knfsd: exportfs: add exportfs.h header 2007-07-17 10:23:06 -07:00
ocfs2 mm: fix fault vs invalidate race for linear mappings 2007-07-19 10:04:41 -07:00
openpromfs Remove SLAB_CTOR_CONSTRUCTOR 2007-05-17 05:23:04 -07:00
partitions Fix LDM for new field in the VOL5 VBLK. 2007-07-16 12:01:30 -07:00
proc kallsyms: make KSYM_NAME_LEN include space for trailing '\0' 2007-07-17 10:23:03 -07:00
qnx4 sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
ramfs Add __GFP_MOVABLE for callers to flag allocations from high memory that may be migrated 2007-07-17 10:22:59 -07:00
reiserfs Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
romfs Remove SLAB_CTOR_CONSTRUCTOR 2007-05-17 05:23:04 -07:00
smbfs sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
sysfs sysfs: cosmetic clean up on node creation failure paths 2007-07-18 15:49:50 -07:00
sysv sendfile: remove .sendfile from filesystems that use generic_file_sendfile() 2007-07-10 08:04:13 +02:00
udf arch/i386/* fs/* ipc/*: mark variables with uninitialized_var() 2007-07-17 16:23:19 -04:00
ufs is_power_of_2: ufs/super.c 2007-07-16 09:05:50 -07:00
vfat [PATCH] mark struct inode_operations const 3 2007-02-12 09:48:46 -08:00
xfs mm: fix fault vs invalidate race for linear mappings 2007-07-19 10:04:41 -07:00
Kconfig jbd2: Move jbd2-debug file to debugfs 2007-07-18 08:50:18 -04:00
Kconfig.binfmt fs: Kill sh dependency for binfmt_flat. 2007-05-21 14:34:00 +09:00
Makefile signal/timer/event: eventfd core 2007-05-11 08:29:36 -07:00
aio.c signal/timer/event: KAIO eventfd support example 2007-05-11 08:29:37 -07:00
anon_inodes.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm 2007-07-17 11:50:26 -07:00
attr.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
bad_inode.c sendfile: remove bad_sendfile() from bad_file_ops 2007-07-10 08:04:15 +02:00
binfmt_aout.c [PATCH] VFS: change struct file to use struct path 2006-12-08 08:28:41 -08:00
binfmt_elf.c binfmt_elf warning fix 2007-07-16 09:05:47 -07:00
binfmt_elf_fdpic.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_em86.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_flat.c nommu: report correct errno in message 2007-06-08 17:23:32 -07:00
binfmt_misc.c Detach sched.h from mm.h 2007-05-21 09:18:19 -07:00
binfmt_script.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_som.c [PARISC] Fix fs/binfmt_som.c 2006-10-04 06:51:26 -06:00
bio.c unexport bio_{,un}map_user 2007-07-10 08:03:34 +02:00
block_dev.c bd_claim_by_disk: fix warning 2007-07-16 09:05:50 -07:00
buffer.c fs: introduce some page/buffer invariants 2007-07-17 10:23:02 -07:00
char_dev.c [PATCH] remove protection of LANANA-reserved majors 2007-04-04 21:12:47 -07:00
compat.c optimize compat_core_sys_select() by a using stack space for small fd sets 2007-05-23 20:14:12 -07:00
compat_ioctl.c compat32: ignore the LOOP_CLR_FD ioctl 2007-07-16 09:05:52 -07:00
dcache.c mm: clean up and kernelify shrinker registration 2007-07-17 10:23:00 -07:00
dcookies.c [PATCH] slab: remove kmem_cache_t 2006-12-07 08:39:25 -08:00
direct-io.c dio: remove bogus refcounting BUG_ON 2007-07-03 18:23:23 -07:00
dnotify.c [PATCH] VFS: change struct file to use struct path 2006-12-08 08:28:41 -08:00
dquot.c mm: clean up and kernelify shrinker registration 2007-07-17 10:23:00 -07:00
drop_caches.c invalidate_mapping_pages(): add cond_resched 2007-07-16 09:05:36 -07:00
eventfd.c eventfd use waitqueue lock ... 2007-05-18 13:09:34 -07:00
eventpoll.c epoll: move kfree inside ep_free 2007-05-15 08:54:00 -07:00
exec.c uselib: add missing MNT_NOEXEC check 2007-05-23 20:14:13 -07:00
fcntl.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
fifo.c Detach sched.h from mm.h 2007-05-21 09:18:19 -07:00
file.c [PATCH] fdtable: Provide free_fdtable() wrapper 2006-12-22 08:55:50 -08:00
file_table.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
filesystems.c add filesystem subtype support 2007-05-08 11:15:01 -07:00
fs-writeback.c Write back inode data pages even when the inode itself is locked 2007-01-26 12:53:20 -08:00
generic_acl.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
inode.c mm: clean up and kernelify shrinker registration 2007-07-17 10:23:00 -07:00
inotify.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
inotify_user.c [PATCH] inotify: read return val fix 2007-02-12 09:48:28 -08:00
internal.h cleanup compat ioctl handling 2007-05-08 11:15:09 -07:00
ioctl.c drop obsolete sys_ioctl export 2007-07-16 09:05:48 -07:00
ioprio.c [PATCH] pid: replace do/while_each_task_pid with do/while_each_pid_task 2007-02-12 09:48:32 -08:00
libfs.c fs/libfs.c: >80 columns line break fix 2007-05-09 06:44:57 +02:00
locks.c locks: fix vfs_test_lock() comment 2007-07-18 19:17:19 -04:00
mbcache.c mm: clean up and kernelify shrinker registration 2007-07-17 10:23:00 -07:00
mpage.c consolidate generic_writepages and mpage_writepages 2007-05-11 08:29:35 -07:00
namei.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
namespace.c fs/namespace.c should #include "internal.h" 2007-07-16 09:05:50 -07:00
nfsctl.c Remove obsolete #include <linux/config.h> 2006-06-30 19:25:36 +02:00
no-block.c [PATCH] BLOCK: Make it possible to disable the block layer [try #6] 2006-09-30 20:52:31 +02:00
open.c sys_fallocate() implementation on i386, x86_64 and powerpc 2007-07-17 21:42:44 -04:00
pipe.c pipe: add documentation and comments 2007-07-10 08:04:16 +02:00
pnode.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
pnode.h [PATCH] rename struct namespace to struct mnt_namespace 2006-12-08 08:28:51 -08:00
posix_acl.c [PATCH] kmemdup: some users 2006-10-01 00:39:19 -07:00
quota.c diskquota: 32bit quota tools on 64bit architectures 2007-07-16 09:05:48 -07:00
quota_v1.c
quota_v2.c
read_write.c Remove remnants of sendfile() 2007-07-10 08:04:15 +02:00
read_write.h [PATCH] Remove readv/writev methods and use aio_read/aio_write instead 2006-10-01 00:39:28 -07:00
readdir.c ROUND_UP macro cleanup in fs/(select|compat|readdir).c 2007-05-08 11:15:09 -07:00
select.c Style fix in fs/select.c 2007-05-09 07:10:02 +02:00
seq_file.c seq_file: more atomicity in traverse() 2007-07-16 09:05:45 -07:00
signalfd.c avoid spurious POLLIN returns in signalfd 2007-06-28 11:34:54 -07:00
splice.c splice: direct splicing updates ppos twice 2007-07-16 15:02:48 +02:00
stack.c [PATCH] fs/stack.c: Copy i_nlink after all other attributes are copied 2007-02-19 14:21:50 -08:00
stat.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
super.c hugetlbfs: handle empty options string 2007-07-16 09:05:46 -07:00
sync.c Introduce fixed sys_sync_file_range2() syscall, implement on PowerPC and ARM 2007-06-28 11:38:30 -07:00
timerfd.c timerfd use waitqueue lock ... 2007-05-18 13:09:34 -07:00
utimes.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
xattr.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
xattr_acl.c [PATCH] remove many unneeded #includes of sched.h 2007-02-14 08:09:54 -08:00