aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
authorChangli Gao <xiaosuo@gmail.com>2010-08-10 21:01:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:02 -0400
commita892e2d7dcdfa6c76e60c50a8c7385c65587a2a6 (patch)
treeaf32ff520eaa8766039fc71e3f9759fe73e727ba /fs/file.c
parent06b1e104b7ea1bf5145643de5a3fce28b831ca4c (diff)
vfs: use kmalloc() to allocate fdmem if possible
Use kmalloc() to allocate fdmem if possible. vmalloc() is used as a fallback solution for fdmem allocation. A new helper function __free_fdtable() is introduced to reduce the lines of code. A potential bug, vfree() a memory allocated by kmalloc(), is fixed. [akpm@linux-foundation.org: use __GFP_NOWARN, uninline alloc_fdmem() and free_fdmem()] Signed-off-by: Changli Gao <xiaosuo@gmail.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Jiri Slaby <jslaby@suse.cz> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Avi Kivity <avi@redhat.com> Cc: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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 }