Force file times update at the next write reference after calling the msync() system call with the MS_ASYNC flag.
Signed-off-by: Anton Salikhmetov <[EMAIL PROTECTED]> --- mm/msync.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 82 insertions(+), 10 deletions(-) diff --git a/mm/msync.c b/mm/msync.c index 60efa36..87f990e 100644 --- a/mm/msync.c +++ b/mm/msync.c @@ -5,6 +5,7 @@ * Copyright (C) 2008 Anton Salikhmetov <[EMAIL PROTECTED]> */ +#include <asm/tlbflush.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/mm.h> @@ -12,6 +13,73 @@ #include <linux/sched.h> #include <linux/syscalls.h> +static void vma_wrprotect_pmd_range(struct vm_area_struct *vma, pmd_t *pmd, + unsigned long start, unsigned long end) +{ + while (start < end) { + spinlock_t *ptl; + pte_t *pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl); + + if (pte_dirty(*pte) && pte_write(*pte)) { + pte_t entry = ptep_clear_flush(vma, start, pte); + + entry = pte_wrprotect(entry); + set_pte_at(vma->vm_mm, start, pte, entry); + } + + pte_unmap_unlock(pte, ptl); + start += PAGE_SIZE; + } +} + +static void vma_wrprotect_pud_range(struct vm_area_struct *vma, pud_t *pud, + unsigned long start, unsigned long end) +{ + pmd_t *pmd = pmd_offset(pud, start); + + while (start < end) { + unsigned long next = pmd_addr_end(start, end); + + if (!pmd_none_or_clear_bad(pmd)) + vma_wrprotect_pmd_range(vma, pmd, start, next); + + ++pmd; + start = next; + } +} + +static void vma_wrprotect_pgd_range(struct vm_area_struct *vma, pgd_t *pgd, + unsigned long start, unsigned long end) +{ + pud_t *pud = pud_offset(pgd, start); + + while (start < end) { + unsigned long next = pud_addr_end(start, end); + + if (!pud_none_or_clear_bad(pud)) + vma_wrprotect_pud_range(vma, pud, start, next); + + ++pud; + start = next; + } +} + +static void vma_wrprotect(struct vm_area_struct *vma) +{ + unsigned long addr = vma->vm_start; + pgd_t *pgd = pgd_offset(vma->vm_mm, addr); + + while (addr < vma->vm_end) { + unsigned long next = pgd_addr_end(addr, vma->vm_end); + + if (!pgd_none_or_clear_bad(pgd)) + vma_wrprotect_pgd_range(vma, pgd, addr, next); + + ++pgd; + addr = next; + } +} + /* * MS_SYNC syncs the entire file - including mappings. * @@ -78,16 +146,20 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) error = 0; start = vma->vm_end; file = vma->vm_file; - if (file && (vma->vm_flags & VM_SHARED) && (flags & MS_SYNC)) { - get_file(file); - up_read(&mm->mmap_sem); - error = do_fsync(file, 0); - fput(file); - if (error || start >= end) - goto out; - down_read(&mm->mmap_sem); - vma = find_vma(mm, start); - continue; + if (file && (vma->vm_flags & VM_SHARED)) { + if ((flags & MS_ASYNC)) + vma_wrprotect(vma); + if (flags & MS_SYNC) { + get_file(file); + up_read(&mm->mmap_sem); + error = do_fsync(file, 0); + fput(file); + if (error || start >= end) + goto out; + down_read(&mm->mmap_sem); + vma = find_vma(mm, start); + continue; + } } vma = vma->vm_next; -- 1.4.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/