diff options
author | Changli Gao <xiaosuo@gmail.com> | 2010-08-10 21:01:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-11 11:59:02 -0400 |
commit | a892e2d7dcdfa6c76e60c50a8c7385c65587a2a6 (patch) | |
tree | af32ff520eaa8766039fc71e3f9759fe73e727ba /fs/file.c | |
parent | 06b1e104b7ea1bf5145643de5a3fce28b831ca4c (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.c | 57 |
1 files changed, 23 insertions, 34 deletions
@@ -39,28 +39,27 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */ | |||
39 | */ | 39 | */ |
40 | static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); | 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) | 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 | ||
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 *))) | 55 | is_vmalloc_addr(ptr) ? vfree(ptr) : kfree(ptr); |
53 | kfree(fdt->fd); | ||
54 | else | ||
55 | vfree(fdt->fd); | ||
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)) | 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 | ||
66 | static void free_fdtable_work(struct work_struct *work) | 65 | static 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 | ||
185 | out_arr: | 183 | out_arr: |
186 | free_fdarr(fdt); | 184 | free_fdmem(fdt->fd); |
187 | out_fdt: | 185 | out_fdt: |
188 | kfree(fdt); | 186 | kfree(fdt); |
189 | out: | 187 | out: |
@@ -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 | } |