diff options
author | Andrew Morton <akpm@osdl.org> | 2006-03-24 06:18:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-24 10:33:26 -0500 |
commit | 707c21c848deeb0200ba3f07e4ba90e6dc419c2f (patch) | |
tree | d8e8f32916ac1f04e45e42595ddd0ef771ddb1ad | |
parent | 9c50823eebf7c256b92b4e0f02b5fb30e97788c2 (diff) |
[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, | |||
132 | unsigned long end, int flags, | 132 | unsigned long end, int flags, |
133 | unsigned long *nr_pages_dirtied) | 133 | unsigned long *nr_pages_dirtied) |
134 | { | 134 | { |
135 | int ret = 0; | ||
136 | struct file *file = vma->vm_file; | 135 | struct file *file = vma->vm_file; |
137 | 136 | ||
138 | if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) | 137 | if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) |
139 | return -EBUSY; | 138 | return -EBUSY; |
140 | 139 | ||
141 | if (file && (vma->vm_flags & VM_SHARED)) { | 140 | if (file && (vma->vm_flags & VM_SHARED)) |
142 | *nr_pages_dirtied = msync_page_range(vma, addr, end); | 141 | *nr_pages_dirtied = msync_page_range(vma, addr, end); |
143 | 142 | return 0; | |
144 | if (flags & MS_SYNC) { | ||
145 | struct address_space *mapping = file->f_mapping; | ||
146 | int err; | ||
147 | |||
148 | ret = filemap_fdatawrite(mapping); | ||
149 | if (file->f_op && file->f_op->fsync) { | ||
150 | /* | ||
151 | * We don't take i_mutex here because mmap_sem | ||
152 | * is already held. | ||
153 | */ | ||
154 | err = file->f_op->fsync(file,file->f_dentry,1); | ||
155 | if (err && !ret) | ||
156 | ret = err; | ||
157 | } | ||
158 | err = filemap_fdatawait(mapping); | ||
159 | if (!ret) | ||
160 | ret = err; | ||
161 | } | ||
162 | } | ||
163 | return ret; | ||
164 | } | 143 | } |
165 | 144 | ||
166 | asmlinkage long sys_msync(unsigned long start, size_t len, int flags) | 145 | 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) | |||
233 | fput(file); | 212 | fput(file); |
234 | down_read(¤t->mm->mmap_sem); | 213 | down_read(¤t->mm->mmap_sem); |
235 | vma = find_vma(current->mm, start); | 214 | vma = find_vma(current->mm, start); |
215 | } else if ((flags & MS_SYNC) && file && | ||
216 | (vma->vm_flags & VM_SHARED)) { | ||
217 | struct address_space *mapping; | ||
218 | int err; | ||
219 | |||
220 | get_file(file); | ||
221 | up_read(¤t->mm->mmap_sem); | ||
222 | mapping = file->f_mapping; | ||
223 | error = filemap_fdatawrite(mapping); | ||
224 | if (file->f_op && file->f_op->fsync) { | ||
225 | mutex_lock(&mapping->host->i_mutex); | ||
226 | err = file->f_op->fsync(file,file->f_dentry,1); | ||
227 | mutex_unlock(&mapping->host->i_mutex); | ||
228 | if (err && !error) | ||
229 | error = err; | ||
230 | } | ||
231 | err = filemap_fdatawait(mapping); | ||
232 | if (err && !error) | ||
233 | error = err; | ||
234 | fput(file); | ||
235 | down_read(¤t->mm->mmap_sem); | ||
236 | if (error) | ||
237 | goto out_unlock; | ||
238 | vma = find_vma(current->mm, start); | ||
236 | } else { | 239 | } else { |
237 | vma = vma->vm_next; | 240 | vma = vma->vm_next; |
238 | } | 241 | } |