diff options
author | Andrew Morton <akpm@osdl.org> | 2006-03-24 06:18:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-24 10:33:26 -0500 |
commit | 676758bdb7bfca8413a85203921746f446e237be (patch) | |
tree | 23c731f429652e16f2cdba98cd503eaa059f929b | |
parent | 707c21c848deeb0200ba3f07e4ba90e6dc419c2f (diff) |
[PATCH] msync: fix return value
msync() does a strange thing. Essentially:
vma = find_vma();
for ( ; ; ) {
if (!vma)
return -ENOMEM;
...
vma = vma->vm_next;
}
so an msync() request which starts within or before a valid VMA and which ends
within or beyond the final VMA will incorrectly return -ENOMEM.
Fix.
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 | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/mm/msync.c b/mm/msync.c index ee9bd6759833..d6a50f3f28b6 100644 --- a/mm/msync.c +++ b/mm/msync.c | |||
@@ -146,7 +146,8 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) | |||
146 | { | 146 | { |
147 | unsigned long end; | 147 | unsigned long end; |
148 | struct vm_area_struct *vma; | 148 | struct vm_area_struct *vma; |
149 | int unmapped_error, error = -EINVAL; | 149 | int unmapped_error = 0; |
150 | int error = -EINVAL; | ||
150 | int done = 0; | 151 | int done = 0; |
151 | 152 | ||
152 | if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) | 153 | if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) |
@@ -171,15 +172,14 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) | |||
171 | if (flags & MS_SYNC) | 172 | if (flags & MS_SYNC) |
172 | current->flags |= PF_SYNCWRITE; | 173 | current->flags |= PF_SYNCWRITE; |
173 | vma = find_vma(current->mm, start); | 174 | vma = find_vma(current->mm, start); |
174 | unmapped_error = 0; | 175 | if (!vma) { |
176 | error = -ENOMEM; | ||
177 | goto out_unlock; | ||
178 | } | ||
175 | do { | 179 | do { |
176 | unsigned long nr_pages_dirtied = 0; | 180 | unsigned long nr_pages_dirtied = 0; |
177 | struct file *file; | 181 | struct file *file; |
178 | 182 | ||
179 | /* Still start < end. */ | ||
180 | error = -ENOMEM; | ||
181 | if (!vma) | ||
182 | goto out_unlock; | ||
183 | /* Here start < vma->vm_end. */ | 183 | /* Here start < vma->vm_end. */ |
184 | if (start < vma->vm_start) { | 184 | if (start < vma->vm_start) { |
185 | unmapped_error = -ENOMEM; | 185 | unmapped_error = -ENOMEM; |
@@ -239,7 +239,7 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) | |||
239 | } else { | 239 | } else { |
240 | vma = vma->vm_next; | 240 | vma = vma->vm_next; |
241 | } | 241 | } |
242 | } while (!done); | 242 | } while (vma && !done); |
243 | out_unlock: | 243 | out_unlock: |
244 | current->flags &= ~PF_SYNCWRITE; | 244 | current->flags &= ~PF_SYNCWRITE; |
245 | up_read(¤t->mm->mmap_sem); | 245 | up_read(¤t->mm->mmap_sem); |