1
2
3
4
5
6
7
8
9
10#include <linux/slab.h>
11#include <linux/pagemap.h>
12#include <linux/mm.h>
13#include <linux/mman.h>
14
15#include <asm/uaccess.h>
16#include <asm/pgtable.h>
17#include <asm/pgalloc.h>
18
19
20
21
22
23
24
25static unsigned char mincore_page(struct vm_area_struct * vma,
26 unsigned long pgoff)
27{
28 unsigned char present = 0;
29 struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping;
30 struct page * page;
31
32 page = find_get_page(as, pgoff);
33 if (page) {
34 present = PageUptodate(page);
35 page_cache_release(page);
36 }
37
38 return present;
39}
40
41static long mincore_vma(struct vm_area_struct * vma,
42 unsigned long start, unsigned long end, unsigned char * vec)
43{
44 long error, i, remaining;
45 unsigned char * tmp;
46
47 error = -ENOMEM;
48 if (!vma->vm_file)
49 return error;
50
51 start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
52 if (end > vma->vm_end)
53 end = vma->vm_end;
54 end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
55
56 error = -EAGAIN;
57 tmp = (unsigned char *) __get_free_page(GFP_KERNEL);
58 if (!tmp)
59 return error;
60
61
62 remaining = (end - start),
63
64 error = 0;
65 for (i = 0; remaining > 0; remaining -= PAGE_SIZE, i++) {
66 int j = 0;
67 long thispiece = (remaining < PAGE_SIZE) ?
68 remaining : PAGE_SIZE;
69
70 while (j < thispiece)
71 tmp[j++] = mincore_page(vma, start++);
72
73 if (copy_to_user(vec + PAGE_SIZE * i, tmp, thispiece)) {
74 error = -EFAULT;
75 break;
76 }
77 }
78
79 free_page((unsigned long) tmp);
80 return error;
81}
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108asmlinkage long sys_mincore(unsigned long start, size_t len,
109 unsigned char * vec)
110{
111 int index = 0;
112 unsigned long end;
113 struct vm_area_struct * vma;
114 int unmapped_error = 0;
115 long error = -EINVAL;
116
117 down_read(¤t->mm->mmap_sem);
118
119 if (start & ~PAGE_CACHE_MASK)
120 goto out;
121 len = (len + ~PAGE_CACHE_MASK) & PAGE_CACHE_MASK;
122 end = start + len;
123 if (end < start)
124 goto out;
125
126 error = -EFAULT;
127 if (!access_ok(VERIFY_WRITE, (unsigned long) vec, len >> PAGE_SHIFT))
128 goto out;
129
130 error = 0;
131 if (end == start)
132 goto out;
133
134
135
136
137
138 vma = find_vma(current->mm, start);
139 for (;;) {
140
141 error = -ENOMEM;
142 if (!vma)
143 goto out;
144
145
146 if (start < vma->vm_start) {
147 unmapped_error = -ENOMEM;
148 start = vma->vm_start;
149 }
150
151
152 if (end <= vma->vm_end) {
153 if (start < end) {
154 error = mincore_vma(vma, start, end,
155 &vec[index]);
156 if (error)
157 goto out;
158 }
159 error = unmapped_error;
160 goto out;
161 }
162
163
164 error = mincore_vma(vma, start, vma->vm_end, &vec[index]);
165 if (error)
166 goto out;
167 index += (vma->vm_end - start) >> PAGE_CACHE_SHIFT;
168 start = vma->vm_end;
169 vma = vma->vm_next;
170 }
171
172out:
173 up_read(¤t->mm->mmap_sem);
174 return error;
175}
176