aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-16 19:01:50 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-16 19:01:50 -0500
commit4fb23e439ce09157d64b89a21061b9fc08f2b495 (patch)
tree168d6c75d6e0e7de5056b2a4736994c434e975dc /mm
parentc7ef259bfb4084d8806dfff9eb8bfc6e82bb8c45 (diff)
Fix up mm/mincore.c error value cases
Hugh Dickins correctly points out that mincore() is actually _supposed_ to fail on an unmapped hole in the user address space, rather than return valid ("empty") information about the hole. This just simplifies the problem further (I had been misled by our previous confusing and complicated way of doing mincore()). Also, in the unlikely situation that we can't allocate a temporary kernel buffer, we should actually return EAGAIN, not ENOMEM, to keep the "unmapped hole" and "allocation failure" error cases separate. Finally, add a comment about our stupid historical lack of support for anonymous mappings. I'll fix that if somebody reminds me after 2.6.20 is out. Acked-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/mincore.c29
1 files changed, 10 insertions, 19 deletions
diff --git a/mm/mincore.c b/mm/mincore.c
index b44d7f875cb6..566b6c2bae5f 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -49,29 +49,20 @@ static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pag
49 struct vm_area_struct *vma = find_vma(current->mm, addr); 49 struct vm_area_struct *vma = find_vma(current->mm, addr);
50 50
51 /* 51 /*
52 * find_vma() didn't find anything: the address 52 * find_vma() didn't find anything above us, or we're
53 * is above everything we have mapped. 53 * in an unmapped hole in the address space: ENOMEM.
54 */ 54 */
55 if (!vma) { 55 if (!vma || addr < vma->vm_start)
56 memset(vec, 0, pages); 56 return -ENOMEM;
57 return pages;
58 }
59
60 /*
61 * find_vma() found something, but we might be
62 * below it: check for that.
63 */
64 if (addr < vma->vm_start) {
65 unsigned long gap = (vma->vm_start - addr) >> PAGE_SHIFT;
66 if (gap > pages)
67 gap = pages;
68 memset(vec, 0, gap);
69 return gap;
70 }
71 57
72 /* 58 /*
73 * Ok, got it. But check whether it's a segment we support 59 * Ok, got it. But check whether it's a segment we support
74 * mincore() on. Right now, we don't do any anonymous mappings. 60 * mincore() on. Right now, we don't do any anonymous mappings.
61 *
62 * FIXME: This is just stupid. And returning ENOMEM is
63 * stupid too. We should just look at the page tables. But
64 * this is what we've traditionally done, so we'll just
65 * continue doing it.
75 */ 66 */
76 if (!vma->vm_file) 67 if (!vma->vm_file)
77 return -ENOMEM; 68 return -ENOMEM;
@@ -142,7 +133,7 @@ asmlinkage long sys_mincore(unsigned long start, size_t len,
142 133
143 tmp = (void *) __get_free_page(GFP_USER); 134 tmp = (void *) __get_free_page(GFP_USER);
144 if (!tmp) 135 if (!tmp)
145 return -ENOMEM; 136 return -EAGAIN;
146 137
147 retval = 0; 138 retval = 0;
148 while (pages) { 139 while (pages) {