Skip to contentSkip to conversation

Updating ctime and mtime for memory-mapped files [try #4]

PATCH In review Anton Salikhmetov 6 participants 21 messages Jan 15, 2008

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover Updating ctime and mtime for memory-mapped files [try #4]

1. Introduction

This is the fourth version of my solution for the bug #2645:

http://bugzilla.kernel.org/show_bug.cgi?id=2645

Changes since the previous version:

1) the case of retouching an already-dirty page pointed out by Miklos Szeredi has been addressed;

2) the file metadata are updated using the page modification time instead of the time of syncing data;

3) a few small corrections according to the latest feedback.

Brief explanation of these changes as well as some design considerations are given below.

2. The case of retouching an already-dirtied page

Miklos Szeredi gave the following feedback on the previous version:

Quoted 5 lines

I suspect your patch is ignoring writes after the first msync, but then why care about msync at all? What's so special about the _first_ msync? Is it just that most test programs only check this, and not what happens if msync is called more than once? That would be a bug in the test cases.

This version adds handling of the case of multiple msync() calls. Before going on with the explanaion, I'll quote a remark by Peter Zijlstra:

Quoted 7 lines

I must agree, doing the mmap dirty, MS_ASYNC, mmap retouch, MS_ASYNC case correctly would need a lot more code which I doubt is worth the effort.

It would require scanning the PTEs and marking them read-only again on MS_ASYNC, and some more logic in set_page_dirty() because that currently bails out early if the page in question is already dirty.

Indeed, the following logic of the __set_pages_dirty_nobuffers() function:

if (!TestSetPageDirty(page)) {
       mapping = page_mapping(page);

       if (!mapping)
               return 1;

       /* critical section */

       if (mapping->host) {
               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
               set_bit(AS_MCTIME, &mapping->flags);
       }
       return 1;
}

return 0;

made it difficult to account for the case of the already-dirty page retouch after the call to msync(MS_ASYNC).

In this version of my solution, I redesigned the logic of the same function as follows:

mapping = page_mapping(page);

if (!mapping)

       return 1;

set_bit(AS_MCTIME, &mapping->flags);

if (TestSetPageDirty(page))

       return 0;

/* critical section */

if (mapping->host) {
       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);

return 1;

This allows us to set the AS_MCTIME bit independently of whether the page had already been dirtied or not. Besides, such change makes the logic of the topmost "if" in this function straight thus improving readability. Finally, we already have the __set_page_dirty() routine with almost identical functionality. My redesign of __set_pages_dirty_nobuffers() is based on how the __set_page_dirty() routine is implemented.

Miklos gave an example of a scenario, where the previous version of my solution would fail:

http://lkml.org/lkml/2008/1/14/100

Here is how it looks in the version I am sending now:

1 page is dirtied through mapping
=> the AS_MCTIME bit turned on
2 app calls msync(MS_ASYNC)
=> inode's times updated, the AS_MCTIME bit turned off
3 page is written again through mapping
=> the AS_MCTIME bit turned on again
4 app calls msync(MS_ASYNC)
=> inode's times updated, the AS_MCTIME bit turned off
5 ...
6 page is written back
=> ... by this moment, the either the msync(MS_ASYNC) has
taken care of updating the file times, or the AS_MCTIME bit is on.

I think that the feedback about writes after the first msync(MS_ASYNC) has thereby been addressed.

3. Updating the time stamps of the block device special files

As for the block device case, let's start from the following assumption:

if the block device data changes, we should do our best to tell the world that this has happened.

This is how I approach this requirement:

1) if the block device is active, this is done at next *sync() through calling the bd_inode_update_time() helper function.

2) if the block device is not active, this is done during the block device file deactivation in the unlink_file_vma() routine.

Removing either of these actions would leave a possibility of losing information about the block device data update. That is why I am keeping both.

4. Recording the time was the file data changed

Finally, I noticed yet another issue with the previous version of my patch. Specifically, the time stamps were set to the current time of the moment when syncing but not the write reference was being done. This led to the following adverse effect on my development system:

1) a text file A was updated by process B;
2) process B exits without calling any of the *sync() functions;
3) vi editor opens the file A;
4) file data synced, file times updated;
5) vi is confused by "thinking" that the file was changed after 3).

This version overcomes this problem by introducing another field into the address_space structure. This field is used to "remember" the time of dirtying, and then this time value is propagated to the file metadata.

This approach is based upon the following suggestion given by Peter Staubach during one of our previous discussions:

http://lkml.org/lkml/2008/1/9/267

Quoted 7 lines

A better architecture would be to arrange for the file times to be updated when the page makes the transition from being unmodified to modified. This is not straightforward due to the current locking, but should be doable, I think. Perhaps recording the current time and then using it to update the file times at a more suitable time (no pun intended) might work.

The solution I propose now proves the viability of the latter approach.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw

PATCH 1/2 Massive code cleanup of sys_msync()

Substantial code cleanup of the sys_msync() function:

1) using the PAGE_ALIGN() macro instead of "manual" alignment;
2) improved readability of the loop traversing the process memory regions.

---
 mm/msync.c |   79 ++++++++++++++++++++++++++++--------------------------------
 1 files changed, 37 insertions(+), 42 deletions(-)
mm/msync.c +37 -42
index 144a757..3270caa 100644
@@ -1,24 +1,25 @@
 /*
  *	linux/mm/msync.c
  *
+ * The msync() system call.
  * Copyright (C) 1994-1999  Linus Torvalds
+ *
+ * Massive code cleanup.
+ * Copyright (C) 2008 Anton Salikhmetov <[email protected]>
  */
 
-/*
- * The msync() system call.
- */
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/syscalls.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 
 /*
  * MS_SYNC syncs the entire file - including mappings.
  *
  * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
- * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
+ * Nor does it mark the relevant pages dirty (it used to up to 2.6.17).
  * Now it doesn't do anything, since dirty pages are properly tracked.
  *
  * The application may now run fsync() to
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
 	unsigned long end;
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
-	int unmapped_error = 0;
-	int error = -EINVAL;
+	int error = 0, unmapped_error = 0;
 
 	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-		goto out;
+		return -EINVAL;
 	if (start & ~PAGE_MASK)
-		goto out;
+		return -EINVAL;
 	if ((flags & MS_ASYNC) && (flags & MS_SYNC))
-		goto out;
-	error = -ENOMEM;
-	len = (len + ~PAGE_MASK) & PAGE_MASK;
+		return -EINVAL;
+
+	len = PAGE_ALIGN(len);
 	end = start + len;
 	if (end < start)
-		goto out;
-	error = 0;
+		return -ENOMEM;
 	if (end == start)
-		goto out;
+		return 0;
+
 	/*
 	 * If the interval [start,end) covers some unmapped address ranges,
 	 * just ignore them, but return -ENOMEM at the end.
 	 */
 	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, start);
-	for (;;) {
+	do {
 		struct file *file;
 
-		/* Still start < end. */
-		error = -ENOMEM;
-		if (!vma)
-			goto out_unlock;
-		/* Here start < vma->vm_end. */
+		if (!vma) {
+			error = -ENOMEM;
+			break;
+		}
 		if (start < vma->vm_start) {
 			start = vma->vm_start;
-			if (start >= end)
-				goto out_unlock;
+			if (start >= end) {
+				error = -ENOMEM;
+				break;
+			}
 			unmapped_error = -ENOMEM;
 		}
-		/* Here vma->vm_start <= start < vma->vm_end. */
-		if ((flags & MS_INVALIDATE) &&
-				(vma->vm_flags & VM_LOCKED)) {
+		if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) {
 			error = -EBUSY;
-			goto out_unlock;
+			break;
 		}
-		file = vma->vm_file;
 		start = vma->vm_end;
-		if ((flags & MS_SYNC) && file &&
-				(vma->vm_flags & VM_SHARED)) {
+
+		file = vma->vm_file;
+		if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {
 			get_file(file);
 			up_read(&mm->mmap_sem);
 			error = do_fsync(file, 0);
 			fput(file);
-			if (error || start >= end)
-				goto out;
+			if (error)
+				return error;
 			down_read(&mm->mmap_sem);
 			vma = find_vma(mm, start);
-		} else {
-			if (start >= end) {
-				error = 0;
-				goto out_unlock;
-			}
-			vma = vma->vm_next;
+			continue;
 		}
-	}
-out_unlock:
+
+		vma = vma->vm_next;
+	} while (start < end);
 	up_read(&mm->mmap_sem);
-out:
+
 	return error ? : unmapped_error;
 }
Signature · 7 lines
1.4.4.4

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#2 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

mm/msync.c line 8

Quoted 10 lines · Anton Salikhmetov

+++ b/mm/msync.c

mm/msync.c +4 -0
@@ -1,24 +1,25 @@
 /*
  *	linux/mm/msync.c
  *
+ * The msync() system call.
  * Copyright (C) 1994-1999  Linus Torvalds
+ *
+ * Massive code cleanup.
+ * Copyright (C) 2008 Anton Salikhmetov <[email protected]>

Please don't put the changelog in here, that's what the log in the SCM is for. And while you're at it remove the confusing file name comment. This should now look something like:

/*
* The msync() system call.
*
* Copyright (C) 1994-1999 Linus Torvalds
* Copyright (C) 2008 Anton Salikhmetov <[email protected]> */

Quoted 4 lines
mm/msync.c +0 -0
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
 	unsigned long end;
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 10 lines
mm/msync.c +3 -4
-	int unmapped_error = 0;
-	int error = -EINVAL;
+	int error = 0, unmapped_error = 0;
 
 	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-		goto out;
+		return -EINVAL;
 	if (start & ~PAGE_MASK)
-		goto out;
+		return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 81

Quoted 2 lines
mm/msync.c +2 -0
+		file = vma->vm_file;
+		if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {

Given that file is assigned just above it would be more readable to test it first.

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 87

Quoted 2 lines
mm/msync.c +2 -0
+			if (error)
+				return error;

This should be an goto out, returns out of the middle of the function make reading and maintaining the code not so nice.

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 97

Quoted 1 line
mm/msync.c +0 -0
 	return error ? : unmapped_error;

Care to get rid of this odd GNU extension while you're at it and use the proper

	return error ? error : unmapped_error;

?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#3 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 16 lines · Anton Salikhmetov

mm/msync.c line 8

Quoted 10 lines

+++ b/mm/msync.c

mm/msync.c +4 -0
@@ -1,24 +1,25 @@
 /*
  *   linux/mm/msync.c
  *
+ * The msync() system call.
  * Copyright (C) 1994-1999  Linus Torvalds
+ *
+ * Massive code cleanup.
+ * Copyright (C) 2008 Anton Salikhmetov <[email protected]>

Please don't put the changelog in here, that's what the log in the SCM is for. And while you're at it remove the confusing file name comment. This should now look something like:

Quoted 6 lines

/*
* The msync() system call.
*
* Copyright (C) 1994-1999 Linus Torvalds
* Copyright (C) 2008 Anton Salikhmetov <[email protected]> */

Thanks!

I'll take into account your recommendation.

Quoted 9 lines
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Sorry, I can't agree. That's what is written in the CodingStyle document:

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

The second part of requirement does not hold true for the sys_msync() routine.

Quoted 6 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 81

Quoted 3 lines
mm/msync.c +2 -0
+             file = vma->vm_file;
+             if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {

Given that file is assigned just above it would be more readable to test it first.

The second part of my solution changes this code, anyway.

Quoted 6 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 87

Quoted 3 lines
mm/msync.c +2 -0
+                     if (error)
+                             return error;

This should be an goto out, returns out of the middle of the function make reading and maintaining the code not so nice.

Sorry, I don't think so. No "common cleanup" is needed here.

Quoted 5 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 97

Quoted 2 lines
mm/msync.c +0 -0
      return error ? : unmapped_error;

Care to get rid of this odd GNU extension while you're at it and use the proper

I do also think that this GNU extension is not readable, so I'll take your recommentation into account.

Quoted 6 lines
        return error ? error : unmapped_error;

?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#4 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

Quoted 23 lines · On Tue, 15 Jan 2008 22:02:54 +0300 Anton Salikhmetov wrote:

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 10 lines · Anton Salikhmetov
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Quoted 4 lines

Sorry, I can't agree. That's what is written in the CodingStyle document:

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

CodingStyle does not try to cover Everything. Nor do we want it to.

At any rate, there is a desire for functions to have a single point of return, regardless of the amount of cleanup to be done, so I agree with Christoph's comments.

Quoted 12 lines

The second part of requirement does not hold true for the sys_msync() routine.

Quoted 6 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 81

Quoted 3 lines
mm/msync.c +2 -0
+             file = vma->vm_file;
+             if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {

Given that file is assigned just above it would be more readable to test it first.

The second part of my solution changes this code, anyway.

Quoted 1 line
Quoted 7 lines
Quoted 5 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 87

Quoted 2 lines
mm/msync.c +2 -0
+                     if (error)
+                             return error;

This should be an goto out, returns out of the middle of the function make reading and maintaining the code not so nice.

Sorry, I don't think so. No "common cleanup" is needed here.

---
~Randy

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#5 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

2008/1/15, Randy Dunlap <[email protected]>:

Quoted 27 lines · On Tue, 15 Jan 2008 22:02:54 +0300 Anton Salikhmetov wrote:
Quoted 26 lines

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 10 lines · Anton Salikhmetov
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Sorry, I can't agree. That's what is written in the CodingStyle document:

Quoted 8 lines
Quoted 2 lines

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

CodingStyle does not try to cover Everything. Nor do we want it to.

At any rate, there is a desire for functions to have a single point of return, regardless of the amount of cleanup to be done, so I agree with Christoph's comments.

Should I replace "return -EINVAL;" statement with the following?

{
    error = -EINVAL;
    goto out;
}
Quoted 17 lines
Quoted 17 lines

The second part of requirement does not hold true for the sys_msync() routine.

Quoted 6 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 81

Quoted 3 lines
mm/msync.c +2 -0
+             file = vma->vm_file;
+             if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {

Given that file is assigned just above it would be more readable to test it first.

The second part of my solution changes this code, anyway.

Quoted 4 lines
Quoted 3 lines
mm/msync.c +2 -0
+                     if (error)
+                             return error;
Quoted 9 lines
Quoted 4 lines
Quoted 2 lines

This should be an goto out, returns out of the middle of the function make reading and maintaining the code not so nice.

Sorry, I don't think so. No "common cleanup" is needed here.

---
~Randy

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#6 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

Quoted 37 lines · Anton Salikhmetov

2008/1/15, Randy Dunlap <[email protected]>:

Quoted 27 lines · On Tue, 15 Jan 2008 22:02:54 +0300 Anton Salikhmetov wrote:
Quoted 26 lines

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 10 lines · Anton Salikhmetov
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Sorry, I can't agree. That's what is written in the CodingStyle document:

Quoted 8 lines
Quoted 2 lines

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

CodingStyle does not try to cover Everything. Nor do we want it to.

At any rate, there is a desire for functions to have a single point of return, regardless of the amount of cleanup to be done, so I agree with Christoph's comments.

Quoted 6 lines

Should I replace "return -EINVAL;" statement with the following?

{
    error = -EINVAL;
    goto out;
}

Notice that error is already -EINVAL, so a simple goto should suffice.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#7 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

Quoted 1 line · Peter Zijlstra

Notice that error is already -EINVAL, so a simple goto should suffice.

Yes, for the start of the function you can basically leave it as-is.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#8 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 5 lines · Peter Zijlstra
Quoted 1 line

Notice that error is already -EINVAL, so a simple goto should suffice.

Yes, for the start of the function you can basically leave it as-is.

OK, I will do as you suggest. Thank you for your answers.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

In reply to Randy Dunlap
Quoted 27 lines · Randy Dunlap
Quoted 25 lines · On Tue, 15 Jan 2008 22:02:54 +0300 Anton Salikhmetov wrote:

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 10 lines · Anton Salikhmetov
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Sorry, I can't agree. That's what is written in the CodingStyle document:

Quoted 8 lines
Quoted 2 lines

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

CodingStyle does not try to cover Everything. Nor do we want it to.

At any rate, there is a desire for functions to have a single point of return, regardless of the amount of cleanup to be done, so I agree with Christoph's comments.

When we're not cleaning up resources, the main advantage of having a single point of return is that you can trace backwards from the return point through the function's logic. But that advantage flies right out the window when you use gotos. You still have to figure out how you got to the return statement by tracing back and looking at all the possible gotos. And the "goto out" style adds bulk and non-negligible complexity when we've got to search back for what the last explicitly set value of "ret" or "error" or whatever the function in question is using was. Sometimes people get this wrong ("retval is already -EINVAL, so I don't need to explicitly set it"), and create bugs.

So I think if we're not actually going to use "structured programming" (no gotos) or "stack cleanup" styles, the single return point style is more trouble than it's worth.

A lesser advantage of the single return point is that you can set a breakpoint or put a printk at the end of a function. But I don't think that's much justification.

Signature · 7 lines
Mathematics is the supreme nostalgia of our time.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#10 lore raw

Re: [PATCH 1/2] Massive code cleanup of sys_msync()

Quoted 49 lines · On Tue, 15 Jan 2008 14:46:57 -0600 Matt Mackall wrote:
Quoted 27 lines · Randy Dunlap
Quoted 25 lines · On Tue, 15 Jan 2008 22:02:54 +0300 Anton Salikhmetov wrote:

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 10 lines · Anton Salikhmetov
Quoted 9 lines
mm/msync.c +1 -2
@@ -33,71 +34,65 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
      unsigned long end;
      struct mm_struct *mm = current->mm;
      struct vm_area_struct *vma;
-     int unmapped_error = 0;
-     int error = -EINVAL;
+     int error = 0, unmapped_error = 0;
 
Quoted 11 lines

mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 42

Quoted 6 lines
mm/msync.c +2 -2
      if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
-             goto out;
+             return -EINVAL;
      if (start & ~PAGE_MASK)
-             goto out;
+             return -EINVAL;

The goto out for a simple return style is used quite commonly in kernel code to have a single return statement which makes code maintaince, e.g. adding locks or allocations simpler. Not sure that getting rid of it makes a lot of sense.

Sorry, I can't agree. That's what is written in the CodingStyle document:

Quoted 8 lines
Quoted 2 lines

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done.

CodingStyle does not try to cover Everything. Nor do we want it to.

At any rate, there is a desire for functions to have a single point of return, regardless of the amount of cleanup to be done, so I agree with Christoph's comments.

When we're not cleaning up resources, the main advantage of having a single point of return is that you can trace backwards from the return point through the function's logic. But that advantage flies right out the window when you use gotos. You still have to figure out how you got to the return statement by tracing back and looking at all the possible gotos. And the "goto out" style adds bulk and non-negligible complexity when we've got to search back for what the last explicitly set value of "ret" or "error" or whatever the function in question is using was. Sometimes people get this wrong ("retval is already -EINVAL, so I don't need to explicitly set it"), and create bugs.

Quoted 7 lines

So I think if we're not actually going to use "structured programming" (no gotos) or "stack cleanup" styles, the single return point style is more trouble than it's worth.

A lesser advantage of the single return point is that you can set a breakpoint or put a printk at the end of a function. But I don't think that's much justification.

OTOH, I think that those are fine reasons for it.

---
~Randy

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

PATCH 2/2 Updating ctime and mtime at syncing

In reply to Anton Salikhmetov

Changes for updating the ctime and mtime fields for memory-mapped files:

1) new flag triggering update of the inode data;
2) new field in the address_space structure for saving modification time;
3) new function to update ctime and mtime for block device files;
4) new helper function to update ctime and mtime when needed;
5) updating time stamps for mapped files in sys_msync() and do_fsync();
6) implementing the feature of auto-updating ctime and mtime;
7) account for the case of retouching an already-dirtied page.

---
 fs/buffer.c             |    3 ++
 fs/fs-writeback.c       |    2 +
 fs/inode.c              |   53 ++++++++++++++++++++++++++++++++++-----------
 fs/sync.c               |    2 +
 include/linux/fs.h      |   13 ++++++++++-
 include/linux/pagemap.h |    3 +-
 mm/mmap.c               |    3 ++
 mm/msync.c              |   29 ++++++++++++++++--------
 mm/page-writeback.c     |   54 +++++++++++++++++++++++++---------------------
 9 files changed, 112 insertions(+), 50 deletions(-)
fs/buffer.c +3 -0
index 7249e01..3967aa7 100644
@@ -701,6 +701,9 @@ static int __set_page_dirty(struct page *page,
 	if (unlikely(!mapping))
 		return !TestSetPageDirty(page);
 
+	mapping->mtime = CURRENT_TIME;
+	set_bit(AS_MCTIME, &mapping->flags);
+
 	if (TestSetPageDirty(page))
 		return 0;
 
fs/fs-writeback.c +2 -0
index 300324b..affd291 100644
@@ -243,6 +243,8 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
 
 	spin_unlock(&inode_lock);
 
+	mapping_update_time(mapping);
+
 	ret = do_writepages(mapping, wbc);
 
 	/* Don't write the inode if only I_DIRTY_PAGES was set */
fs/inode.c +40 -13

88 lines not on this page · raw message

fs/sync.c +2 -0
index 7cd005e..5561464 100644
@@ -87,6 +87,8 @@ long do_fsync(struct file *file, int datasync)
 		goto out;
 	}
 
+	mapping_update_time(mapping);
+
 	ret = filemap_fdatawrite(mapping);
 
 	/*
include/linux/fs.h +12 -1
index b3ec4a4..f0d3ced 100644
@@ -511,6 +511,7 @@ struct address_space {
 	spinlock_t		private_lock;	/* for use by the address_space */
 	struct list_head	private_list;	/* ditto */
 	struct address_space	*assoc_mapping;	/* ditto */
+	struct timespec		mtime;		/* modification time */
 } __attribute__((aligned(sizeof(long))));
 	/*
 	 * On most architectures that alignment is already the case; but
@@ -1977,7 +1978,17 @@ extern int buffer_migrate_page(struct address_space *,
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern int __must_check inode_setattr(struct inode *, struct iattr *);
 
-extern void file_update_time(struct file *file);
+extern void inode_update_time(struct inode *, struct timespec *);
+
+static inline void file_update_time(struct file *file)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct timespec ts = current_fs_time(inode->i_sb);
+
+	inode_update_time(inode, &ts);
+}
+
+extern void mapping_update_time(struct address_space *);
 
 static inline ino_t parent_ino(struct dentry *dentry)
 {
include/linux/pagemap.h +2 -1
index db8a410..bf0f9e7 100644
@@ -17,8 +17,9 @@
  * Bits in mapping->flags.  The lower __GFP_BITS_SHIFT bits are the page
  * allocation mode flags.
  */
-#define	AS_EIO		(__GFP_BITS_SHIFT + 0)	/* IO error on async write */
+#define AS_EIO		(__GFP_BITS_SHIFT + 0)	/* IO error on async write */
 #define AS_ENOSPC	(__GFP_BITS_SHIFT + 1)	/* ENOSPC on async write */
+#define AS_MCTIME	(__GFP_BITS_SHIFT + 2)	/* mtime and ctime to update */
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
 {
mm/mmap.c +3 -0
index 15678aa..f659733 100644
@@ -210,9 +210,12 @@ void unlink_file_vma(struct vm_area_struct *vma)
 
 	if (file) {
 		struct address_space *mapping = file->f_mapping;
+
 		spin_lock(&mapping->i_mmap_lock);
 		__remove_shared_vm_struct(vma, file, mapping);
 		spin_unlock(&mapping->i_mmap_lock);
+
+		mapping_update_time(mapping);
 	}
 }
 
mm/msync.c +19 -10
index 3270caa..80ca1cc 100644
@@ -5,6 +5,7 @@
  * Copyright (C) 1994-1999  Linus Torvalds
  *
  * Massive code cleanup.
+ * Updating the ctime and mtime stamps for memory-mapped files.
  * Copyright (C) 2008 Anton Salikhmetov <[email protected]>
  */
 
@@ -22,6 +23,10 @@
  * Nor does it mark the relevant pages dirty (it used to up to 2.6.17).
  * Now it doesn't do anything, since dirty pages are properly tracked.
  *
+ * The msync() system call updates the ctime and mtime fields for
+ * the mapped file when called with the MS_SYNC or MS_ASYNC flags
+ * according to the POSIX standard.
+ *
  * The application may now run fsync() to
  * write out the dirty pages and wait on the writeout and check the result.
  * Or the application may run fadvise(FADV_DONTNEED) against the fd to start
@@ -78,16 +83,20 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
 		start = vma->vm_end;
 
 		file = vma->vm_file;
-		if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) {
-			get_file(file);
-			up_read(&mm->mmap_sem);
-			error = do_fsync(file, 0);
-			fput(file);
-			if (error)
-				return error;
-			down_read(&mm->mmap_sem);
-			vma = find_vma(mm, start);
-			continue;
+		if (file && (vma->vm_flags & VM_SHARED)) {
+			if (flags & MS_ASYNC)
+				mapping_update_time(file->f_mapping);
+			if (flags & MS_SYNC) {
+				get_file(file);
+				up_read(&mm->mmap_sem);
+				error = do_fsync(file, 0);
+				fput(file);
+				if (error)
+					return error;
+				down_read(&mm->mmap_sem);
+				vma = find_vma(mm, start);
+				continue;
+			}
 		}
 
 		vma = vma->vm_next;
mm/page-writeback.c +29 -25

64 lines not on this page · raw message

Signature · 7 lines
1.4.4.4

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#12 lore raw

Re: [PATCH 2/2] Updating ctime and mtime at syncing

Quoted 29 lines · Anton Salikhmetov
mm/page-writeback.c +4 -15
index 3d3848f..53d0e34 100644
@@ -997,35 +997,39 @@ int __set_page_dirty_no_writeback(struct page *page)
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-	if (!TestSetPageDirty(page)) {
-		struct address_space *mapping = page_mapping(page);
-		struct address_space *mapping2;
+	struct address_space *mapping = page_mapping(page);
+	struct address_space *mapping2;
 
-		if (!mapping)
-			return 1;
+	if (!mapping)
+		return 1;
 
-		write_lock_irq(&mapping->tree_lock);
-		mapping2 = page_mapping(page);
-		if (mapping2) { /* Race with truncate? */
-			BUG_ON(mapping2 != mapping);
-			WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-			if (mapping_cap_account_dirty(mapping)) {
-				__inc_zone_page_state(page, NR_FILE_DIRTY);
-				__inc_bdi_stat(mapping->backing_dev_info,
-						BDI_RECLAIMABLE);
-				task_io_account_write(PAGE_CACHE_SIZE);

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1007

Quoted 10 lines
mm/page-writeback.c +2 -8
-			}
-			radix_tree_tag_set(&mapping->page_tree,
-				page_index(page), PAGECACHE_TAG_DIRTY);
-		}
-		write_unlock_irq(&mapping->tree_lock);
-		if (mapping->host) {
-			/* !PageAnon && !swapper_space */
-			__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+	mapping->mtime = CURRENT_TIME;
+	set_bit(AS_MCTIME, &mapping->flags);

This seems vulnerable to the race we have against truncate, handled by the mapping2 magic below. Do we care?

Quoted 30 lines
mm/page-writeback.c +23 -2
+
+	if (TestSetPageDirty(page))
+		return 0;
+
+	write_lock_irq(&mapping->tree_lock);
+	mapping2 = page_mapping(page);
+	if (mapping2) {
+		/* Race with truncate? */
+		BUG_ON(mapping2 != mapping);
+		WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
+		if (mapping_cap_account_dirty(mapping)) {
+			__inc_zone_page_state(page, NR_FILE_DIRTY);
+			__inc_bdi_stat(mapping->backing_dev_info,
+					BDI_RECLAIMABLE);
+			task_io_account_write(PAGE_CACHE_SIZE);
 		}
-		return 1;
+		radix_tree_tag_set(&mapping->page_tree,
+				page_index(page), PAGECACHE_TAG_DIRTY);
 	}
-	return 0;
+	write_unlock_irq(&mapping->tree_lock);
+
+	if (mapping->host)
+		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+	return 1;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 
#13 lore raw

Re: [PATCH 2/2] Updating ctime and mtime at syncing

2008/1/15, Peter Zijlstra <[email protected]>:

Quoted 63 lines · Anton Salikhmetov
Quoted 30 lines
mm/page-writeback.c +4 -15
index 3d3848f..53d0e34 100644
@@ -997,35 +997,39 @@ int __set_page_dirty_no_writeback(struct page *page)
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-     if (!TestSetPageDirty(page)) {
-             struct address_space *mapping = page_mapping(page);
-             struct address_space *mapping2;
+     struct address_space *mapping = page_mapping(page);
+     struct address_space *mapping2;
 
-             if (!mapping)
-                     return 1;
+     if (!mapping)
+             return 1;
 
-             write_lock_irq(&mapping->tree_lock);
-             mapping2 = page_mapping(page);
-             if (mapping2) { /* Race with truncate? */
-                     BUG_ON(mapping2 != mapping);
-                     WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-                     if (mapping_cap_account_dirty(mapping)) {
-                             __inc_zone_page_state(page, NR_FILE_DIRTY);
-                             __inc_bdi_stat(mapping->backing_dev_info,
-                                             BDI_RECLAIMABLE);
-                             task_io_account_write(PAGE_CACHE_SIZE);

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1007

Quoted 10 lines
mm/page-writeback.c +2 -8
-                     }
-                     radix_tree_tag_set(&mapping->page_tree,
-                             page_index(page), PAGECACHE_TAG_DIRTY);
-             }
-             write_unlock_irq(&mapping->tree_lock);
-             if (mapping->host) {
-                     /* !PageAnon && !swapper_space */
-                     __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+     mapping->mtime = CURRENT_TIME;
+     set_bit(AS_MCTIME, &mapping->flags);

This seems vulnerable to the race we have against truncate, handled by the mapping2 magic below. Do we care?

Quoted 17 lines
mm/page-writeback.c +15 -1
+
+     if (TestSetPageDirty(page))
+             return 0;
+
+     write_lock_irq(&mapping->tree_lock);
+     mapping2 = page_mapping(page);
+     if (mapping2) {
+             /* Race with truncate? */
+             BUG_ON(mapping2 != mapping);
+             WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
+             if (mapping_cap_account_dirty(mapping)) {
+                     __inc_zone_page_state(page, NR_FILE_DIRTY);
+                     __inc_bdi_stat(mapping->backing_dev_info,
+                                     BDI_RECLAIMABLE);
+                     task_io_account_write(PAGE_CACHE_SIZE);
              }
-             return 1;
Quoted 8 lines

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1030

Quoted 8 lines
mm/page-writeback.c +6 -1
+             radix_tree_tag_set(&mapping->page_tree,
+                             page_index(page), PAGECACHE_TAG_DIRTY);
      }
-     return 0;
+     write_unlock_irq(&mapping->tree_lock);
+
+     if (mapping->host)
+             __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);

The inode gets marked dirty using the same "mapping" variable as my code does. So, AFAIU, my change does not introduce any new vulnerabilities. I would nevertherless be grateful to you for a scenario where the race would be triggered.

Quoted 7 lines

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1035

Quoted 5 lines
mm/page-writeback.c +2 -0
+
+     return 1;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#14 lore raw

Re: [PATCH 2/2] Updating ctime and mtime at syncing

Quoted 69 lines · Anton Salikhmetov

2008/1/15, Peter Zijlstra <[email protected]>:

Quoted 68 lines · Anton Salikhmetov
Quoted 30 lines
mm/page-writeback.c +4 -15
index 3d3848f..53d0e34 100644
@@ -997,35 +997,39 @@ int __set_page_dirty_no_writeback(struct page *page)
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-     if (!TestSetPageDirty(page)) {
-             struct address_space *mapping = page_mapping(page);
-             struct address_space *mapping2;
+     struct address_space *mapping = page_mapping(page);
+     struct address_space *mapping2;
 
-             if (!mapping)
-                     return 1;
+     if (!mapping)
+             return 1;
 
-             write_lock_irq(&mapping->tree_lock);
-             mapping2 = page_mapping(page);
-             if (mapping2) { /* Race with truncate? */
-                     BUG_ON(mapping2 != mapping);
-                     WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-                     if (mapping_cap_account_dirty(mapping)) {
-                             __inc_zone_page_state(page, NR_FILE_DIRTY);
-                             __inc_bdi_stat(mapping->backing_dev_info,
-                                             BDI_RECLAIMABLE);
-                             task_io_account_write(PAGE_CACHE_SIZE);

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1007

Quoted 10 lines
mm/page-writeback.c +2 -8
-                     }
-                     radix_tree_tag_set(&mapping->page_tree,
-                             page_index(page), PAGECACHE_TAG_DIRTY);
-             }
-             write_unlock_irq(&mapping->tree_lock);
-             if (mapping->host) {
-                     /* !PageAnon && !swapper_space */
-                     __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+     mapping->mtime = CURRENT_TIME;
+     set_bit(AS_MCTIME, &mapping->flags);

This seems vulnerable to the race we have against truncate, handled by the mapping2 magic below. Do we care?

Quoted 22 lines
mm/page-writeback.c +18 -2
+
+     if (TestSetPageDirty(page))
+             return 0;
+
+     write_lock_irq(&mapping->tree_lock);
+     mapping2 = page_mapping(page);
+     if (mapping2) {
+             /* Race with truncate? */
+             BUG_ON(mapping2 != mapping);
+             WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
+             if (mapping_cap_account_dirty(mapping)) {
+                     __inc_zone_page_state(page, NR_FILE_DIRTY);
+                     __inc_bdi_stat(mapping->backing_dev_info,
+                                     BDI_RECLAIMABLE);
+                     task_io_account_write(PAGE_CACHE_SIZE);
              }
-             return 1;
+             radix_tree_tag_set(&mapping->page_tree,
+                             page_index(page), PAGECACHE_TAG_DIRTY);
      }
-     return 0;
+     write_unlock_irq(&mapping->tree_lock);
Quoted 8 lines
Quoted 3 lines

mm/page-writeback.c int __set_page_dirty_no_writeback(struct page *page) · line 1030

Quoted 3 lines
mm/page-writeback.c +3 -0
+
+     if (mapping->host)
+             __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);

The inode gets marked dirty using the same "mapping" variable as my code does. So, AFAIU, my change does not introduce any new vulnerabilities. I would nevertherless be grateful to you for a scenario where the race would be triggered.

Ah, right, so that would be a resounding no to my previous question :-)

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#15 lore raw

Re: [PATCH 2/2] Updating ctime and mtime at syncing

In reply to Anton Salikhmetov

fs/inode.c void file_update_time(struct file *file) · line 1290

Quoted 10 lines · Anton Salikhmetov
fs/inode.c +10 -0
+/*
+ * Update the ctime and mtime stamps for memory-mapped block device files.
+ */
+static void bd_inode_update_time(struct inode *inode, struct timespec *ts)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct list_head *p;
+
+	if (bdev == NULL)
+		return;

inode->i_bdev is never NULL for inodes currently beeing written to.

fs/inode.c void file_update_time(struct file *file) · line 1294

Quoted 4 lines
fs/inode.c +4 -0
+
+	mutex_lock(&bdev->bd_mutex);
+	list_for_each(p, &bdev->bd_inodes) {
+		inode = list_entry(p, struct inode, i_devices);

this should use list_for_each_entry.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#16 lore raw

Re: [PATCH 2/2] Updating ctime and mtime at syncing

2008/1/15, Christoph Hellwig <[email protected]>:

Quoted 14 lines · Anton Salikhmetov

fs/inode.c void file_update_time(struct file *file) · line 1290

Quoted 10 lines
fs/inode.c +10 -0
+/*
+ * Update the ctime and mtime stamps for memory-mapped block device files.
+ */
+static void bd_inode_update_time(struct inode *inode, struct timespec *ts)
+{
+     struct block_device *bdev = inode->i_bdev;
+     struct list_head *p;
+
+     if (bdev == NULL)
+             return;

inode->i_bdev is never NULL for inodes currently beeing written to.

Quoted 8 lines

fs/inode.c void file_update_time(struct file *file) · line 1294

Quoted 4 lines
fs/inode.c +4 -0
+
+     mutex_lock(&bdev->bd_mutex);
+     list_for_each(p, &bdev->bd_inodes) {
+             inode = list_entry(p, struct inode, i_devices);

this should use list_for_each_entry.

Thank you very much for your recommenations. I'll take them into account.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw
In reply to Anton Salikhmetov
Quoted 10 lines

1. Introduction

This is the fourth version of my solution for the bug #2645:

http://bugzilla.kernel.org/show_bug.cgi?id=2645

Changes since the previous version:

1) the case of retouching an already-dirty page pointed out by Miklos Szeredi has been addressed;

I'm a bit sceptical, as we've also pointed out, that this is not possible without messing with the page tables.

Did you try my test program on the patched kernel?

I've refreshed the patch, where we left this issue last time. It should basically have equivalent functionality to your patch, and is a lot simpler. There might be performance issues with it, but it's a good starting point.

Miklos
----

mm/memory.c +4 -0
Index: linux/mm/memory.c
===================================================================
@@ -1680,6 +1680,8 @@ gotten:
 unlock:
 	pte_unmap_unlock(page_table, ptl);
 	if (dirty_page) {
+		if (vma->vm_file)
+			file_update_time(vma->vm_file);
 		/*
 		 * Yes, Virginia, this is actually required to prevent a race
 		 * with clear_page_dirty_for_io() from clearing the page dirty
@@ -2313,6 +2315,8 @@ out_unlocked:
 	if (anon)
 		page_cache_release(vmf.page);
 	else if (dirty_page) {
+		if (vma->vm_file)
+			file_update_time(vma->vm_file);
 		set_page_dirty_balance(dirty_page, page_mkwrite);
 		put_page(dirty_page);
 	}

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#18 lore raw
Quoted 14 lines · Miklos Szeredi
Quoted 10 lines

1. Introduction

This is the fourth version of my solution for the bug #2645:

http://bugzilla.kernel.org/show_bug.cgi?id=2645

Changes since the previous version:

1) the case of retouching an already-dirty page pointed out by Miklos Szeredi has been addressed;

I'm a bit sceptical, as we've also pointed out, that this is not possible without messing with the page tables.

Quoted 6 lines

Did you try my test program on the patched kernel?

I've refreshed the patch, where we left this issue last time. It should basically have equivalent functionality to your patch, and is a lot simpler. There might be performance issues with it, but it's a good starting point.

It has the same problem as Anton's in that it won't get triggered again for an already dirty mapped page.

But yeah, its simpler than fudging set_page_dirty().

Quoted 15 lines

Index: linux/mm/memory.c
===================================================================

mm/memory.c +2 -0
@@ -1680,6 +1680,8 @@ gotten:
 unlock:
 	pte_unmap_unlock(page_table, ptl);
 	if (dirty_page) {
+		if (vma->vm_file)
+			file_update_time(vma->vm_file);
 		/*
 		 * Yes, Virginia, this is actually required to prevent a race
 		 * with clear_page_dirty_for_io() from clearing the page dirty

mm/memory.c out_unlocked: · line 2322

Quoted 8 lines
mm/memory.c +2 -0
@@ -2313,6 +2315,8 @@ out_unlocked:
 	if (anon)
 		page_cache_release(vmf.page);
 	else if (dirty_page) {
+		if (vma->vm_file)
+			file_update_time(vma->vm_file);
 		set_page_dirty_balance(dirty_page, page_mkwrite);
 		put_page(dirty_page);
 	}

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#19 lore raw
Quoted 17 lines · Miklos Szeredi
Quoted 16 lines
Quoted 10 lines

1. Introduction

This is the fourth version of my solution for the bug #2645:

http://bugzilla.kernel.org/show_bug.cgi?id=2645

Changes since the previous version:

1) the case of retouching an already-dirty page pointed out by Miklos Szeredi has been addressed;

I'm a bit sceptical, as we've also pointed out, that this is not possible without messing with the page tables.

Did you try my test program on the patched kernel?

Quoted 7 lines
Quoted 4 lines

I've refreshed the patch, where we left this issue last time. It should basically have equivalent functionality to your patch, and is a lot simpler. There might be performance issues with it, but it's a good starting point.

It has the same problem as Anton's in that it won't get triggered again for an already dirty mapped page.

Yes, it's not better in this respect, than Anton's patch. And it might be worse performance-wise, since file_update_time() is sure to be slower, than set_bit(). According to Andrew, this may not actually matter in practice, but that would have to be benchmarked, I guess.

Miklos

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#20 lore raw
In reply to Miklos Szeredi

2008/1/15, Miklos Szeredi <[email protected]>:

Quoted 8 lines
Quoted 8 lines

1. Introduction

This is the fourth version of my solution for the bug #2645:

http://bugzilla.kernel.org/show_bug.cgi?id=2645

Changes since the previous version:

Quoted 7 lines
Quoted 2 lines

1) the case of retouching an already-dirty page pointed out by Miklos Szeredi has been addressed;

I'm a bit sceptical, as we've also pointed out, that this is not possible without messing with the page tables.

Did you try my test program on the patched kernel?

I just tried your test program. Alas, my assumption appears to be wrong.

Thank you for your comment!

Now I start thinking that it is better not to care about the MS_ASYNC case whatsoever.

Quoted 25 lines

I've refreshed the patch, where we left this issue last time. It should basically have equivalent functionality to your patch, and is a lot simpler. There might be performance issues with it, but it's a good starting point.

Miklos
----

Index: linux/mm/memory.c
===================================================================

mm/memory.c 2008-01-15 21:16:14.000000000 +0100 renamed from mm/memory.c 2008-01-09 21:16:30.000000000 +0100 +2 -0
@@ -1680,6 +1680,8 @@ gotten:
 unlock:
        pte_unmap_unlock(page_table, ptl);
        if (dirty_page) {
+               if (vma->vm_file)
+                       file_update_time(vma->vm_file);
                /*
                 * Yes, Virginia, this is actually required to prevent a race
                 * with clear_page_dirty_for_io() from clearing the page dirty

mm/memory.c 2008-01-15 21:16:14.000000000 +0100 out_unlocked: · line 2322

Quoted 8 lines
mm/memory.c 2008-01-15 21:16:14.000000000 +0100 renamed from mm/memory.c 2008-01-09 21:16:30.000000000 +0100 +2 -0
@@ -2313,6 +2315,8 @@ out_unlocked:
        if (anon)
                page_cache_release(vmf.page);
        else if (dirty_page) {
+               if (vma->vm_file)
+                       file_update_time(vma->vm_file);
                set_page_dirty_balance(dirty_page, page_mkwrite);
                put_page(dirty_page);
        }

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>