diff options
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 | } |
