diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2006-09-26 02:30:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:44 -0400 |
commit | d08b3851da41d0ee60851f2c75b118e1f7a5fc89 (patch) | |
tree | a01f6930a1387e8f66607e2fe16c62bb7044353b /mm/mprotect.c | |
parent | 725d704ecaca4a43f067092c140d4f3271cf2856 (diff) |
[PATCH] mm: tracking shared dirty pages
Tracking of dirty pages in shared writeable mmap()s.
The idea is simple: write protect clean shared writeable pages, catch the
write-fault, make writeable and set dirty. On page write-back clean all the
PTE dirty bits and write protect them once again.
The implementation is a tad harder, mainly because the default
backing_dev_info capabilities were too loosely maintained. Hence it is not
enough to test the backing_dev_info for cap_account_dirty.
The current heuristic is as follows, a VMA is eligible when:
- its shared writeable
(vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)
- it is not a 'special' mapping
(vm_flags & (VM_PFNMAP|VM_INSERTPAGE)) == 0
- the backing_dev_info is cap_account_dirty
mapping_cap_account_dirty(vma->vm_file->f_mapping)
- f_op->mmap() didn't change the default page protection
Page from remap_pfn_range() are explicitly excluded because their COW
semantics are already horrid enough (see vm_normal_page() in do_wp_page()) and
because they don't have a backing store anyway.
mprotect() is taught about the new behaviour as well. However it overrides
the last condition.
Cleaning the pages on write-back is done with page_mkclean() a new rmap call.
It can be called on any page, but is currently only implemented for mapped
pages, if the page is found the be of a VMA that accounts dirty pages it will
also wrprotect the PTE.
Finally, in fs/buffers.c:try_to_free_buffers(); remove clear_page_dirty() from
under ->private_lock. This seems to be safe, since ->private_lock is used to
serialize access to the buffers, not the page itself. This is needed because
clear_page_dirty() will call into page_mkclean() and would thereby violate
locking order.
[dhowells@redhat.com: Provide a page_mkclean() implementation for NOMMU]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/mprotect.c')
-rw-r--r-- | mm/mprotect.c | 21 |
1 files changed, 8 insertions, 13 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c index 638edabaff7..367b7f6c063 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -123,8 +123,6 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, | |||
123 | unsigned long oldflags = vma->vm_flags; | 123 | unsigned long oldflags = vma->vm_flags; |
124 | long nrpages = (end - start) >> PAGE_SHIFT; | 124 | long nrpages = (end - start) >> PAGE_SHIFT; |
125 | unsigned long charged = 0; | 125 | unsigned long charged = 0; |
126 | unsigned int mask; | ||
127 | pgprot_t newprot; | ||
128 | pgoff_t pgoff; | 126 | pgoff_t pgoff; |
129 | int error; | 127 | int error; |
130 | 128 | ||
@@ -176,24 +174,21 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, | |||
176 | } | 174 | } |
177 | 175 | ||
178 | success: | 176 | success: |
179 | /* Don't make the VMA automatically writable if it's shared, but the | ||
180 | * backer wishes to know when pages are first written to */ | ||
181 | mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED; | ||
182 | if (vma->vm_ops && vma->vm_ops->page_mkwrite) | ||
183 | mask &= ~VM_SHARED; | ||
184 | |||
185 | newprot = protection_map[newflags & mask]; | ||
186 | |||
187 | /* | 177 | /* |
188 | * vm_flags and vm_page_prot are protected by the mmap_sem | 178 | * vm_flags and vm_page_prot are protected by the mmap_sem |
189 | * held in write mode. | 179 | * held in write mode. |
190 | */ | 180 | */ |
191 | vma->vm_flags = newflags; | 181 | vma->vm_flags = newflags; |
192 | vma->vm_page_prot = newprot; | 182 | vma->vm_page_prot = protection_map[newflags & |
183 | (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; | ||
184 | if (vma_wants_writenotify(vma)) | ||
185 | vma->vm_page_prot = protection_map[newflags & | ||
186 | (VM_READ|VM_WRITE|VM_EXEC)]; | ||
187 | |||
193 | if (is_vm_hugetlb_page(vma)) | 188 | if (is_vm_hugetlb_page(vma)) |
194 | hugetlb_change_protection(vma, start, end, newprot); | 189 | hugetlb_change_protection(vma, start, end, vma->vm_page_prot); |
195 | else | 190 | else |
196 | change_protection(vma, start, end, newprot); | 191 | change_protection(vma, start, end, vma->vm_page_prot); |
197 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); | 192 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); |
198 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); | 193 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); |
199 | return 0; | 194 | return 0; |