This stack check implementation leverages the compiler's profiling (gcc -p)
[linux-2.6.git] / arch / um / kernel / filehandle.c
1 /* 
2  * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/slab.h"
7 #include "linux/list.h"
8 #include "linux/spinlock.h"
9 #include "linux/fs.h"
10 #include "linux/errno.h"
11 #include "filehandle.h"
12 #include "os.h"
13 #include "kern_util.h"
14
15 static spinlock_t open_files_lock = SPIN_LOCK_UNLOCKED;
16 static struct list_head open_files = LIST_HEAD_INIT(open_files);
17
18 #define NUM_RECLAIM 128
19
20 static void reclaim_fds(void)
21 {
22         struct file_handle *victim;
23         int closed = NUM_RECLAIM;
24
25         spin_lock(&open_files_lock);
26         while(!list_empty(&open_files) && closed--){
27                 victim = list_entry(open_files.prev, struct file_handle, list);
28                 os_close_file(victim->fd);
29                 victim->fd = -1;
30                 list_del_init(&victim->list);
31         }
32         spin_unlock(&open_files_lock);
33 }
34
35 int open_file(char *name, struct openflags flags, int mode)
36 {
37         int fd;
38
39         fd = os_open_file(name, flags, mode);
40         if(fd != -EMFILE)
41                 return(fd);
42
43         reclaim_fds();
44         fd = os_open_file(name, flags, mode);
45
46         return(fd);
47 }
48
49 void *open_dir(char *file)
50 {
51         void *dir;
52         int err;
53
54         dir = os_open_dir(file, &err);
55         if(dir != NULL)
56                 return(dir);
57         if(err != -EMFILE)
58                 return(ERR_PTR(err));
59
60         reclaim_fds();
61
62         dir = os_open_dir(file, &err);
63         if(dir == NULL)
64                 dir = ERR_PTR(err);
65
66         return(dir);
67 }
68
69 void not_reclaimable(struct file_handle *fh)
70 {
71         char *name;
72
73         if(fh->get_name == NULL)
74                 return;
75
76         if(list_empty(&fh->list)){
77                 name = (*fh->get_name)(fh->inode);
78                 if(name != NULL){
79                         fh->fd = open_file(name, fh->flags, 0);
80                         kfree(name);
81                 }
82                 else printk("File descriptor %d has no name\n", fh->fd);
83         }
84         else {
85                 spin_lock(&open_files_lock);
86                 list_del_init(&fh->list);
87                 spin_unlock(&open_files_lock);
88         }
89 }
90
91 void is_reclaimable(struct file_handle *fh, char *(name_proc)(struct inode *),
92                     struct inode *inode)
93 {
94         fh->get_name = name_proc;
95         fh->inode = inode;
96
97         spin_lock(&open_files_lock);
98         list_add(&fh->list, &open_files);
99         spin_unlock(&open_files_lock);
100 }
101
102 static int active_handle(struct file_handle *fh)
103 {
104         int fd;
105         char *name;
106
107         if(!list_empty(&fh->list))
108                 list_move(&fh->list, &open_files);
109
110         if(fh->fd != -1)
111                 return(0);
112
113         if(fh->inode == NULL)
114                 return(-ENOENT);
115
116         name = (*fh->get_name)(fh->inode);
117         if(name == NULL)
118                 return(-ENOMEM);
119
120         fd = open_file(name, fh->flags, 0);
121         kfree(name);
122         if(fd < 0)
123                 return(fd);
124
125         fh->fd = fd;
126         is_reclaimable(fh, fh->get_name, fh->inode);
127
128         return(0);
129 }
130
131 int filehandle_fd(struct file_handle *fh)
132 {
133         int err;
134
135         err = active_handle(fh);
136         if(err)
137                 return(err);
138
139         return(fh->fd);
140 }
141
142 static void init_fh(struct file_handle *fh, int fd, struct openflags flags)
143 {
144         flags.c = 0;
145         *fh = ((struct file_handle) { .list     = LIST_HEAD_INIT(fh->list),
146                                       .fd       = fd,
147                                       .get_name = NULL,
148                                       .inode    = NULL,
149                                       .flags    = flags });
150 }
151
152 int open_filehandle(char *name, struct openflags flags, int mode, 
153                     struct file_handle *fh)
154 {
155         int fd;
156
157         fd = open_file(name, flags, mode);
158         if(fd < 0)
159                 return(fd);
160
161         init_fh(fh, fd, flags);
162         return(0);
163 }
164
165 int close_file(struct file_handle *fh)
166 {
167         spin_lock(&open_files_lock);
168         list_del(&fh->list);
169         spin_unlock(&open_files_lock);
170
171         os_close_file(fh->fd);
172
173         fh->fd = -1;
174         return(0);
175 }
176
177 int read_file(struct file_handle *fh, unsigned long long offset, char *buf,
178               int len)
179 {
180         int err;
181
182         err = active_handle(fh);
183         if(err)
184                 return(err);
185
186         err = os_seek_file(fh->fd, offset);
187         if(err)
188                 return(err);
189
190         return(os_read_file(fh->fd, buf, len));
191 }
192
193 int write_file(struct file_handle *fh, unsigned long long offset, 
194                const char *buf, int len)
195 {
196         int err;
197
198         err = active_handle(fh);
199         if(err)
200                 return(err);
201
202         if(offset != -1)
203                 err = os_seek_file(fh->fd, offset);
204         if(err)
205                 return(err);
206
207         return(os_write_file(fh->fd, buf, len));
208 }
209
210 int truncate_file(struct file_handle *fh, unsigned long long size)
211 {
212         int err;
213
214         err = active_handle(fh);
215         if(err)
216                 return(err);
217
218         return(os_truncate_fd(fh->fd, size));
219 }
220
221 int make_pipe(struct file_handle *fhs)
222 {
223         int fds[2], err;
224
225         err = os_pipe(fds, 1, 1);
226         if(err && (err != -EMFILE))
227                 return(err);
228
229         if(err){
230                 reclaim_fds();
231                 err = os_pipe(fds, 1, 1);
232         }
233         if(err)
234                 return(err);
235
236         init_fh(&fhs[0], fds[0], OPENFLAGS());
237         init_fh(&fhs[1], fds[1], OPENFLAGS());
238         return(0);
239 }
240
241 /*
242  * Overrides for Emacs so that we follow Linus's tabbing style.
243  * Emacs will notice this stuff at the end of the file and automatically
244  * adjust the settings for this buffer only.  This must remain at the end
245  * of the file.
246  * ---------------------------------------------------------------------------
247  * Local variables:
248  * c-file-style: "linux"
249  * End:
250  */