aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c57
1 files changed, 23 insertions, 34 deletions
diff --git a/fs/file.c b/fs/file.c
index cccaead962c2..0be344755c02 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -39,28 +39,27 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */
39 */ 39 */
40static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); 40static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
41 41
42static inline void * alloc_fdmem(unsigned int size) 42static inline void *alloc_fdmem(unsigned int size)
43{ 43{
44 if (size <= PAGE_SIZE) 44 void *data;
45 return kmalloc(size, GFP_KERNEL); 45
46 else 46 data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN);
47 return vmalloc(size); 47 if (data != NULL)
48 return data;
49
50 return vmalloc(size);
48} 51}
49 52
50static inline void free_fdarr(struct fdtable *fdt) 53static void free_fdmem(void *ptr)
51{ 54{
52 if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) 55 is_vmalloc_addr(ptr) ? vfree(ptr) : kfree(ptr);
53 kfree(fdt->fd);
54 else
55 vfree(fdt->fd);
56} 56}
57 57
58static inline void free_fdset(struct fdtable *fdt) 58static void __free_fdtable(struct fdtable *fdt)
59{ 59{
60 if (fdt->max_fds <= (PAGE_SIZE * BITS_PER_BYTE / 2)) 60 free_fdmem(fdt->fd);
61 kfree(fdt->open_fds); 61 free_fdmem(fdt->open_fds);
62 else 62 kfree(fdt);
63 vfree(fdt->open_fds);
64} 63}
65 64
66static void free_fdtable_work(struct work_struct *work) 65static void free_fdtable_work(struct work_struct *work)
@@ -75,9 +74,8 @@ static void free_fdtable_work(struct work_struct *work)
75 spin_unlock_bh(&f->lock); 74 spin_unlock_bh(&f->lock);
76 while(fdt) { 75 while(fdt) {
77 struct fdtable *next = fdt->next; 76 struct fdtable *next = fdt->next;
78 vfree(fdt->fd); 77
79 free_fdset(fdt); 78 __free_fdtable(fdt);
80 kfree(fdt);
81 fdt = next; 79 fdt = next;
82 } 80 }
83} 81}
@@ -98,7 +96,7 @@ void free_fdtable_rcu(struct rcu_head *rcu)
98 container_of(fdt, struct files_struct, fdtab)); 96 container_of(fdt, struct files_struct, fdtab));
99 return; 97 return;
100 } 98 }
101 if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) { 99 if (!is_vmalloc_addr(fdt->fd) && !is_vmalloc_addr(fdt->open_fds)) {
102 kfree(fdt->fd); 100 kfree(fdt->fd);
103 kfree(fdt->open_fds); 101 kfree(fdt->open_fds);
104 kfree(fdt); 102 kfree(fdt);
@@ -183,7 +181,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
183 return fdt; 181 return fdt;
184 182
185out_arr: 183out_arr:
186 free_fdarr(fdt); 184 free_fdmem(fdt->fd);
187out_fdt: 185out_fdt:
188 kfree(fdt); 186 kfree(fdt);
189out: 187out:
@@ -213,9 +211,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
213 * caller and alloc_fdtable(). Cheaper to catch it here... 211 * caller and alloc_fdtable(). Cheaper to catch it here...
214 */ 212 */
215 if (unlikely(new_fdt->max_fds <= nr)) { 213 if (unlikely(new_fdt->max_fds <= nr)) {
216 free_fdarr(new_fdt); 214 __free_fdtable(new_fdt);
217 free_fdset(new_fdt);
218 kfree(new_fdt);
219 return -EMFILE; 215 return -EMFILE;
220 } 216 }
221 /* 217 /*
@@ -231,9 +227,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
231 free_fdtable(cur_fdt); 227 free_fdtable(cur_fdt);
232 } else { 228 } else {
233 /* Somebody else expanded, so undo our attempt */ 229 /* Somebody else expanded, so undo our attempt */
234 free_fdarr(new_fdt); 230 __free_fdtable(new_fdt);
235 free_fdset(new_fdt);
236 kfree(new_fdt);
237 } 231 }
238 return 1; 232 return 1;
239} 233}
@@ -323,11 +317,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
323 while (unlikely(open_files > new_fdt->max_fds)) { 317 while (unlikely(open_files > new_fdt->max_fds)) {
324 spin_unlock(&oldf->file_lock); 318 spin_unlock(&oldf->file_lock);
325 319
326 if (new_fdt != &newf->fdtab) { 320 if (new_fdt != &newf->fdtab)
327 free_fdarr(new_fdt); 321 __free_fdtable(new_fdt);
328 free_fdset(new_fdt);
329 kfree(new_fdt);
330 }
331 322
332 new_fdt = alloc_fdtable(open_files - 1); 323 new_fdt = alloc_fdtable(open_files - 1);
333 if (!new_fdt) { 324 if (!new_fdt) {
@@ -337,9 +328,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
337 328
338 /* beyond sysctl_nr_open; nothing to do */ 329 /* beyond sysctl_nr_open; nothing to do */
339 if (unlikely(new_fdt->max_fds < open_files)) { 330 if (unlikely(new_fdt->max_fds < open_files)) {
340 free_fdarr(new_fdt); 331 __free_fdtable(new_fdt);
341 free_fdset(new_fdt);
342 kfree(new_fdt);
343 *errorp = -EMFILE; 332 *errorp = -EMFILE;
344 goto out_release; 333 goto out_release;
345 } 334 }