diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 5b0fb9f09f21..3b25b182d2be 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -368,17 +368,25 @@ EXPORT_SYMBOL(daemonize); | |||
| 368 | static inline void close_files(struct files_struct * files) | 368 | static inline void close_files(struct files_struct * files) |
| 369 | { | 369 | { |
| 370 | int i, j; | 370 | int i, j; |
| 371 | struct fdtable *fdt; | ||
| 371 | 372 | ||
| 372 | j = 0; | 373 | j = 0; |
| 374 | |||
| 375 | /* | ||
| 376 | * It is safe to dereference the fd table without RCU or | ||
| 377 | * ->file_lock because this is the last reference to the | ||
| 378 | * files structure. | ||
| 379 | */ | ||
| 380 | fdt = files_fdtable(files); | ||
| 373 | for (;;) { | 381 | for (;;) { |
| 374 | unsigned long set; | 382 | unsigned long set; |
| 375 | i = j * __NFDBITS; | 383 | i = j * __NFDBITS; |
| 376 | if (i >= files->max_fdset || i >= files->max_fds) | 384 | if (i >= fdt->max_fdset || i >= fdt->max_fds) |
| 377 | break; | 385 | break; |
| 378 | set = files->open_fds->fds_bits[j++]; | 386 | set = fdt->open_fds->fds_bits[j++]; |
| 379 | while (set) { | 387 | while (set) { |
| 380 | if (set & 1) { | 388 | if (set & 1) { |
| 381 | struct file * file = xchg(&files->fd[i], NULL); | 389 | struct file * file = xchg(&fdt->fd[i], NULL); |
| 382 | if (file) | 390 | if (file) |
| 383 | filp_close(file, files); | 391 | filp_close(file, files); |
| 384 | } | 392 | } |
| @@ -403,18 +411,22 @@ struct files_struct *get_files_struct(struct task_struct *task) | |||
| 403 | 411 | ||
| 404 | void fastcall put_files_struct(struct files_struct *files) | 412 | void fastcall put_files_struct(struct files_struct *files) |
| 405 | { | 413 | { |
| 414 | struct fdtable *fdt; | ||
| 415 | |||
| 406 | if (atomic_dec_and_test(&files->count)) { | 416 | if (atomic_dec_and_test(&files->count)) { |
| 407 | close_files(files); | 417 | close_files(files); |
| 408 | /* | 418 | /* |
| 409 | * Free the fd and fdset arrays if we expanded them. | 419 | * Free the fd and fdset arrays if we expanded them. |
| 420 | * If the fdtable was embedded, pass files for freeing | ||
| 421 | * at the end of the RCU grace period. Otherwise, | ||
| 422 | * you can free files immediately. | ||
| 410 | */ | 423 | */ |
| 411 | if (files->fd != &files->fd_array[0]) | 424 | fdt = files_fdtable(files); |
| 412 | free_fd_array(files->fd, files->max_fds); | 425 | if (fdt == &files->fdtab) |
| 413 | if (files->max_fdset > __FD_SETSIZE) { | 426 | fdt->free_files = files; |
| 414 | free_fdset(files->open_fds, files->max_fdset); | 427 | else |
| 415 | free_fdset(files->close_on_exec, files->max_fdset); | 428 | kmem_cache_free(files_cachep, files); |
| 416 | } | 429 | free_fdtable(fdt); |
| 417 | kmem_cache_free(files_cachep, files); | ||
| 418 | } | 430 | } |
| 419 | } | 431 | } |
| 420 | 432 | ||
| @@ -831,6 +843,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 831 | group_dead = atomic_dec_and_test(&tsk->signal->live); | 843 | group_dead = atomic_dec_and_test(&tsk->signal->live); |
| 832 | if (group_dead) { | 844 | if (group_dead) { |
| 833 | del_timer_sync(&tsk->signal->real_timer); | 845 | del_timer_sync(&tsk->signal->real_timer); |
| 846 | exit_itimers(tsk->signal); | ||
| 834 | acct_process(code); | 847 | acct_process(code); |
| 835 | } | 848 | } |
| 836 | exit_mm(tsk); | 849 | exit_mm(tsk); |
| @@ -1191,7 +1204,7 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap, | |||
| 1191 | 1204 | ||
| 1192 | exit_code = p->exit_code; | 1205 | exit_code = p->exit_code; |
| 1193 | if (unlikely(!exit_code) || | 1206 | if (unlikely(!exit_code) || |
| 1194 | unlikely(p->state > TASK_STOPPED)) | 1207 | unlikely(p->state & TASK_TRACED)) |
| 1195 | goto bail_ref; | 1208 | goto bail_ref; |
| 1196 | return wait_noreap_copyout(p, pid, uid, | 1209 | return wait_noreap_copyout(p, pid, uid, |
| 1197 | why, (exit_code << 8) | 0x7f, | 1210 | why, (exit_code << 8) | 0x7f, |
