Initial revision
[linux-2.6.git] / mm / proc_mm.c
1 /* 
2  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/mm.h"
7 #include "linux/init.h"
8 #include "linux/proc_fs.h"
9 #include "linux/proc_mm.h"
10 #include "linux/file.h"
11 #include "asm/uaccess.h"
12 #include "asm/mmu_context.h"
13
14 static struct file_operations proc_mm_fops;
15
16 struct mm_struct *proc_mm_get_mm(int fd)
17 {
18         struct mm_struct *ret = ERR_PTR(-EBADF);
19         struct file *file;
20
21         file = fget(fd);
22         if (!file)
23                 goto out;
24
25         ret = ERR_PTR(-EINVAL);
26         if(file->f_op != &proc_mm_fops)
27                 goto out_fput;
28
29         ret = file->private_data;
30  out_fput:
31         fput(file);
32  out:
33         return(ret);
34 }
35
36 extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
37                      unsigned long len, unsigned long prot, 
38                      unsigned long flags, unsigned long fd,
39                      unsigned long pgoff);
40
41 static ssize_t write_proc_mm(struct file *file, const char *buffer,
42                              size_t count, loff_t *ppos)
43 {
44         struct mm_struct *mm = file->private_data;
45         struct proc_mm_op req;
46         int n, ret;
47
48         if(count > sizeof(req))
49                 return(-EINVAL);
50
51         n = copy_from_user(&req, buffer, count);
52         if(n != 0)
53                 return(-EFAULT);
54
55         ret = count;
56         switch(req.op){
57         case MM_MMAP: {
58                 struct mm_mmap *map = &req.u.mmap;
59
60                 ret = do_mmap2(mm, map->addr, map->len, map->prot, 
61                                map->flags, map->fd, map->offset >> PAGE_SHIFT);
62                 if((ret & ~PAGE_MASK) == 0)
63                         ret = count;
64         
65                 break;
66         }
67         case MM_MUNMAP: {
68                 struct mm_munmap *unmap = &req.u.munmap;
69
70                 down_write(&mm->mmap_sem);
71                 ret = do_munmap(mm, unmap->addr, unmap->len);
72                 up_write(&mm->mmap_sem);
73
74                 if(ret == 0)
75                         ret = count;
76                 break;
77         }
78         case MM_MPROTECT: {
79                 struct mm_mprotect *protect = &req.u.mprotect;
80
81                 ret = do_mprotect(mm, protect->addr, protect->len, 
82                                   protect->prot);
83                 if(ret == 0)
84                         ret = count;
85                 break;
86         }
87
88         case MM_COPY_SEGMENTS: {
89                 struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
90
91                 if(IS_ERR(from)){
92                         ret = PTR_ERR(from);
93                         break;
94                 }
95
96                 mm_copy_segments(from, mm);
97                 break;
98         }
99         default:
100                 ret = -EINVAL;
101                 break;
102         }
103
104         return(ret);
105 }
106
107 static int open_proc_mm(struct inode *inode, struct file *file)
108 {
109         struct mm_struct *mm = mm_alloc();
110         int ret;
111
112         ret = -ENOMEM;
113         if(mm == NULL)
114                 goto out_mem;
115
116         ret = init_new_context(current, mm);
117         if(ret)
118                 goto out_free;
119
120         spin_lock(&mmlist_lock);
121         list_add(&mm->mmlist, &current->mm->mmlist);
122         mmlist_nr++;
123         spin_unlock(&mmlist_lock);
124
125         file->private_data = mm;
126
127         return(0);
128
129  out_free:
130         mmput(mm);
131  out_mem:
132         return(ret);
133 }
134
135 static int release_proc_mm(struct inode *inode, struct file *file)
136 {
137         struct mm_struct *mm = file->private_data;
138
139         mmput(mm);
140         return(0);
141 }
142
143 static struct file_operations proc_mm_fops = {
144         .open           = open_proc_mm,
145         .release        = release_proc_mm,
146         .write          = write_proc_mm,
147 };
148
149 static int make_proc_mm(void)
150 {
151         struct proc_dir_entry *ent;
152
153         ent = create_proc_entry("mm", 0222, &proc_root);
154         if(ent == NULL){
155                 printk("make_proc_mm : Failed to register /proc/mm\n");
156                 return(0);
157         }
158         ent->proc_fops = &proc_mm_fops;
159
160         return(0);
161 }
162
163 __initcall(make_proc_mm);
164
165 /*
166  * Overrides for Emacs so that we follow Linus's tabbing style.
167  * Emacs will notice this stuff at the end of the file and automatically
168  * adjust the settings for this buffer only.  This must remain at the end
169  * of the file.
170  * ---------------------------------------------------------------------------
171  * Local variables:
172  * c-file-style: "linux"
173  * End:
174  */