[PATCH] Make msync update atime and possibly ctime/mtime

From: Alexander Nyberg
Date: Sun Dec 05 2004 - 14:00:02 EST


There's an issue that doing the sequence of
open; mmap; change file; possibly msync; munmap; close;

I know this is still a problem if the user doesn't do msync,
but I have not yet figured out a good way to do it without msync.
This should help us a bit on the way.

http://www.opengroup.org/onlinepubs/007908799/xsh/msync.html says that:
"If msync() causes any write to a file, the file's st_ctime and
st_mtime fields are marked for update."

I think it makes a good time to update the atime of the file
aswell as it won't get done anywhere else.



Signed-off-by: Alexander Nyberg <alexn@xxxxxxxxx>

===== mm/msync.c 1.19 vs edited =====
--- 1.19/mm/msync.c 2004-10-19 07:26:38 +02:00
+++ edited/mm/msync.c 2004-12-04 22:48:54 +01:00
@@ -27,15 +27,16 @@ static int filemap_sync_pte(pte_t *ptep,
pte_t pte = *ptep;
unsigned long pfn = pte_pfn(pte);
struct page *page;
+ int dirty = 0;

if (pte_present(pte) && pfn_valid(pfn)) {
page = pfn_to_page(pfn);
if (!PageReserved(page) &&
- (ptep_clear_flush_dirty(vma, address, ptep) ||
+ ((dirty = ptep_clear_flush_dirty(vma, address, ptep)) ||
page_test_and_clear_dirty(page)))
set_page_dirty(page);
}
- return 0;
+ return dirty;
}

static int filemap_sync_pte_range(pmd_t * pmd,
@@ -43,7 +44,7 @@ static int filemap_sync_pte_range(pmd_t
struct vm_area_struct *vma, unsigned int flags)
{
pte_t *pte;
- int error;
+ int dirty = 0;

if (pmd_none(*pmd))
return 0;
@@ -55,16 +56,16 @@ static int filemap_sync_pte_range(pmd_t
pte = pte_offset_map(pmd, address);
if ((address & PMD_MASK) != (end & PMD_MASK))
end = (address & PMD_MASK) + PMD_SIZE;
- error = 0;
+
do {
- error |= filemap_sync_pte(pte, vma, address, flags);
+ dirty |= filemap_sync_pte(pte, vma, address, flags);
address += PAGE_SIZE;
pte++;
} while (address && (address < end));

pte_unmap(pte - 1);

- return error;
+ return dirty;
}

static inline int filemap_sync_pmd_range(pgd_t * pgd,
@@ -72,7 +73,7 @@ static inline int filemap_sync_pmd_range
struct vm_area_struct *vma, unsigned int flags)
{
pmd_t * pmd;
- int error;
+ int dirty = 0;

if (pgd_none(*pgd))
return 0;
@@ -84,13 +85,13 @@ static inline int filemap_sync_pmd_range
pmd = pmd_offset(pgd, address);
if ((address & PGDIR_MASK) != (end & PGDIR_MASK))
end = (address & PGDIR_MASK) + PGDIR_SIZE;
- error = 0;
+
do {
- error |= filemap_sync_pte_range(pmd, address, end, vma, flags);
+ dirty |= filemap_sync_pte_range(pmd, address, end, vma, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
- return error;
+ return dirty;
}

static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
@@ -98,7 +99,7 @@ static int filemap_sync(struct vm_area_s
{
pgd_t * dir;
unsigned long end = address + size;
- int error = 0;
+ int dirty = 0;

/* Aquire the lock early; it may be possible to avoid dropping
* and reaquiring it repeatedly.
@@ -117,7 +118,7 @@ static int filemap_sync(struct vm_area_s
if (address >= end)
BUG();
do {
- error |= filemap_sync_pmd_range(dir, address, end, vma, flags);
+ dirty |= filemap_sync_pmd_range(dir, address, end, vma, flags);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
@@ -129,7 +130,7 @@ static int filemap_sync(struct vm_area_s
out:
spin_unlock(&vma->vm_mm->page_table_lock);

- return error;
+ return dirty;
}

/*
@@ -146,17 +147,17 @@ static int filemap_sync(struct vm_area_s
static int msync_interval(struct vm_area_struct * vma,
unsigned long start, unsigned long end, int flags)
{
- int ret = 0;
+ int dirty, ret = 0;
struct file * file = vma->vm_file;

if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED))
return -EBUSY;

if (file && (vma->vm_flags & VM_SHARED)) {
- ret = filemap_sync(vma, start, end-start, flags);
+ struct address_space *mapping = file->f_mapping;
+ dirty = filemap_sync(vma, start, end-start, flags);

- if (!ret && (flags & MS_SYNC)) {
- struct address_space *mapping = file->f_mapping;
+ if (flags & MS_SYNC) {
int err;

down(&mapping->host->i_sem);
@@ -171,6 +172,11 @@ static int msync_interval(struct vm_area
ret = err;
up(&mapping->host->i_sem);
}
+
+ /* only update ctime & mtime if file actually changed */
+ if (dirty)
+ inode_update_time(mapping->host, 1);
+ update_atime(mapping->host);
}
return ret;
}


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/