Commit b37e39b0 authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

[PATCH] vmtrunc: truncate_count not atomic

Why is mapping->truncate_count atomic?  It's incremented inside i_mmap_lock
(and i_sem), and the reads don't need it to be atomic.

And why smp_rmb() before call to ->nopage?  The compiler cannot reorder the
initial assignment of sequence after the call to ->nopage, and no cpu (yet!)
can read from the future, which is all that matters there.

And delete totally bogus reset of truncate_count from blkmtd add_device.
truncate_count is all about detecting i_size changes: i_size does not change
there; and if it did, the count should be incremented not reset.
Signed-off-by: default avatarHugh Dickins <hugh@veritas.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent de146a08
...@@ -661,7 +661,6 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size ...@@ -661,7 +661,6 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size
memset(dev, 0, sizeof(struct blkmtd_dev)); memset(dev, 0, sizeof(struct blkmtd_dev));
dev->blkdev = bdev; dev->blkdev = bdev;
atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
if(!readonly) { if(!readonly) {
init_MUTEX(&dev->wrbuf_mutex); init_MUTEX(&dev->wrbuf_mutex);
} }
......
...@@ -198,7 +198,6 @@ void inode_init_once(struct inode *inode) ...@@ -198,7 +198,6 @@ void inode_init_once(struct inode *inode)
INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
spin_lock_init(&inode->i_data.tree_lock); spin_lock_init(&inode->i_data.tree_lock);
spin_lock_init(&inode->i_data.i_mmap_lock); spin_lock_init(&inode->i_data.i_mmap_lock);
atomic_set(&inode->i_data.truncate_count, 0);
INIT_LIST_HEAD(&inode->i_data.private_list); INIT_LIST_HEAD(&inode->i_data.private_list);
spin_lock_init(&inode->i_data.private_lock); spin_lock_init(&inode->i_data.private_lock);
INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap); INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
......
...@@ -341,7 +341,7 @@ struct address_space { ...@@ -341,7 +341,7 @@ struct address_space {
struct prio_tree_root i_mmap; /* tree of private and shared mappings */ struct prio_tree_root i_mmap; /* tree of private and shared mappings */
struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
spinlock_t i_mmap_lock; /* protect tree, count, list */ spinlock_t i_mmap_lock; /* protect tree, count, list */
atomic_t truncate_count; /* Cover race condition with truncate */ unsigned int truncate_count; /* Cover race condition with truncate */
unsigned long nrpages; /* number of total pages */ unsigned long nrpages; /* number of total pages */
pgoff_t writeback_index;/* writeback starts here */ pgoff_t writeback_index;/* writeback starts here */
struct address_space_operations *a_ops; /* methods */ struct address_space_operations *a_ops; /* methods */
......
...@@ -1424,7 +1424,7 @@ void unmap_mapping_range(struct address_space *mapping, ...@@ -1424,7 +1424,7 @@ void unmap_mapping_range(struct address_space *mapping,
spin_lock(&mapping->i_mmap_lock); spin_lock(&mapping->i_mmap_lock);
/* Protect against page fault */ /* Protect against page fault */
atomic_inc(&mapping->truncate_count); mapping->truncate_count++;
if (unlikely(!prio_tree_empty(&mapping->i_mmap))) if (unlikely(!prio_tree_empty(&mapping->i_mmap)))
unmap_mapping_range_list(&mapping->i_mmap, &details); unmap_mapping_range_list(&mapping->i_mmap, &details);
...@@ -1726,7 +1726,7 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -1726,7 +1726,7 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
struct page * new_page; struct page * new_page;
struct address_space *mapping = NULL; struct address_space *mapping = NULL;
pte_t entry; pte_t entry;
int sequence = 0; unsigned int sequence = 0;
int ret = VM_FAULT_MINOR; int ret = VM_FAULT_MINOR;
int anon = 0; int anon = 0;
...@@ -1738,9 +1738,8 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -1738,9 +1738,8 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
if (vma->vm_file) { if (vma->vm_file) {
mapping = vma->vm_file->f_mapping; mapping = vma->vm_file->f_mapping;
sequence = atomic_read(&mapping->truncate_count); sequence = mapping->truncate_count;
} }
smp_rmb(); /* Prevent CPU from reordering lock-free ->nopage() */
retry: retry:
cond_resched(); cond_resched();
new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret); new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
...@@ -1774,9 +1773,8 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -1774,9 +1773,8 @@ do_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
* invalidated this page. If unmap_mapping_range got called, * invalidated this page. If unmap_mapping_range got called,
* retry getting the page. * retry getting the page.
*/ */
if (mapping && if (mapping && unlikely(sequence != mapping->truncate_count)) {
(unlikely(sequence != atomic_read(&mapping->truncate_count)))) { sequence = mapping->truncate_count;
sequence = atomic_read(&mapping->truncate_count);
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
page_cache_release(new_page); page_cache_release(new_page);
goto retry; goto retry;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment