diff options
author | Andrew Morton <akpm@osdl.org> | 2006-03-24 03:18:13 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-24 07:33:26 -0800 |
commit | 707c21c848deeb0200ba3f07e4ba90e6dc419c2f (patch) | |
tree | d8e8f32916ac1f04e45e42595ddd0ef771ddb1ad | |
parent | 9c50823eebf7c256b92b4e0f02b5fb30e97788c2 (diff) | |
download | linux-707c21c848deeb0200ba3f07e4ba90e6dc419c2f.tar.bz2 |
[PATCH] msync(MS_SYNC): don't hold mmap_sem while syncing
It seems bad to hold mmap_sem while performing synchronous disk I/O. Alter
the msync(MS_SYNC) code so that the lock is released while we sync the file.
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | mm/msync.c | 49 |
1 files changed, 26 insertions, 23 deletions
diff --git a/mm/msync.c b/mm/msync.c index 8a66f5d5d4f0..ee9bd6759833 100644 --- a/mm/msync.c +++ b/mm/msync.c @@ -132,35 +132,14 @@ static int msync_interval(struct vm_area_struct *vma, unsigned long addr, unsigned long end, int flags, unsigned long *nr_pages_dirtied) { - int ret = 0; struct file *file = vma->vm_file; if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) return -EBUSY; - if (file && (vma->vm_flags & VM_SHARED)) { + if (file && (vma->vm_flags & VM_SHARED)) *nr_pages_dirtied = msync_page_range(vma, addr, end); - - if (flags & MS_SYNC) { - struct address_space *mapping = file->f_mapping; - int err; - - ret = filemap_fdatawrite(mapping); - if (file->f_op && file->f_op->fsync) { - /* - * We don't take i_mutex here because mmap_sem - * is already held. - */ - err = file->f_op->fsync(file,file->f_dentry,1); - if (err && !ret) - ret = err; - } - err = filemap_fdatawait(mapping); - if (!ret) - ret = err; - } - } - return ret; + return 0; } asmlinkage long sys_msync(unsigned long start, size_t len, int flags) @@ -233,6 +212,30 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) fput(file); down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm, start); + } else if ((flags & MS_SYNC) && file && + (vma->vm_flags & VM_SHARED)) { + struct address_space *mapping; + int err; + + get_file(file); + up_read(¤t->mm->mmap_sem); + mapping = file->f_mapping; + error = filemap_fdatawrite(mapping); + if (file->f_op && file->f_op->fsync) { + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file,file->f_dentry,1); + mutex_unlock(&mapping->host->i_mutex); + if (err && !error) + error = err; + } + err = filemap_fdatawait(mapping); + if (err && !error) + error = err; + fput(file); + down_read(¤t->mm->mmap_sem); + if (error) + goto out_unlock; + vma = find_vma(current->mm, start); } else { vma = vma->vm_next; } |