[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/