Commit a892e2d7dcdfa6c76e60c50a8c7385c65587a2a6
Committed by
Linus Torvalds
1 parent
06b1e104b7
Exists in
master
and in
39 other branches
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
fs/file.c
... | ... | @@ -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 | } |