]>
Commit | Line | Data |
---|---|---|
decd1569 | 1 | diff -Naur host/arch/i386/config.in host-ptrace/arch/i386/config.in |
2 | --- host/arch/i386/config.in Fri Aug 9 15:57:14 2002 | |
3 | +++ host-ptrace/arch/i386/config.in Sun Nov 10 18:40:09 2002 | |
4 | @@ -291,6 +291,8 @@ | |
5 | bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF | |
6 | fi | |
7 | ||
8 | +bool '/proc/mm' CONFIG_PROC_MM | |
9 | + | |
10 | endmenu | |
11 | ||
12 | source drivers/mtd/Config.in | |
13 | diff -Naur host/arch/i386/kernel/ldt.c host-ptrace/arch/i386/kernel/ldt.c | |
14 | --- host/arch/i386/kernel/ldt.c Fri Oct 26 00:01:41 2001 | |
15 | +++ host-ptrace/arch/i386/kernel/ldt.c Sun Nov 3 18:37:48 2002 | |
16 | @@ -24,11 +24,12 @@ | |
17 | * assured by user-space anyway. Writes are atomic, to protect | |
18 | * the security checks done on new descriptors. | |
19 | */ | |
20 | -static int read_ldt(void * ptr, unsigned long bytecount) | |
21 | +static int read_ldt(struct task_struct *task, void * ptr, | |
22 | + unsigned long bytecount) | |
23 | { | |
24 | int err; | |
25 | unsigned long size; | |
26 | - struct mm_struct * mm = current->mm; | |
27 | + struct mm_struct * mm = task->mm; | |
28 | ||
29 | err = 0; | |
30 | if (!mm->context.segments) | |
31 | @@ -64,9 +65,10 @@ | |
32 | return err; | |
33 | } | |
34 | ||
35 | -static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) | |
36 | +static int write_ldt(struct task_struct *task, void * ptr, | |
37 | + unsigned long bytecount, int oldmode) | |
38 | { | |
39 | - struct mm_struct * mm = current->mm; | |
40 | + struct mm_struct * mm = task->mm; | |
41 | __u32 entry_1, entry_2, *lp; | |
42 | int error; | |
43 | struct modify_ldt_ldt_s ldt_info; | |
44 | @@ -148,23 +150,29 @@ | |
45 | return error; | |
46 | } | |
47 | ||
48 | -asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) | |
49 | +int modify_ldt(struct task_struct *task, int func, void *ptr, | |
50 | + unsigned long bytecount) | |
51 | { | |
52 | int ret = -ENOSYS; | |
53 | ||
54 | switch (func) { | |
55 | case 0: | |
56 | - ret = read_ldt(ptr, bytecount); | |
57 | + ret = read_ldt(task, ptr, bytecount); | |
58 | break; | |
59 | case 1: | |
60 | - ret = write_ldt(ptr, bytecount, 1); | |
61 | + ret = write_ldt(task, ptr, bytecount, 1); | |
62 | break; | |
63 | case 2: | |
64 | ret = read_default_ldt(ptr, bytecount); | |
65 | break; | |
66 | case 0x11: | |
67 | - ret = write_ldt(ptr, bytecount, 0); | |
68 | + ret = write_ldt(task, ptr, bytecount, 0); | |
69 | break; | |
70 | } | |
71 | return ret; | |
72 | +} | |
73 | + | |
74 | +asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) | |
75 | +{ | |
76 | + return(modify_ldt(current, func, ptr, bytecount)); | |
77 | } | |
78 | diff -Naur host/arch/i386/kernel/process.c host-ptrace/arch/i386/kernel/process.c | |
79 | --- host/arch/i386/kernel/process.c Fri Aug 9 15:57:14 2002 | |
80 | +++ host-ptrace/arch/i386/kernel/process.c Wed Nov 6 22:12:45 2002 | |
81 | @@ -551,13 +551,11 @@ | |
82 | * we do not have to muck with descriptors here, that is | |
83 | * done in switch_mm() as needed. | |
84 | */ | |
85 | -void copy_segments(struct task_struct *p, struct mm_struct *new_mm) | |
86 | +void mm_copy_segments(struct mm_struct *old_mm, struct mm_struct *new_mm) | |
87 | { | |
88 | - struct mm_struct * old_mm; | |
89 | void *old_ldt, *ldt; | |
90 | ||
91 | ldt = NULL; | |
92 | - old_mm = current->mm; | |
93 | if (old_mm && (old_ldt = old_mm->context.segments) != NULL) { | |
94 | /* | |
95 | * Completely new LDT, we initialize it from the parent: | |
96 | @@ -570,6 +568,16 @@ | |
97 | } | |
98 | new_mm->context.segments = ldt; | |
99 | new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */ | |
100 | +} | |
101 | + | |
102 | +void copy_segments(struct task_struct *p, struct mm_struct *new_mm) | |
103 | +{ | |
104 | + mm_copy_segments(current->mm, new_mm); | |
105 | +} | |
106 | + | |
107 | +void copy_task_segments(struct task_struct *from, struct mm_struct *new_mm) | |
108 | +{ | |
109 | + mm_copy_segments(from->mm, new_mm); | |
110 | } | |
111 | ||
112 | /* | |
113 | diff -Naur host/arch/i386/kernel/ptrace.c host-ptrace/arch/i386/kernel/ptrace.c | |
114 | --- host/arch/i386/kernel/ptrace.c Fri Aug 9 15:57:14 2002 | |
115 | +++ host-ptrace/arch/i386/kernel/ptrace.c Mon Nov 11 19:03:38 2002 | |
116 | @@ -147,6 +147,11 @@ | |
117 | put_stack_long(child, EFL_OFFSET, tmp); | |
118 | } | |
119 | ||
120 | +extern int modify_ldt(struct task_struct *task, int func, void *ptr, | |
121 | + unsigned long bytecount); | |
122 | + | |
123 | +extern struct mm_struct *proc_mm_get_mm(int fd); | |
124 | + | |
125 | asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | |
126 | { | |
127 | struct task_struct *child; | |
128 | @@ -415,6 +420,53 @@ | |
129 | child->ptrace |= PT_TRACESYSGOOD; | |
130 | else | |
131 | child->ptrace &= ~PT_TRACESYSGOOD; | |
132 | + ret = 0; | |
133 | + break; | |
134 | + } | |
135 | + | |
136 | + case PTRACE_FAULTINFO: { | |
137 | + struct ptrace_faultinfo fault; | |
138 | + | |
139 | + fault = ((struct ptrace_faultinfo) | |
140 | + { .is_write = child->thread.error_code, | |
141 | + .addr = child->thread.cr2 }); | |
142 | + ret = copy_to_user((unsigned long *) data, &fault, | |
143 | + sizeof(fault)); | |
144 | + if(ret) | |
145 | + break; | |
146 | + break; | |
147 | + } | |
148 | + case PTRACE_SIGPENDING: | |
149 | + ret = copy_to_user((unsigned long *) data, | |
150 | + &child->pending.signal, | |
151 | + sizeof(child->pending.signal)); | |
152 | + break; | |
153 | + | |
154 | + case PTRACE_LDT: { | |
155 | + struct ptrace_ldt ldt; | |
156 | + | |
157 | + if(copy_from_user(&ldt, (unsigned long *) data, | |
158 | + sizeof(ldt))){ | |
159 | + ret = -EIO; | |
160 | + break; | |
161 | + } | |
162 | + ret = modify_ldt(child, ldt.func, ldt.ptr, ldt.bytecount); | |
163 | + break; | |
164 | + } | |
165 | + | |
166 | + case PTRACE_SWITCH_MM: { | |
167 | + struct mm_struct *old = child->mm; | |
168 | + struct mm_struct *new = proc_mm_get_mm(data); | |
169 | + | |
170 | + if(IS_ERR(new)){ | |
171 | + ret = PTR_ERR(new); | |
172 | + break; | |
173 | + } | |
174 | + | |
175 | + atomic_inc(&new->mm_users); | |
176 | + child->mm = new; | |
177 | + child->active_mm = new; | |
178 | + mmput(old); | |
179 | ret = 0; | |
180 | break; | |
181 | } | |
182 | diff -Naur host/arch/i386/kernel/sys_i386.c host-ptrace/arch/i386/kernel/sys_i386.c | |
183 | --- host/arch/i386/kernel/sys_i386.c Mon Mar 19 15:35:09 2001 | |
184 | +++ host-ptrace/arch/i386/kernel/sys_i386.c Mon Nov 11 17:23:25 2002 | |
185 | @@ -40,7 +40,7 @@ | |
186 | } | |
187 | ||
188 | /* common code for old and new mmaps */ | |
189 | -static inline long do_mmap2( | |
190 | +long do_mmap2(struct mm_struct *mm, | |
191 | unsigned long addr, unsigned long len, | |
192 | unsigned long prot, unsigned long flags, | |
193 | unsigned long fd, unsigned long pgoff) | |
194 | @@ -55,9 +55,9 @@ | |
195 | goto out; | |
196 | } | |
197 | ||
198 | - down_write(¤t->mm->mmap_sem); | |
199 | - error = do_mmap(file, addr, len, prot, flags, pgoff << PAGE_SHIFT); | |
200 | - up_write(¤t->mm->mmap_sem); | |
201 | + down_write(&mm->mmap_sem); | |
202 | + error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); | |
203 | + up_write(&mm->mmap_sem); | |
204 | ||
205 | if (file) | |
206 | fput(file); | |
207 | @@ -69,7 +69,7 @@ | |
208 | unsigned long prot, unsigned long flags, | |
209 | unsigned long fd, unsigned long pgoff) | |
210 | { | |
211 | - return do_mmap2(addr, len, prot, flags, fd, pgoff); | |
212 | + return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); | |
213 | } | |
214 | ||
215 | /* | |
216 | @@ -100,7 +100,7 @@ | |
217 | if (a.offset & ~PAGE_MASK) | |
218 | goto out; | |
219 | ||
220 | - err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); | |
221 | + err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); | |
222 | out: | |
223 | return err; | |
224 | } | |
225 | diff -Naur host/include/asm-i386/processor.h host-ptrace/include/asm-i386/processor.h | |
226 | --- host/include/asm-i386/processor.h Sun Nov 10 18:47:37 2002 | |
227 | +++ host-ptrace/include/asm-i386/processor.h Mon Nov 11 17:33:30 2002 | |
228 | @@ -436,6 +436,8 @@ | |
229 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | |
230 | ||
231 | /* Copy and release all segment info associated with a VM */ | |
232 | +extern void mm_copy_segments(struct mm_struct *old_mm, | |
233 | + struct mm_struct *new_mm); | |
234 | extern void copy_segments(struct task_struct *p, struct mm_struct * mm); | |
235 | extern void release_segments(struct mm_struct * mm); | |
236 | ||
237 | diff -Naur host/include/asm-i386/ptrace.h host-ptrace/include/asm-i386/ptrace.h | |
238 | --- host/include/asm-i386/ptrace.h Sun Sep 23 19:20:51 2001 | |
239 | +++ host-ptrace/include/asm-i386/ptrace.h Sun Nov 10 18:36:22 2002 | |
240 | @@ -51,6 +51,22 @@ | |
241 | ||
242 | #define PTRACE_SETOPTIONS 21 | |
243 | ||
244 | +struct ptrace_faultinfo { | |
245 | + int is_write; | |
246 | + unsigned long addr; | |
247 | +}; | |
248 | + | |
249 | +struct ptrace_ldt { | |
250 | + int func; | |
251 | + void *ptr; | |
252 | + unsigned long bytecount; | |
253 | +}; | |
254 | + | |
255 | +#define PTRACE_FAULTINFO 52 | |
256 | +#define PTRACE_SIGPENDING 53 | |
257 | +#define PTRACE_LDT 54 | |
258 | +#define PTRACE_SWITCH_MM 55 | |
259 | + | |
260 | /* options set using PTRACE_SETOPTIONS */ | |
261 | #define PTRACE_O_TRACESYSGOOD 0x00000001 | |
262 | ||
263 | diff -Naur host/include/linux/mm.h host-ptrace/include/linux/mm.h | |
264 | --- host/include/linux/mm.h Fri Aug 30 15:03:44 2002 | |
265 | +++ host-ptrace/include/linux/mm.h Mon Nov 11 19:08:53 2002 | |
266 | @@ -492,6 +492,9 @@ | |
267 | int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, | |
268 | int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); | |
269 | ||
270 | +extern long do_mprotect(struct mm_struct *mm, unsigned long start, | |
271 | + size_t len, unsigned long prot); | |
272 | + | |
273 | /* | |
274 | * On a two-level page table, this ends up being trivial. Thus the | |
275 | * inlining and the symmetry break with pte_alloc() that does all | |
276 | @@ -539,9 +542,10 @@ | |
277 | ||
278 | extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); | |
279 | ||
280 | -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, | |
281 | - unsigned long len, unsigned long prot, | |
282 | - unsigned long flag, unsigned long pgoff); | |
283 | +extern unsigned long do_mmap_pgoff(struct mm_struct *mm, | |
284 | + struct file *file, unsigned long addr, | |
285 | + unsigned long len, unsigned long prot, | |
286 | + unsigned long flag, unsigned long pgoff); | |
287 | ||
288 | static inline unsigned long do_mmap(struct file *file, unsigned long addr, | |
289 | unsigned long len, unsigned long prot, | |
290 | @@ -551,7 +555,7 @@ | |
291 | if ((offset + PAGE_ALIGN(len)) < offset) | |
292 | goto out; | |
293 | if (!(offset & ~PAGE_MASK)) | |
294 | - ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT); | |
295 | + ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT); | |
296 | ||
297 | #ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC | |
298 | #define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) | |
299 | diff -Naur host/include/linux/proc_mm.h host-ptrace/include/linux/proc_mm.h | |
300 | --- host/include/linux/proc_mm.h Wed Dec 31 19:00:00 1969 | |
301 | +++ host-ptrace/include/linux/proc_mm.h Mon Nov 11 17:41:09 2002 | |
302 | @@ -0,0 +1,44 @@ | |
303 | +/* | |
304 | + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | |
305 | + * Licensed under the GPL | |
306 | + */ | |
307 | + | |
308 | +#ifndef __PROC_MM_H | |
309 | +#define __PROC_MM_H | |
310 | + | |
311 | +#define MM_MMAP 54 | |
312 | +#define MM_MUNMAP 55 | |
313 | +#define MM_MPROTECT 56 | |
314 | +#define MM_COPY_SEGMENTS 57 | |
315 | + | |
316 | +struct mm_mmap { | |
317 | + unsigned long addr; | |
318 | + unsigned long len; | |
319 | + unsigned long prot; | |
320 | + unsigned long flags; | |
321 | + unsigned long fd; | |
322 | + unsigned long offset; | |
323 | +}; | |
324 | + | |
325 | +struct mm_munmap { | |
326 | + unsigned long addr; | |
327 | + unsigned long len; | |
328 | +}; | |
329 | + | |
330 | +struct mm_mprotect { | |
331 | + unsigned long addr; | |
332 | + unsigned long len; | |
333 | + unsigned int prot; | |
334 | +}; | |
335 | + | |
336 | +struct proc_mm_op { | |
337 | + int op; | |
338 | + union { | |
339 | + struct mm_mmap mmap; | |
340 | + struct mm_munmap munmap; | |
341 | + struct mm_mprotect mprotect; | |
342 | + int copy_segments; | |
343 | + } u; | |
344 | +}; | |
345 | + | |
346 | +#endif | |
347 | diff -Naur host/mm/Makefile host-ptrace/mm/Makefile | |
348 | --- host/mm/Makefile Fri Aug 9 15:57:31 2002 | |
349 | +++ host-ptrace/mm/Makefile Sun Nov 10 18:37:33 2002 | |
350 | @@ -17,5 +17,6 @@ | |
351 | shmem.o | |
352 | ||
353 | obj-$(CONFIG_HIGHMEM) += highmem.o | |
354 | +obj-$(CONFIG_PROC_MM) += proc_mm.o | |
355 | ||
356 | include $(TOPDIR)/Rules.make | |
357 | diff -Naur host/mm/mmap.c host-ptrace/mm/mmap.c | |
358 | --- host/mm/mmap.c Fri Aug 9 15:57:31 2002 | |
359 | +++ host-ptrace/mm/mmap.c Mon Nov 11 17:24:18 2002 | |
360 | @@ -390,10 +390,11 @@ | |
361 | return 0; | |
362 | } | |
363 | ||
364 | -unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len, | |
365 | - unsigned long prot, unsigned long flags, unsigned long pgoff) | |
366 | +unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, | |
367 | + unsigned long addr, unsigned long len, | |
368 | + unsigned long prot, unsigned long flags, | |
369 | + unsigned long pgoff) | |
370 | { | |
371 | - struct mm_struct * mm = current->mm; | |
372 | struct vm_area_struct * vma, * prev; | |
373 | unsigned int vm_flags; | |
374 | int correct_wcount = 0; | |
375 | diff -Naur host/mm/mprotect.c host-ptrace/mm/mprotect.c | |
376 | --- host/mm/mprotect.c Fri Aug 9 15:57:31 2002 | |
377 | +++ host-ptrace/mm/mprotect.c Mon Nov 11 17:47:58 2002 | |
378 | @@ -264,7 +264,8 @@ | |
379 | return 0; | |
380 | } | |
381 | ||
382 | -asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) | |
383 | +long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, | |
384 | + unsigned long prot) | |
385 | { | |
386 | unsigned long nstart, end, tmp; | |
387 | struct vm_area_struct * vma, * next, * prev; | |
388 | @@ -281,9 +282,9 @@ | |
389 | if (end == start) | |
390 | return 0; | |
391 | ||
392 | - down_write(¤t->mm->mmap_sem); | |
393 | + down_write(&mm->mmap_sem); | |
394 | ||
395 | - vma = find_vma_prev(current->mm, start, &prev); | |
396 | + vma = find_vma_prev(mm, start, &prev); | |
397 | error = -ENOMEM; | |
398 | if (!vma || vma->vm_start > start) | |
399 | goto out; | |
400 | @@ -332,6 +333,11 @@ | |
401 | } | |
402 | out: | |
403 | ||
404 | - up_write(¤t->mm->mmap_sem); | |
405 | + up_write(&mm->mmap_sem); | |
406 | return error; | |
407 | +} | |
408 | + | |
409 | +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) | |
410 | +{ | |
411 | + return(do_mprotect(current->mm, start, len, prot)); | |
412 | } | |
413 | diff -Naur host/mm/proc_mm.c host-ptrace/mm/proc_mm.c | |
414 | --- host/mm/proc_mm.c Wed Dec 31 19:00:00 1969 | |
415 | +++ host-ptrace/mm/proc_mm.c Mon Nov 11 19:07:52 2002 | |
416 | @@ -0,0 +1,173 @@ | |
417 | +/* | |
418 | + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | |
419 | + * Licensed under the GPL | |
420 | + */ | |
421 | + | |
422 | +#include "linux/proc_fs.h" | |
423 | +#include "linux/proc_mm.h" | |
424 | +#include "linux/file.h" | |
425 | +#include "asm/uaccess.h" | |
426 | +#include "asm/mmu_context.h" | |
427 | + | |
428 | +static struct file_operations proc_mm_fops; | |
429 | + | |
430 | +struct mm_struct *proc_mm_get_mm(int fd) | |
431 | +{ | |
432 | + struct mm_struct *ret = ERR_PTR(-EBADF); | |
433 | + struct file *file; | |
434 | + | |
435 | + file = fget(fd); | |
436 | + if (!file) | |
437 | + goto out; | |
438 | + | |
439 | + ret = ERR_PTR(-EINVAL); | |
440 | + if(file->f_op != &proc_mm_fops) | |
441 | + goto out_fput; | |
442 | + | |
443 | + ret = file->private_data; | |
444 | + | |
445 | + out_fput: | |
446 | + fput(file); | |
447 | + out: | |
448 | + return(ret); | |
449 | +} | |
450 | + | |
451 | +extern long do_mmap2(struct mm_struct *mm, unsigned long addr, | |
452 | + unsigned long len, unsigned long prot, | |
453 | + unsigned long flags, unsigned long fd, | |
454 | + unsigned long pgoff); | |
455 | + | |
456 | +static ssize_t write_proc_mm(struct file *file, const char *buffer, | |
457 | + size_t count, loff_t *ppos) | |
458 | +{ | |
459 | + struct mm_struct *mm = file->private_data; | |
460 | + struct proc_mm_op req; | |
461 | + int n, ret; | |
462 | + | |
463 | + if(count > sizeof(req)) | |
464 | + return(-EINVAL); | |
465 | + | |
466 | + n = copy_from_user(&req, buffer, count); | |
467 | + if(n != 0) | |
468 | + return(-EFAULT); | |
469 | + | |
470 | + ret = count; | |
471 | + switch(req.op){ | |
472 | + case MM_MMAP: { | |
473 | + struct mm_mmap *map = &req.u.mmap; | |
474 | + | |
475 | + ret = do_mmap2(mm, map->addr, map->len, map->prot, | |
476 | + map->flags, map->fd, map->offset >> PAGE_SHIFT); | |
477 | + if((ret & ~PAGE_MASK) == 0) | |
478 | + ret = count; | |
479 | + | |
480 | + break; | |
481 | + } | |
482 | + case MM_MUNMAP: { | |
483 | + struct mm_munmap *unmap = &req.u.munmap; | |
484 | + | |
485 | + down_write(&mm->mmap_sem); | |
486 | + ret = do_munmap(mm, unmap->addr, unmap->len); | |
487 | + up_write(&mm->mmap_sem); | |
488 | + | |
489 | + if(ret == 0) | |
490 | + ret = count; | |
491 | + break; | |
492 | + } | |
493 | + case MM_MPROTECT: { | |
494 | + struct mm_mprotect *protect = &req.u.mprotect; | |
495 | + | |
496 | + ret = do_mprotect(mm, protect->addr, protect->len, | |
497 | + protect->prot); | |
498 | + if(ret == 0) | |
499 | + ret = count; | |
500 | + break; | |
501 | + } | |
502 | + | |
503 | + case MM_COPY_SEGMENTS: { | |
504 | + struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments); | |
505 | + | |
506 | + if(IS_ERR(from)){ | |
507 | + ret = PTR_ERR(from); | |
508 | + break; | |
509 | + } | |
510 | + | |
511 | + mm_copy_segments(from, mm); | |
512 | + break; | |
513 | + } | |
514 | + default: | |
515 | + ret = -EINVAL; | |
516 | + break; | |
517 | + } | |
518 | + | |
519 | + return(ret); | |
520 | +} | |
521 | + | |
522 | +static int open_proc_mm(struct inode *inode, struct file *file) | |
523 | +{ | |
524 | + struct mm_struct *mm = mm_alloc(); | |
525 | + int ret; | |
526 | + | |
527 | + ret = -ENOMEM; | |
528 | + if(mm == NULL) | |
529 | + goto out_mem; | |
530 | + | |
531 | + ret = init_new_context(current, mm); | |
532 | + if(ret) | |
533 | + goto out_free; | |
534 | + | |
535 | + spin_lock(&mmlist_lock); | |
536 | + list_add(&mm->mmlist, ¤t->mm->mmlist); | |
537 | + mmlist_nr++; | |
538 | + spin_unlock(&mmlist_lock); | |
539 | + | |
540 | + file->private_data = mm; | |
541 | + | |
542 | + return(0); | |
543 | + | |
544 | + out_free: | |
545 | + mmput(mm); | |
546 | + out_mem: | |
547 | + return(ret); | |
548 | +} | |
549 | + | |
550 | +static int release_proc_mm(struct inode *inode, struct file *file) | |
551 | +{ | |
552 | + struct mm_struct *mm = file->private_data; | |
553 | + | |
554 | + mmput(mm); | |
555 | + return(0); | |
556 | +} | |
557 | + | |
558 | +static struct file_operations proc_mm_fops = { | |
559 | + .open = open_proc_mm, | |
560 | + .release = release_proc_mm, | |
561 | + .write = write_proc_mm, | |
562 | +}; | |
563 | + | |
564 | +static int make_proc_mm(void) | |
565 | +{ | |
566 | + struct proc_dir_entry *ent; | |
567 | + | |
568 | + ent = create_proc_entry("mm", 0222, &proc_root); | |
569 | + if(ent == NULL){ | |
570 | + printk("make_proc_mm : Failed to register /proc/mm\n"); | |
571 | + return(0); | |
572 | + } | |
573 | + ent->proc_fops = &proc_mm_fops; | |
574 | + | |
575 | + return(0); | |
576 | +} | |
577 | + | |
578 | +__initcall(make_proc_mm); | |
579 | + | |
580 | +/* | |
581 | + * Overrides for Emacs so that we follow Linus's tabbing style. | |
582 | + * Emacs will notice this stuff at the end of the file and automatically | |
583 | + * adjust the settings for this buffer only. This must remain at the end | |
584 | + * of the file. | |
585 | + * --------------------------------------------------------------------------- | |
586 | + * Local variables: | |
587 | + * c-file-style: "linux" | |
588 | + * End: | |
589 | + */ |