updating the ctime and mtime time stamps in msync()
Subsystems (2)
RFC PATCH 1/1 updating the ctime and mtime time stamps in msync()
Due to the lack of reaction in LKML I presume the message was lost in the high traffic of that list. Resending it now with the addressee changed to the memory management mailing list.
I would like to propose my solution for the bug #2645 from the kernel bug tracker:
http://bugzilla.kernel.org/show_bug.cgi?id=2645
The Open Group defines the behavior of the mmap() function as follows.
The st_ctime and st_mtime fields of a file that is mapped with MAP_SHARED and PROT_WRITE shall be marked for update at some point in the interval between a write reference to the mapped region and the next call to msync() with MS_ASYNC or MS_SYNC for that portion of the file by any process. If there is no such call and if the underlying file is modified as a result of a write reference, then these fields shall be marked for update at some time after the write reference.
The above citation was taken from the following link:
http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html
Therefore, the msync() function should be called before verifying the time stamps st_mtime and st_ctime in the test program Badari wrote in the context of the bug #2645. Otherwise, the time stamps may be updated
at some unspecified moment according to the POSIX standard.
I changed his test program a little. The changed unit test can be downloaded using the following link:
http://pygx.sourceforge.net/mmap.c
This program showed that the msync() function had a bug:
it did not update the st_mtime and st_ctime fields.
The program shows appropriate behavior of the msync() function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between the mmap() and msync() system calls.
Additionally, the test cases for the msync() system call from the LTP test suite (msync01 - msync05, mmapstress01, mmapstress09, and mmapstress10) successfully passed using the kernel with the patch included into this email.
The patch adds a call to the file_update_time() function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using the PAGE_ALIGN() macro instead of "manual" alignment, improved readability of the loop, which traverses the process memory regions, updated comments.
---
mm/msync.c +48 -44
@@ -1,26 +1,32 @@/* * linux/mm/msync.c * +* The msync() system call. * Copyright (C) 1994-1999 Linus Torvalds +* +* Updating the mtime and ctime stamps for mapped files +* and 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 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
@@ -33,70 +39,68 @@ 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; -if (start & ~PAGE_MASK ) +if ((flags & ~(MS_ASYNC |MS_INVALIDATE |MS_SYNC )) || + (start & ~PAGE_MASK ) || + ((flags &MS_ASYNC ) && (flags &MS_SYNC ))) { + error = -EINVAL ; goto out; -if ((flags &MS_ASYNC ) && (flags &MS_SYNC )) - goto out; - error = -ENOMEM ; - len = (len + ~PAGE_MASK ) &PAGE_MASK ; + } + + len =PAGE_ALIGN (len); end = start + len; -if (end < start) +if (end < start) { + error = -ENOMEM ; goto out; - error =0 ; + }if (end == start) goto out; +/* * 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 )) { error = -EBUSY ; - goto out_unlock; +break ; } file = vma->vm_file; - start = vma->vm_end; -if ((flags &MS_SYNC ) && file && - (vma->vm_flags &VM_SHARED )) { +if (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; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; +if (file->f_mapping->host->i_state &I_DIRTY_PAGES ) +file_update_time (file); +if (flags &MS_SYNC ) { +up_read (&mm->mmap_sem); + error =do_fsync (file,0 ); +down_read (&mm->mmap_sem); } - vma = vma->vm_next; +fput (file); +if (error) +break ; } - } -out_unlock: + + start = vma->vm_end; + vma = vma->vm_next; + }while (start < end);up_read (&mm->mmap_sem); out:return 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>
Since no reaction in LKML was recieved for this message it seemed logical to suggest closing the bug #2645 as "WONTFIX":
http://bugzilla.kernel.org/show_bug.cgi?id=2645#c15
However, the reporter of the bug, Jacob Oestergaard, insisted the solution to be resubmitted once more:
Quoted 1 line
Quoted 1 line
Quoted 1 line
Please re-submit to LKML.
This bug causes backup systems to *miss* changed files.
This bug does cause data loss in common real-world deployments (I gave an example with a database when posting the bug, but this affects the data from all mmap using applications with common backup systems).
Silent exclusion from backups is very very nasty.
<<<
Please comment on my solution or commit it if it's acceptable in its present form.
2008/1/7, Anton Salikhmetov <[email protected]>:
Quoted 202 lines
From: Anton Salikhmetov <[email protected]>
Due to the lack of reaction in LKML I presume the message was lost in the high traffic of that list. Resending it now with the addressee changed to the memory management mailing list.
I would like to propose my solution for the bug #2645 from the kernel bug tracker:
http://bugzilla.kernel.org/show_bug.cgi?id=2645
The Open Group defines the behavior of the
mmap()function as follows.The
st_ctimeandst_mtimefields of a file that is mapped withMAP_SHAREDandPROT_WRITEshall be marked for update at some point in the interval between a write reference to the mapped region and the next call tomsync()withMS_ASYNCorMS_SYNCfor that portion of the file by any process. If there is no such call and if the underlying file is modified as a result of a write reference, then these fields shall be marked for update at some time after the write reference.The above citation was taken from the following link:
http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html
Therefore, the
msync()function should be called before verifying the time stampsst_mtimeandst_ctimein the test program Badari wrote in the context of the bug #2645. Otherwise, the time stamps may be updated
at some unspecified moment according to the POSIX standard.I changed his test program a little. The changed unit test can be downloaded using the following link:
http://pygx.sourceforge.net/mmap.c
This program showed that the
msync()function had a bug:
it did not update thest_mtimeandst_ctimefields.The program shows appropriate behavior of the
msync()function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between themmap()andmsync()system calls.Additionally, the test cases for the
msync()system call from the LTP test suite (msync01 - msync05, mmapstress01, mmapstress09, and mmapstress10) successfully passed using the kernel with the patch included into this email.The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment, improved readability of the loop, which traverses the process memory regions, updated comments.Signed-off-by Anton Salikhmetov <[email protected]>---
mm/msync.c +44
-42@@ -1,26 +1,32 @@/* * linux/mm/msync.c * +* The msync() system call. * Copyright (C) 1994-1999 Linus Torvalds +* +* Updating the mtime and ctime stamps for mapped files +* and 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 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 @@ -33,70 +39,68 @@ 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; -if (start & ~PAGE_MASK ) +if ((flags & ~(MS_ASYNC |MS_INVALIDATE |MS_SYNC )) || + (start & ~PAGE_MASK ) || + ((flags &MS_ASYNC ) && (flags &MS_SYNC ))) { + error = -EINVAL ; goto out; -if ((flags &MS_ASYNC ) && (flags &MS_SYNC )) - goto out; - error = -ENOMEM ; - len = (len + ~PAGE_MASK ) &PAGE_MASK ; + } + + len =PAGE_ALIGN (len); end = start + len; -if (end < start) +if (end < start) { + error = -ENOMEM ; goto out; - error =0 ; + }if (end == start) goto out; +/* * 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)) { error = -EBUSY; - goto out_unlock; + break; } file = vma->vm_file; - start = vma->vm_end; -if ((flags &MS_SYNC ) && file && - (vma->vm_flags &VM_SHARED )) { + if (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; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; + if (file->f_mapping->host->i_state & I_DIRTY_PAGES) + file_update_time(file); + if (flags & MS_SYNC) { + up_read(&mm->mmap_sem); + error = do_fsync(file, 0); + down_read(&mm->mmap_sem); } - vma = vma->vm_next; + fput(file); + if (error) + break;
mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 106
Quoted 10 lines
mm/msync.c +4
-2} - } -out_unlock: + + start = vma->vm_end; + vma = vma->vm_next; + }while (start < end);up_read (&mm->mmap_sem); out:return 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>
Quoted 4 lines · Anton Salikhmetov
Since no reaction in LKML was recieved for this message it seemed logical to suggest closing the bug #2645 as "WONTFIX":
Thank you!
A quick run-down for those who don't know what this is about:
Some applications use mmap() to modify files. Common examples are databases.
Linux does not update the mtime of files that are modified using mmap, even if msync() is called.
This is very clearly against OpenGroup specifications.
This misfeatures causes such files to be silently *excluded* from normal backup runs.
Solaris implements this properly.
NT has the same bug as Linux, using their private bastardisation of the mmap interface - but since they don't care about SuS and are broken in so many other ways, that really doesn't matter.
So, dear kernel developers, can we please integrate this patch to make Linux stop silently excluding peoples databases from their backup?
Signature · 7 lines
/ jakob -- 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>
On Wed, Jan 09, 2008 at 02:32:53PM +0300, Anton Salikhmetov wrote:
...
Quoted 3 lines
This bug causes backup systems to *miss* changed files.
This problem is seen with both Amanda and TSM (Tivoli Storage Manager).
A site running Amanda with, say, a full backup weekly and incremental backups daily, will only get weekly backups of their mmap modified databases.
However, large sites running TSM will be hit even harder by this because TSM will always perform incremental backups from the client (managing which versions to keep for how long on the server side). TSM will *never* again take a backup of the mmap modified database.
The really nasty part is; nothing is failing. Everything *appears* to work. Your data is just not backed up because it appears to be untouched.
So, if you run TSM (or pretty much any other backup solution actually) on Linux, maybe you should run a
find / -type f -print0 | xargs -0 touch
before starting your backup job. Sort of removes the point of using proper backup software, but at least you'll get your data backed up.
Signature · 7 lines
/ jakob -- 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>
Quoted 8 lines · Anton Salikhmetov
Since no reaction in LKML was recieved for this message it seemed logical to suggest closing the bug #2645 as "WONTFIX":
http://bugzilla.kernel.org/show_bug.cgi?id=2645#c15
However, the reporter of the bug, Jacob Oestergaard, insisted the solution to be resubmitted once more:
Good idea. The bug is real and should be fixed IMHO.
...
Quoted 6 lines
This bug causes backup systems to *miss* changed files.
This bug does cause data loss in common real-world deployments (I gave an example with a database when posting the bug, but this affects the data from all mmap using applications with common backup systems).
Not just backup systems, but any application that relies on mtime being correctly updated will be bitten by this.
Quoted 2 lines
Silent exclusion from backups is very very nasty.
Agreed.
In fact if mtime is not reliable (which it is not) one could argue that we might as well not update it at all, ever. But I think we can all agree that just fixing it (as your patch does) is a lot better.
Quoted 3 lines
Please comment on my solution or commit it if it's acceptable in its present form.
I've only looked briefly at your patch but it seems resonable. I'll try to do some testing with it later.
Thank you for working on this long standing bug.
...
Quoted 14 lines
Quoted 14 lines
I would like to propose my solution for the bug #2645 from the kernel bug tracker:
http://bugzilla.kernel.org/show_bug.cgi?id=2645
The Open Group defines the behavior of the
mmap()function as follows.The
st_ctimeandst_mtimefields of a file that is mapped withMAP_SHAREDandPROT_WRITEshall be marked for update at some point in the interval between a write reference to the mapped region and the next call tomsync()withMS_ASYNCorMS_SYNCfor that portion of the file by any process. If there is no such call and if the underlying file is modified as a result of a write reference, then these fields shall be marked for update at some time after the write reference.
Quoted 4 lines
Quoted 4 lines
The above citation was taken from the following link:
http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html
...
I agree that our current behaviour is certainly not what the standard (sensibly) requires.
Signature · 9 lines
Jesper Juhl <[email protected]> Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html Plain text mails only, please http://www.expita.com/nomime.html -- 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>
2008/1/9, Jesper Juhl <[email protected]>:
Quoted 2 lines
I've only looked briefly at your patch but it seems resonable. I'll try to do some testing with it later.
Jesper, thank you very much for your answer!
In fact, I tested my change quite extensively using test cases for the mmap() and msync() system calls from the LTP test suite. Please note that I did mention that in my previous message:
Quoted 1 line
Quoted 1 line
Quoted 1 line
Additionally, the test cases for the msync() system call from the LTP test suite (msync01 - msync05, mmapstress01, mmapstress09, and mmapstress10) successfully passed using the kernel with the patch included into this email.
<<<
--
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>
Quoted 13 lines · Anton Salikhmetov
Since no reaction in LKML was recieved for this message it seemed logical to suggest closing the bug #2645 as "WONTFIX":
http://bugzilla.kernel.org/show_bug.cgi?id=2645#c15
However, the reporter of the bug, Jacob Oestergaard, insisted the solution to be resubmitted once more:
Please re-submit to LKML.
Yes, please!
Let's have the right discussion and get this bug addressed for real. It is a real bug and is causing data corruption for some very large Red Hat customers because their applications were architected to use mmap, but their backups are not backing up the modified files due to this aspect of the system.
This is the 4'th or 5'th attempt in the last 2 years to submit a patch to address this situation. None have been able to make it all of the way through the process and to be integrated.
I posted some comments.
Thanx...
ps
Quoted 225 lines
This bug causes backup systems to *miss* changed files.
This bug does cause data loss in common real-world deployments (I gave an example with a database when posting the bug, but this affects the data from all mmap using applications with common backup systems).
Silent exclusion from backups is very very nasty.
<<<
Please comment on my solution or commit it if it's acceptable in its present form.
2008/1/7, Anton Salikhmetov <[email protected]>:
Quoted 210 lines
From: Anton Salikhmetov <[email protected]>
Due to the lack of reaction in LKML I presume the message was lost in the high traffic of that list. Resending it now with the addressee changed to the memory management mailing list.
I would like to propose my solution for the bug #2645 from the kernel bug tracker:
http://bugzilla.kernel.org/show_bug.cgi?id=2645
The Open Group defines the behavior of the
mmap()function as follows.The
st_ctimeandst_mtimefields of a file that is mapped withMAP_SHAREDandPROT_WRITEshall be marked for update at some point in the interval between a write reference to the mapped region and the next call tomsync()withMS_ASYNCorMS_SYNCfor that portion of the file by any process. If there is no such call and if the underlying file is modified as a result of a write reference, then these fields shall be marked for update at some time after the write reference.The above citation was taken from the following link:
http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html
Therefore, the
msync()function should be called before verifying the time stampsst_mtimeandst_ctimein the test program Badari wrote in the context of the bug #2645. Otherwise, the time stamps may be updated
at some unspecified moment according to the POSIX standard.I changed his test program a little. The changed unit test can be downloaded using the following link:
http://pygx.sourceforge.net/mmap.c
This program showed that the
msync()function had a bug:
it did not update thest_mtimeandst_ctimefields.The program shows appropriate behavior of the
msync()function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between themmap()andmsync()system calls.Additionally, the test cases for the
msync()system call from the LTP test suite (msync01 - msync05, mmapstress01, mmapstress09, and mmapstress10) successfully passed using the kernel with the patch included into this email.The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment, improved readability of the loop, which traverses the process memory regions, updated comments.Signed-off-by Anton Salikhmetov <[email protected]>---
mm/msync.c +48
-44@@ -1,26 +1,32 @@/* * linux/mm/msync.c * +* The msync() system call. * Copyright (C) 1994-1999 Linus Torvalds +* +* Updating the mtime and ctime stamps for mapped files +* and 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 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 @@ -33,70 +39,68 @@ 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; -if (start & ~PAGE_MASK ) +if ((flags & ~(MS_ASYNC |MS_INVALIDATE |MS_SYNC )) || + (start & ~PAGE_MASK ) || + ((flags &MS_ASYNC ) && (flags &MS_SYNC ))) { + error = -EINVAL ; goto out; -if ((flags &MS_ASYNC ) && (flags &MS_SYNC )) - goto out; - error = -ENOMEM ; - len = (len + ~PAGE_MASK ) &PAGE_MASK ; + } + + len =PAGE_ALIGN (len); end = start + len; -if (end < start) +if (end < start) { + error = -ENOMEM ; goto out; - error =0 ; + }if (end == start) goto out; +/* * 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 )) { error = -EBUSY ; - goto out_unlock; +break ; } file = vma->vm_file; - start = vma->vm_end; -if ((flags &MS_SYNC ) && file && - (vma->vm_flags &VM_SHARED )) { +if (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; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; +if (file->f_mapping->host->i_state &I_DIRTY_PAGES ) +file_update_time (file); +if (flags &MS_SYNC ) { +up_read (&mm->mmap_sem); + error =do_fsync (file,0 ); +down_read (&mm->mmap_sem); } - vma = vma->vm_next; +fput (file); +if (error) +break ; } - } -out_unlock: + + start = vma->vm_end; + vma = vma->vm_next; + }while (start < end);up_read (&mm->mmap_sem); out:return error ? : unmapped_error;
Quoted 9 lines
Quoted 3 lines
--
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/
--
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>
Quoted 9 lines · On Mon, 07 Jan 2008 20:54:19 +0300 Anton Salikhmetov <[email protected]>…
This program showed that the
msync()function had a bug:
it did not update thest_mtimeandst_ctimefields.The program shows appropriate behavior of the
msync()function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between themmap()andmsync()system calls.
As long as the ctime and mtime stamps change when the memory is written to, what exactly is the problem?
Is it that the ctime and mtime does not change again when the memory is written to again?
Is there a way for backup programs to miss file modification times?
Could you explain (using short words and simple sentences) what the exact problem is?
Eg.
1) program mmaps file
2) program writes to mmaped area
3) ??? <=== this part, in equally simple words :)
4) data loss
An explanation like that will help people understand exactly what the bug is, and why the patch should be applied ASAP.
Quoted 6 lines
The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment, improved readability of the loop, which traverses the process memory regions, updated comments.
Due to the various cleanups all being in one file, it took me a while to understand the patch. In an area of code this subtle, it may be better to submit the cleanups in (a) separate patch(es) from the patch that adds the call to file_update_time().
Quoted 6 lines
mm/msync.c +1
-4- (vma->vm_flags & VM_SHARED)) { +if (file && (vma->vm_flags &VM_SHARED )) {get_file (file); -up_read (&mm->mmap_sem); - error =do_fsync (file,0 ); -fput (file);
mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 90
Quoted 10 lines
mm/msync.c +2
-8-if (error || start >= end) - goto out; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; +if (file->f_mapping->host->i_state &I_DIRTY_PAGES ) +file_update_time (file);
I wonder if calling file_update_time() from inside the loop is the best idea. Why not call that function just once, after msync breaks from the loop?
thanks,
Rik
Signature · 7 lines
All Rights Reversed -- 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>
Quoted 7 lines · Rik van Riel
Quoted 4 lines
Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between the
mmap()andmsync()system calls.As long as the ctime and mtime stamps change when the memory is written to, what exactly is the problem?
A "not" is missing from the sentence above. The quote above should have read:
Quoted 3 lines
Quoted 3 lines
Specifically, the ctime and mtime time stamps do _not_ change when modifying the mapped memory and do not change when there have been no write references between the
mmap()andmsync()system calls.
So essentially the problem is that mtime stamps are _never_ changed when the file is only modified through mmap. Not even when calling msync().
Signature · 8 lines
Kind regards, Klaus S. Madsen -- 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>
Quoted 9 lines · Rik van Riel
Could you explain (using short words and simple sentences) what the exact problem is?
Eg.
1) program mmaps file
2) program writes to mmaped area
3) ??? <=== this part, in equally simple words :)
4) data loss
It's like this:
Monday 9:04AM: System boots, database server starts up, mmaps file Monday 9:06AM: Database server writes to mmap area, updates mtime/ctime
Monday <many times> Database server writes to mmap area, no further update.. Monday 11:45PM: Backup sees "file modified 9:06AM, let's back it up" Tuesday 9:00AM-5:00PM: Database server touches it another 5,398 times, no mtime Tuesday 11:45PM: Backup sees "file modified back on Monday, we backed this up.. Wed 9:00AM-5:00PM: More updates, more not touching the mtime
Wed 11:45PM: *yawn* It hasn't been touched in 2 days, no sense in backing it up..
Lather, rinse, repeat....
Quoted 9 lines · On Wed, 09 Jan 2008 16:06:17 -0500 [email protected] wrote:
Quoted 2 lines · Rik van Riel
Could you explain (using short words and simple sentences) what the exact problem is?
It's like this:
Monday 9:04AM: System boots, database server starts up, mmaps file Monday 9:06AM: Database server writes to mmap area, updates mtime/ctime
Quoted 8 lines
Monday <many times> Database server writes to mmap area, no further update.. Monday 11:45PM: Backup sees "file modified 9:06AM, let's back it up" Tuesday 9:00AM-5:00PM: Database server touches it another 5,398 times, no mtime Tuesday 11:45PM: Backup sees "file modified back on Monday, we backed this up.. Wed 9:00AM-5:00PM: More updates, more not touching the mtime
Wed 11:45PM: *yawn* It hasn't been touched in 2 days, no sense in backing it up..Lather, rinse, repeat....
On the other hand, updating the mtime and ctime whenever a page is dirtied also does not work right. Apparently that can break mutt.
Calling msync() every once in a while with Anton's patch does not look like a fool proof method to me either, because the VM can write all the dirty pages to disk by itself, leaving nothing for msync() to detect. (I think...)
Can we get by with simply updating the ctime and mtime every time msync() is called, regardless of whether or not the mmaped pages were still dirty by the time we called msync() ?
Signature · 7 lines
All Rights Reversed -- 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>
Quoted 20 lines · Rik van Riel
Quoted 17 lines · On Wed, 09 Jan 2008 16:06:17 -0500 [email protected] wrote:
Quoted 3 lines · Rik van Riel
Could you explain (using short words and simple sentences) what the exact problem is?
It's like this:
Monday 9:04AM: System boots, database server starts up, mmaps file Monday 9:06AM: Database server writes to mmap area, updates mtime/ctimeMonday <many times> Database server writes to mmap area, no further update.. Monday 11:45PM: Backup sees "file modified 9:06AM, let's back it up" Tuesday 9:00AM-5:00PM: Database server touches it another 5,398 times, no mtime Tuesday 11:45PM: Backup sees "file modified back on Monday, we backed this up.. Wed 9:00AM-5:00PM: More updates, more not touching the mtime
Wed 11:45PM: *yawn* It hasn't been touched in 2 days, no sense in backing it up..
Quoted 7 lines
Quoted 2 lines
Lather, rinse, repeat....
On the other hand, updating the mtime and ctime whenever a page is dirtied also does not work right. Apparently that can break mutt.
Could you elaborate on why that would break mutt? I am assuming that the pages being modified are mmap'd, but if they are not, then it is very clear why mutt (and anything else) would break.
Quoted 7 lines
Calling
msync()every once in a while with Anton's patch does not look like a fool proof method to me either, because the VM can write all the dirty pages to disk by itself, leaving nothing formsync()to detect. (I think...)Can we get by with simply updating the ctime and mtime every time
msync()is called, regardless of whether or not the mmaped pages were still dirty by the time we calledmsync()?
As long as we can keep track of that information and then remember it for an munmap so that eventually the file times do get updated, then this should work.
It would seem that a better solution would be to update the file times whenever the inode gets cleaned, ie. modified pages written out and the inode synchronized to the disk. That way, long running programs would not have to msync occasionally in order to have the data file properly backed up.
Thanx...
ps
ps
--
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>
On Wed, Jan 09, 2008 at 05:06:33PM -0500, Rik van Riel wrote:
...
Quoted 2 lines
Quoted 2 lines
Lather, rinse, repeat....
Just verified this at one customer site; they had a db that was last backed up in 2003 :/
Quoted 4 lines
On the other hand, updating the mtime and ctime whenever a page is dirtied also does not work right. Apparently that can break mutt.
Thinking back on the atime discussion, I bet there would be some performance problems in updating the ctime/mtime that often too :)
Quoted 3 lines
Calling
msync()every once in a while with Anton's patch does not look like a fool proof method to me either, because the VM can write all the dirty pages to disk by itself, leaving nothing formsync()to detect. (I think...)
Reading the man page:
"The st_ctime and st_mtime fields of a file that is mapped with MAP_SHARED and PROT_WRITE will be marked for update at some point in the interval between a write reference to the mapped region and the next call to msync() with MS_ASYNC or MS_SYNC for that portion of the file by any process. If there is no such call, these fields may be marked for update at any time after a write reference if the underlying file is modified as a result."
So, whenever someone writes in the region, this must cause us to update the mtime/ctime no later than at the time of the next call to msync().
Could one do something like the lazy atime updates, coupled with a forced flush at msync()?
Quoted 3 lines
Can we get by with simply updating the ctime and mtime every time
msync()is called, regardless of whether or not the mmaped pages were still dirty by the time we calledmsync()?
The update must still happen, eventually, after a write to the mapped region followed by an unmap/close even if no msync is ever called.
The msync only serves as a "no later than" deadline. The write to the region triggers the need for the update.
At least this is how I read the standard - please feel free to correct me if I am mistaken.
Signature · 7 lines
/ jakob -- 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>
Quoted 6 lines · On Wed, 9 Jan 2008 23:33:40 +0100 Jakob Oestergaard <[email protected]> wrote:
Quoted 3 lines · Rik van Riel
Can we get by with simply updating the ctime and mtime every time
msync()is called, regardless of whether or not the mmaped pages were still dirty by the time we calledmsync()?
Quoted 8 lines
The update must still happen, eventually, after a write to the mapped region followed by an unmap/close even if no msync is ever called.
The msync only serves as a "no later than" deadline. The write to the region triggers the need for the update.
At least this is how I read the standard - please feel free to correct me if I am mistaken.
You are absolutely right. If we wrote dirty pages to disk, the ctime and mtime updates must happen no later than msync or close time.
I guess a third possible time (if we want to minimize the number of updates) would be when natural syncing of the file data to disk, by other things in the VM, would be about to clear the I_DIRTY_PAGES flag on the inode. That way we do not need to remember any special "we already flushed all dirty data, but we have not updated the mtime and ctime yet" state.
Does this sound reasonable?
Signature · 7 lines
All rights reversed. -- 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>
2008/1/10, Rik van Riel <[email protected]>:
Quoted 20 lines
Quoted 6 lines · On Wed, 9 Jan 2008 23:33:40 +0100 Jakob Oestergaard <[email protected]> wrote:
Quoted 3 lines · Rik van Riel
Can we get by with simply updating the ctime and mtime every time
msync()is called, regardless of whether or not the mmaped pages were still dirty by the time we calledmsync()?Quoted 8 lines
The update must still happen, eventually, after a write to the mapped region followed by an unmap/close even if no msync is ever called.
The msync only serves as a "no later than" deadline. The write to the region triggers the need for the update.
At least this is how I read the standard - please feel free to correct me if I am mistaken.
You are absolutely right. If we wrote dirty pages to disk, the ctime and mtime updates must happen no later than msync or close time.
Quoted 8 lines
I guess a third possible time (if we want to minimize the number of updates) would be when natural syncing of the file data to disk, by other things in the VM, would be about to clear the
I_DIRTY_PAGESflag on the inode. That way we do not need to remember any special "we already flushed all dirty data, but we have not updated the mtime and ctime yet" state.Does this sound reasonable?
No, it doesn't. The msync() system call called with the MS_ASYNC flag should (the POSIX standard requires that) update the st_ctime and st_mtime stamps in the same manner as for the MS_SYNC flag. However, the current implementation of msync() doesn't call the do_fsync() function for the MS_ASYNC case. The msync() function may be called with the MS_ASYNC flag before "natural syncing".
--
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>
On Thu, Jan 10, 2008 at 03:03:03AM +0300, Anton Salikhmetov wrote:
...
Quoted 7 lines
Quoted 7 lines
I guess a third possible time (if we want to minimize the number of updates) would be when natural syncing of the file data to disk, by other things in the VM, would be about to clear the
I_DIRTY_PAGESflag on the inode. That way we do not need to remember any special "we already flushed all dirty data, but we have not updated the mtime and ctime yet" state.
Quoted 8 lines
Quoted 1 line
Does this sound reasonable?
No, it doesn't. The
msync()system call called with theMS_ASYNCflag should (the POSIX standard requires that) update thest_ctimeandst_mtimestamps in the same manner as for theMS_SYNCflag. However, the current implementation ofmsync()doesn't call thedo_fsync()function for theMS_ASYNCcase. Themsync()function may be called with theMS_ASYNCflag before "natural syncing".
If the update was done as Rik suggested, with the addition that msync() triggered an explicit sync of the inode data, then everything would be ok, right?
Signature · 7 lines
/ jakob -- 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>
2008/1/10, Jakob Oestergaard <[email protected]>:
Quoted 18 lines · Anton Salikhmetov
...
Quoted 7 lines
Quoted 7 lines
I guess a third possible time (if we want to minimize the number of updates) would be when natural syncing of the file data to disk, by other things in the VM, would be about to clear the
I_DIRTY_PAGESflag on the inode. That way we do not need to remember any special "we already flushed all dirty data, but we have not updated the mtime and ctime yet" state.Quoted 8 lines
Quoted 1 line
Does this sound reasonable?
No, it doesn't. The
msync()system call called with theMS_ASYNCflag should (the POSIX standard requires that) update thest_ctimeandst_mtimestamps in the same manner as for theMS_SYNCflag. However, the current implementation ofmsync()doesn't call thedo_fsync()function for theMS_ASYNCcase. Themsync()function may be called with theMS_ASYNCflag before "natural syncing".
Quoted 3 lines
If the update was done as Rik suggested, with the addition that
msync()triggered an explicit sync of the inode data, then everything would be ok, right?
Indeed, if msync() is called with MS_SYNC an explicit sync is triggered, and Rik's suggestion would work. However, the POSIX standard requires a call to msync() with MS_ASYNC to update the st_ctime and st_mtime stamps too. No explicit sync of the inode data is triggered in the current implementation of msync(). Hence Rik's suggestion would fail to satisfy POSIX in the latter case.
Quoted 6 lines
--
/ jakob
--
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>
Quoted 6 lines · On Thu, 10 Jan 2008 13:53:59 +0300 "Anton Salikhmetov" <[email protected]>…
Indeed, if
msync()is called withMS_SYNCan explicit sync is triggered, and Rik's suggestion would work. However, the POSIX standard requires a call tomsync()withMS_ASYNCto update thest_ctimeandst_mtimestamps too. No explicit sync of the inode data is triggered in the current implementation ofmsync(). Hence Rik's suggestion would fail to satisfy POSIX in the latter case.
Since your patch is already changing msync(), has it occurred to you that your patch could change msync() to do the right thing?
Signature · 7 lines
All rights reversed. -- 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>
2008/1/10, Rik van Riel <[email protected]>:
Quoted 10 lines
Quoted 6 lines · On Thu, 10 Jan 2008 13:53:59 +0300 "Anton Salikhmetov" <[email protected]>…
Indeed, if
msync()is called withMS_SYNCan explicit sync is triggered, and Rik's suggestion would work. However, the POSIX standard requires a call tomsync()withMS_ASYNCto update thest_ctimeandst_mtimestamps too. No explicit sync of the inode data is triggered in the current implementation ofmsync(). Hence Rik's suggestion would fail to satisfy POSIX in the latter case.
Quoted 3 lines
Since your patch is already changing
msync(), has it occurred to you that your patch could changemsync()to do the right thing?
No, not quite. Peter Staubach mentioned an issue in my solution:
Quoted 10 lines
Quoted 1 line
Quoted 1 line
The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment check, improved readability of the loop, which traverses the process memory regions, updated comments.
These changes catch the simple case, where the file is mmap'd, modified via the mmap'd region, and then an msync is done, all on a mostly quiet system.
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process, I_DIRTY_PAGES will be cleared, thus causing a miss in this code.
The I_DIRTY_PAGES check here is good, but I think that there needs to be some code elsewhere too, to catch the case where I_DIRTY_PAGES is being cleared, but the time fields still need to be updated.
<<<
So I'm working on my next solution for this bug now.
Quoted 4 lines
--
All rights reversed.
--
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>
Quoted 10 lines · On Thu, 10 Jan 2008 18:56:07 +0300 "Anton Salikhmetov" <[email protected]>…
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process,
I_DIRTY_PAGESwill be cleared, thus causing a miss in this code.The
I_DIRTY_PAGEScheck here is good, but I think that there needs to be some code elsewhere too, to catch the case whereI_DIRTY_PAGESis being cleared, but the time fields still need to be updated.
Agreed. The mtime and ctime should probably also be updated when I_DIRTY_PAGES is cleared.
The alternative would be to remember that the inode had been dirty in the past, and have the mtime and ctime updated on msync or close - which would be more complex.
Signature · 7 lines
All rights reversed. -- 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>
2008/1/10, Rik van Riel <[email protected]>:
Quoted 14 lines
Quoted 10 lines · On Thu, 10 Jan 2008 18:56:07 +0300 "Anton Salikhmetov" <[email protected]>…
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process,
I_DIRTY_PAGESwill be cleared, thus causing a miss in this code.The
I_DIRTY_PAGEScheck here is good, but I think that there needs to be some code elsewhere too, to catch the case whereI_DIRTY_PAGESis being cleared, but the time fields still need to be updated.
Quoted 6 lines
Agreed. The mtime and ctime should probably also be updated when
I_DIRTY_PAGESis cleared.The alternative would be to remember that the inode had been dirty in the past, and have the mtime and ctime updated on msync or close - which would be more complex.
Adding the new flag (AS_MCTIME) has been already suggested by Peter Staubach in his first solution for this bug. Now I understand that the AS_MCTIME flag is required for fixing the bug.
Quoted 4 lines
--
All rights reversed.
--
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>
Quoted 20 lines · Anton Salikhmetov
2008/1/10, Rik van Riel <[email protected]>:
Quoted 18 lines
Quoted 11 lines · On Thu, 10 Jan 2008 18:56:07 +0300 "Anton Salikhmetov" <[email protected]>…
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process,
I_DIRTY_PAGESwill be cleared, thus causing a miss in this code.The
I_DIRTY_PAGEScheck here is good, but I think that there needs to be some code elsewhere too, to catch the case whereI_DIRTY_PAGESis being cleared, but the time fields still need to be updated.Agreed. The mtime and ctime should probably also be updated when
I_DIRTY_PAGESis cleared.
Quoted 8 lines
Quoted 4 lines
The alternative would be to remember that the inode had been dirty in the past, and have the mtime and ctime updated on msync or close - which would be more complex.
Adding the new flag (
AS_MCTIME) has been already suggested by Peter Staubach in his first solution for this bug. Now I understand that theAS_MCTIMEflag is required for fixing the bug.
Well, that was the approach before we had I_DIRTY_PAGES. I am still wondering whether we can get this approach to work, with a little more support and heuristics. PeterZ's work to better track dirty pages should be helpful in determining when and why a patch was dirty.
I keep thinking that by recording the time when a page was found to be dirty and the file is mmap'd and then updating the mtime and ctime fields in the inode during msync() and sync_single_inode() if that time is newer than the mtime and ctime fields, then we can solve the problem of when and when not to update those two time fields.
I haven't had a chance to think it all through completely or do the appropriate analysis yet though.
ps
--
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>
Quoted 16 lines · Rik van Riel
Quoted 11 lines · On Thu, 10 Jan 2008 18:56:07 +0300 "Anton Salikhmetov" <[email protected]>…
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process,
I_DIRTY_PAGESwill be cleared, thus causing a miss in this code.The
I_DIRTY_PAGEScheck here is good, but I think that there needs to be some code elsewhere too, to catch the case whereI_DIRTY_PAGESis being cleared, but the time fields still need to be updated.
Quoted 6 lines
Agreed. The mtime and ctime should probably also be updated when
I_DIRTY_PAGESis cleared.The alternative would be to remember that the inode had been dirty in the past, and have the mtime and ctime updated on msync or close - which would be more complex.
And also remembering that the file times should not be updated if the pages were modified via a write(2) operation. Or if there has been an intervening write(2) operation...
The number of cases to consider and the boundary conditions quickly make this reasonably complex to get right. That's why this is the 4'th or 5'th attempt in the last 18 months or so to get this situation addressed.
ps
--
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>
Quoted 8 lines · Rik van Riel
I guess a third possible time (if we want to minimize the number of updates) would be when natural syncing of the file data to disk, by other things in the VM, would be about to clear the
I_DIRTY_PAGESflag on the inode. That way we do not need to remember any special "we already flushed all dirty data, but we have not updated the mtime and ctime yet" state.Does this sound reasonable?
Is it possible that a *very* large file (multi-gigabyte or even bigger database, for example) would never get out of I_DIRTY_PAGES, because there's always a few dozen just-recently dirtied pages that haven't made it out to disk yet?
Of course, getting a *consistent* backup of a file like that is quite the challenge already, because of the high likelyhood of the file being changed while the backup runs - that's why big sites often do a 'quiesce/snapshot/wakeup' on a database and then backup the snapshot...
2008/1/10, Rik van Riel <[email protected]>:
Quoted 18 lines
Quoted 16 lines · On Wed, 09 Jan 2008 16:06:17 -0500 [email protected] wrote:
Quoted 2 lines · Rik van Riel
Could you explain (using short words and simple sentences) what the exact problem is?
It's like this:
Monday 9:04AM: System boots, database server starts up, mmaps file Monday 9:06AM: Database server writes to mmap area, updates mtime/ctimeMonday <many times> Database server writes to mmap area, no further update.. Monday 11:45PM: Backup sees "file modified 9:06AM, let's back it up" Tuesday 9:00AM-5:00PM: Database server touches it another 5,398 times, no mtime Tuesday 11:45PM: Backup sees "file modified back on Monday, we backed this up.. Wed 9:00AM-5:00PM: More updates, more not touching the mtime
Wed 11:45PM: *yawn* It hasn't been touched in 2 days, no sense in backing it up..
Quoted 4 lines
Quoted 1 line
Lather, rinse, repeat....
On the other hand, updating the mtime and ctime whenever a page is dirtied also does not work right. Apparently that can break mutt.
Please tell why you think that can break mutt? Such approach was suggested by Peter once and looks reasonable to me too.
Quoted 5 lines
Calling
msync()every once in a while with Anton's patch does not look like a fool proof method to me either, because the VM can write all the dirty pages to disk by itself, leaving nothing formsync()to detect. (I think...)
Quoted 7 lines
Can we get by with simply updating the ctime and mtime every time
msync()is called, regardless of whether or not the mmaped pages were still dirty by the time we calledmsync()?--
All Rights Reversed
--
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>
2008/1/9, Rik van Riel <[email protected]>:
Quoted 41 lines
Quoted 9 lines · On Mon, 07 Jan 2008 20:54:19 +0300 Anton Salikhmetov <[email protected]>…
This program showed that the
msync()function had a bug:
it did not update thest_mtimeandst_ctimefields.The program shows appropriate behavior of the
msync()function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between themmap()andmsync()system calls.As long as the ctime and mtime stamps change when the memory is written to, what exactly is the problem?
Is it that the ctime and mtime does not change again when the memory is written to again?
Is there a way for backup programs to miss file modification times?
Could you explain (using short words and simple sentences) what the exact problem is?
Eg.
1) program mmaps file
2) program writes to mmaped area
3) ??? <=== this part, in equally simple words :)
4) data lossAn explanation like that will help people understand exactly what the bug is, and why the patch should be applied ASAP.
Quoted 6 lines
The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment, improved readability of the loop, which traverses the process memory regions, updated comments.
Quoted 4 lines
Due to the various cleanups all being in one file, it took me a while to understand the patch. In an area of code this subtle, it may be better to submit the cleanups in (a) separate patch(es) from the patch that adds the call to
file_update_time().
Now I'm working on my next solution for this bug. It will probably modify more than one file and be split into several parts.
Quoted 18 lines
Quoted 7 lines
mm/msync.c +1
-4- (vma->vm_flags & VM_SHARED)) { +if (file && (vma->vm_flags &VM_SHARED )) {get_file (file); -up_read (&mm->mmap_sem); - error =do_fsync (file,0 ); -fput (file);mm/msync.c asmlinkage long sys_msync(unsigned long start, size_t len, int flags) · line 90
Quoted 10 lines
mm/msync.c +2
-8-if (error || start >= end) - goto out; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; +if (file->f_mapping->host->i_state &I_DIRTY_PAGES ) +file_update_time (file);
Quoted 3 lines
I wonder if calling
file_update_time()from inside the loop is the best idea. Why not call that function just once, after msync breaks from the loop?
That function should be called inside of the loop because the memory region, which msync() is called with, may contain pages mapped for different files.
Quoted 7 lines
thanks,
Rik
--
All Rights Reversed
--
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>
Quoted 33 lines · Anton Salikhmetov
From: Anton Salikhmetov <[email protected]>
I would like to propose my solution for the bug #2645 from the kernel bug tracker:
http://bugzilla.kernel.org/show_bug.cgi?id=2645
The Open Group defines the behavior of the
mmap()function as follows.The
st_ctimeandst_mtimefields of a file that is mapped withMAP_SHAREDandPROT_WRITEshall be marked for update at some point in the interval between a write reference to the mapped region and the next call tomsync()withMS_ASYNCorMS_SYNCfor that portion of the file by any process. If there is no such call and if the underlying file is modified as a result of a write reference, then these fields shall be marked for update at some time after the write reference.The above citation was taken from the following link:
http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html
Therefore, the
msync()function should be called before verifying the time stampsst_mtimeandst_ctimein the test program Badari wrote in the context of the bug #2645. Otherwise, the time stamps may be updated
at some unspecified moment according to the POSIX standard.I changed his test program a little. The changed unit test can be downloaded using the following link:
http://pygx.sourceforge.net/mmap.c
This program showed that the
msync()function had a bug:
it did not update thest_mtimeandst_ctimefields.
Quoted 8 lines
The program shows the appropriate behavior of the
msync()function using the kernel with the proposed patch applied. Specifically, the ctime and mtime time stamps do change when modifying the mapped memory and do not change when there have been no write references between themmap()andmsync()system calls.
Sorry, I don't see where the test program shows that the file times did not change if there had not been an intervening modification to the mmap'd region. It appears to me that it just shows the file times changing or not when there has been intervening modification after the mmap call and before the fstat call.
Or am I looking in the wrong place? :-)
Quoted 5 lines
Additionally, the test cases for the
msync()system call from the LTP test suite (msync01 - msync05, mmapstress01, mmapstress09, and mmapstress10) successfully passed using the kernel with the patch included into this email.
Quoted 8 lines
The patch adds a call to the
file_update_time()function to change the file metadata before syncing. The patch also contains substantial code cleanup: consolidated error check
for function parameters, using thePAGE_ALIGN()macro instead of "manual" alignment check, improved readability of the loop, which traverses the process memory regions, updated comments.
These changes catch the simple case, where the file is mmap'd, modified via the mmap'd region, and then an msync is done, all on a mostly quiet system.
However, I don't see how they will work if there has been something like a sync(2) done after the mmap'd region is modified and the msync call. When the inode is written out as part of the sync process, I_DIRTY_PAGES will be cleared, thus causing a miss in this code.
The I_DIRTY_PAGES check here is good, but I think that there needs to be some code elsewhere too, to catch the case where I_DIRTY_PAGES is being cleared, but the time fields still need to be updated.
Signature · 11 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.
Thanx...
psQuoted 157 lines
Signed-off-by Anton Salikhmetov <[email protected]>---
mm/msync.c +5
-0@@ -1,26 +1,32 @@/* * linux/mm/msync.c * +* The msync() system call. * Copyright (C) 1994-1999 Linus Torvalds +* +* Updating the mtime and ctime stamps for mapped files +* and code cleanup. +* Copyright (C) 2008 Anton Salikhmetov <[email protected]> */ Quoted 1 line
-/*
- * The
msync()system call.
- */mm/msync.c +2
-2+#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> Quoted 1 line
/*
*
MS_SYNCsyncs the entire file - including mappings.
*
*MS_ASYNCdoes 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. *
+ * Themsync()system call updates the ctime and mtime fields for
+ * the mapped file when called with theMS_SYNCorMS_ASYNCflags
+ * according to the POSIX standard.
+ *
* The application may now runfsync()to
* write out the dirty pages and wait on the writeout and check the result.
* Or the application may runfadvise(FADV_DONTNEED)against the fd to startmm/msync.c +13
-11@@ -33,70 +39,68 @@ 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; -if (start & ~PAGE_MASK ) +if ((flags & ~(MS_ASYNC |MS_INVALIDATE |MS_SYNC )) || + (start & ~PAGE_MASK ) || + ((flags &MS_ASYNC ) && (flags &MS_SYNC ))) { + error = -EINVAL ; goto out; -if ((flags &MS_ASYNC ) && (flags &MS_SYNC )) - goto out; - error = -ENOMEM ; - len = (len + ~PAGE_MASK ) &PAGE_MASK ; + } + + len =PAGE_ALIGN (len); end = start + len; -if (end < start) +if (end < start) { + error = -ENOMEM ; goto out; - error =0 ; + }if (end == start) goto out; +/* * 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;Quoted 1 line
- /* Still start < end. */
mm/msync.c +23
-26- 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 )) { error = -EBUSY ; - goto out_unlock; +break ; } file = vma->vm_file; - start = vma->vm_end; -if ((flags &MS_SYNC ) && file && - (vma->vm_flags &VM_SHARED )) { +if (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; -down_read (&mm->mmap_sem); - vma =find_vma (mm, start); - }else { -if (start >= end) { - error =0 ; - goto out_unlock; +if (file->f_mapping->host->i_state &I_DIRTY_PAGES ) +file_update_time (file); +if (flags &MS_SYNC ) { +up_read (&mm->mmap_sem); + error =do_fsync (file,0 ); +down_read (&mm->mmap_sem); } - vma = vma->vm_next; +fput (file); +if (error) +break ; } - } -out_unlock: + + start = vma->vm_end; + vma = vma->vm_next; + }while (start < end);up_read (&mm->mmap_sem); out:return error ? : unmapped_error; --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/
Signature · 10 lines
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/ -- 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>