1
2
3
4
5
6
7
8
9#include <linux/fs.h>
10#include <linux/mm.h>
11#include <linux/sched.h>
12#include <linux/malloc.h>
13#include <linux/vmalloc.h>
14
15#include <asm/bitops.h>
16
17
18
19
20
21
22struct file ** alloc_fd_array(int num)
23{
24 struct file **new_fds;
25 int size = num * sizeof(struct file *);
26
27 if (size < PAGE_SIZE)
28 new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
29 else if (size == PAGE_SIZE)
30 new_fds = (struct file **) __get_free_page(GFP_KERNEL);
31 else
32 new_fds = (struct file **) vmalloc(size);
33 return new_fds;
34}
35
36void free_fd_array(struct file **array, int num)
37{
38 int size = num * sizeof(struct file *);
39
40 if (!array) {
41 printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
42 return;
43 }
44
45 if (num <= NR_OPEN_DEFAULT)
46 return;
47 else if (size < PAGE_SIZE)
48 kfree(array);
49 else if (size == PAGE_SIZE)
50 free_page((unsigned long) array);
51 else
52 vfree(array);
53}
54
55
56
57
58
59int expand_fd_array(struct files_struct *files, int nr)
60{
61 struct file **new_fds;
62 int error, nfds;
63
64
65 error = -EMFILE;
66 if (files->max_fds >= NR_OPEN || nr > NR_OPEN)
67 goto out;
68
69 nfds = files->max_fds;
70
71
72
73
74
75
76 do {
77#if NR_OPEN_DEFAULT < 256
78 if (nfds < 256)
79 nfds = 256;
80 else
81#endif
82 if (nfds < (PAGE_SIZE / sizeof(struct file *)))
83 nfds = PAGE_SIZE / sizeof(struct file *);
84 else {
85 nfds = nfds * 2;
86 if (nfds > NR_OPEN)
87 nfds = NR_OPEN;
88 }
89 } while (nfds < nr);
90
91 error = -ENOMEM;
92 new_fds = alloc_fd_array(nfds);
93 if (!new_fds)
94 goto out;
95
96
97
98 if (nfds > files->max_fds) {
99 struct file **old_fds;
100 int i = files->max_fds;
101
102 old_fds = files->fd;
103 files->fd = new_fds;
104 files->max_fds = nfds;
105
106
107 if (i) {
108 memcpy(new_fds, old_fds, i * sizeof(struct file *));
109
110 memset(&new_fds[i], 0,
111 (nfds-i) * sizeof(struct file *));
112 free_fd_array(old_fds, i);
113 }
114 } else {
115
116 free_fd_array(new_fds, nfds);
117 }
118 error = 0;
119out:
120 return error;
121}
122
123
124
125
126
127fd_set * alloc_fdset(int num)
128{
129 fd_set *new_fdset;
130 int size = num / 8;
131
132 if (size < PAGE_SIZE)
133 new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
134 else if (size == PAGE_SIZE)
135 new_fdset = (fd_set *) __get_free_page(GFP_KERNEL);
136 else
137 new_fdset = (fd_set *) vmalloc(size);
138 return new_fdset;
139}
140
141void free_fdset(fd_set *array, int num)
142{
143 int size = num / 8;
144
145 if (!array) {
146 printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
147 return;
148 }
149
150 if (num <= __FD_SETSIZE)
151 return;
152 else if (size < PAGE_SIZE)
153 kfree(array);
154 else if (size == PAGE_SIZE)
155 free_page((unsigned long) array);
156 else
157 vfree(array);
158}
159
160
161
162
163int expand_fdset(struct files_struct *files, int nr)
164{
165 fd_set *new_openset = 0, *new_execset = 0;
166 int error, nfds = 0;
167
168 error = -EMFILE;
169 if (files->max_fdset >= NR_OPEN || nr > NR_OPEN)
170 goto out;
171
172 nfds = files->max_fdset;
173
174 do {
175 if (nfds < (PAGE_SIZE * 8))
176 nfds = PAGE_SIZE * 8;
177 else {
178 nfds = nfds * 2;
179 if (nfds > NR_OPEN)
180 nfds = NR_OPEN;
181 }
182 } while (nfds < nr);
183
184 error = -ENOMEM;
185 new_openset = alloc_fdset(nfds);
186 new_execset = alloc_fdset(nfds);
187 if (!new_openset || !new_execset)
188 goto out;
189
190 error = 0;
191
192
193 if (nfds > files->max_fdset) {
194 int i = files->max_fdset / (sizeof(unsigned long) * 8);
195 int count = (nfds - files->max_fdset) / 8;
196
197
198
199
200
201 if (i) {
202 memcpy (new_openset, files->open_fds, files->max_fdset/8);
203 memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
204 memset (&new_openset->fds_bits[i], 0, count);
205 memset (&new_execset->fds_bits[i], 0, count);
206 }
207
208 free_fdset (files->close_on_exec, files->max_fdset);
209 free_fdset (files->open_fds, files->max_fdset);
210 files->max_fdset = nfds;
211 files->open_fds = new_openset;
212 files->close_on_exec = new_execset;
213 return 0;
214 }
215
216
217out:
218 if (new_openset)
219 free_fdset(new_openset, nfds);
220 if (new_execset)
221 free_fdset(new_execset, nfds);
222 return error;
223}
224
225