Commit a892e2d7dcdfa6c76e60c50a8c7385c65587a2a6

Authored by Changli Gao
Committed by Linus Torvalds
1 parent 06b1e104b7

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>

Showing 1 changed file with 23 additions and 34 deletions Side-by-side Diff

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