diff options
-rw-r--r-- | fs/file.c | 100 | ||||
-rw-r--r-- | include/linux/fdtable.h | 6 | ||||
-rw-r--r-- | kernel/exit.c | 93 |
3 files changed, 99 insertions, 100 deletions
@@ -84,7 +84,7 @@ static void free_fdtable_work(struct work_struct *work) | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | void free_fdtable_rcu(struct rcu_head *rcu) | 87 | static void free_fdtable_rcu(struct rcu_head *rcu) |
88 | { | 88 | { |
89 | struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); | 89 | struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); |
90 | struct fdtable_defer *fddef; | 90 | struct fdtable_defer *fddef; |
@@ -116,6 +116,11 @@ void free_fdtable_rcu(struct rcu_head *rcu) | |||
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
119 | static inline void free_fdtable(struct fdtable *fdt) | ||
120 | { | ||
121 | call_rcu(&fdt->rcu, free_fdtable_rcu); | ||
122 | } | ||
123 | |||
119 | /* | 124 | /* |
120 | * Expand the fdset in the files_struct. Called with the files spinlock | 125 | * Expand the fdset in the files_struct. Called with the files spinlock |
121 | * held for write. | 126 | * held for write. |
@@ -388,6 +393,99 @@ out: | |||
388 | return NULL; | 393 | return NULL; |
389 | } | 394 | } |
390 | 395 | ||
396 | static void close_files(struct files_struct * files) | ||
397 | { | ||
398 | int i, j; | ||
399 | struct fdtable *fdt; | ||
400 | |||
401 | j = 0; | ||
402 | |||
403 | /* | ||
404 | * It is safe to dereference the fd table without RCU or | ||
405 | * ->file_lock because this is the last reference to the | ||
406 | * files structure. But use RCU to shut RCU-lockdep up. | ||
407 | */ | ||
408 | rcu_read_lock(); | ||
409 | fdt = files_fdtable(files); | ||
410 | rcu_read_unlock(); | ||
411 | for (;;) { | ||
412 | unsigned long set; | ||
413 | i = j * BITS_PER_LONG; | ||
414 | if (i >= fdt->max_fds) | ||
415 | break; | ||
416 | set = fdt->open_fds[j++]; | ||
417 | while (set) { | ||
418 | if (set & 1) { | ||
419 | struct file * file = xchg(&fdt->fd[i], NULL); | ||
420 | if (file) { | ||
421 | filp_close(file, files); | ||
422 | cond_resched(); | ||
423 | } | ||
424 | } | ||
425 | i++; | ||
426 | set >>= 1; | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | |||
431 | struct files_struct *get_files_struct(struct task_struct *task) | ||
432 | { | ||
433 | struct files_struct *files; | ||
434 | |||
435 | task_lock(task); | ||
436 | files = task->files; | ||
437 | if (files) | ||
438 | atomic_inc(&files->count); | ||
439 | task_unlock(task); | ||
440 | |||
441 | return files; | ||
442 | } | ||
443 | |||
444 | void put_files_struct(struct files_struct *files) | ||
445 | { | ||
446 | struct fdtable *fdt; | ||
447 | |||
448 | if (atomic_dec_and_test(&files->count)) { | ||
449 | close_files(files); | ||
450 | /* | ||
451 | * Free the fd and fdset arrays if we expanded them. | ||
452 | * If the fdtable was embedded, pass files for freeing | ||
453 | * at the end of the RCU grace period. Otherwise, | ||
454 | * you can free files immediately. | ||
455 | */ | ||
456 | rcu_read_lock(); | ||
457 | fdt = files_fdtable(files); | ||
458 | if (fdt != &files->fdtab) | ||
459 | kmem_cache_free(files_cachep, files); | ||
460 | free_fdtable(fdt); | ||
461 | rcu_read_unlock(); | ||
462 | } | ||
463 | } | ||
464 | |||
465 | void reset_files_struct(struct files_struct *files) | ||
466 | { | ||
467 | struct task_struct *tsk = current; | ||
468 | struct files_struct *old; | ||
469 | |||
470 | old = tsk->files; | ||
471 | task_lock(tsk); | ||
472 | tsk->files = files; | ||
473 | task_unlock(tsk); | ||
474 | put_files_struct(old); | ||
475 | } | ||
476 | |||
477 | void exit_files(struct task_struct *tsk) | ||
478 | { | ||
479 | struct files_struct * files = tsk->files; | ||
480 | |||
481 | if (files) { | ||
482 | task_lock(tsk); | ||
483 | tsk->files = NULL; | ||
484 | task_unlock(tsk); | ||
485 | put_files_struct(files); | ||
486 | } | ||
487 | } | ||
488 | |||
391 | static void __devinit fdtable_defer_list_init(int cpu) | 489 | static void __devinit fdtable_defer_list_init(int cpu) |
392 | { | 490 | { |
393 | struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); | 491 | struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); |
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index b84ca064f727..3855f4febe70 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h | |||
@@ -94,14 +94,8 @@ struct vfsmount; | |||
94 | struct dentry; | 94 | struct dentry; |
95 | 95 | ||
96 | extern int expand_files(struct files_struct *, int nr); | 96 | extern int expand_files(struct files_struct *, int nr); |
97 | extern void free_fdtable_rcu(struct rcu_head *rcu); | ||
98 | extern void __init files_defer_init(void); | 97 | extern void __init files_defer_init(void); |
99 | 98 | ||
100 | static inline void free_fdtable(struct fdtable *fdt) | ||
101 | { | ||
102 | call_rcu(&fdt->rcu, free_fdtable_rcu); | ||
103 | } | ||
104 | |||
105 | static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) | 99 | static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) |
106 | { | 100 | { |
107 | struct file * file = NULL; | 101 | struct file * file = NULL; |
diff --git a/kernel/exit.c b/kernel/exit.c index f65345f9e5bb..20dfc7617c2e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -466,99 +466,6 @@ void daemonize(const char *name, ...) | |||
466 | 466 | ||
467 | EXPORT_SYMBOL(daemonize); | 467 | EXPORT_SYMBOL(daemonize); |
468 | 468 | ||
469 | static void close_files(struct files_struct * files) | ||
470 | { | ||
471 | int i, j; | ||
472 | struct fdtable *fdt; | ||
473 | |||
474 | j = 0; | ||
475 | |||
476 | /* | ||
477 | * It is safe to dereference the fd table without RCU or | ||
478 | * ->file_lock because this is the last reference to the | ||
479 | * files structure. But use RCU to shut RCU-lockdep up. | ||
480 | */ | ||
481 | rcu_read_lock(); | ||
482 | fdt = files_fdtable(files); | ||
483 | rcu_read_unlock(); | ||
484 | for (;;) { | ||
485 | unsigned long set; | ||
486 | i = j * BITS_PER_LONG; | ||
487 | if (i >= fdt->max_fds) | ||
488 | break; | ||
489 | set = fdt->open_fds[j++]; | ||
490 | while (set) { | ||
491 | if (set & 1) { | ||
492 | struct file * file = xchg(&fdt->fd[i], NULL); | ||
493 | if (file) { | ||
494 | filp_close(file, files); | ||
495 | cond_resched(); | ||
496 | } | ||
497 | } | ||
498 | i++; | ||
499 | set >>= 1; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | |||
504 | struct files_struct *get_files_struct(struct task_struct *task) | ||
505 | { | ||
506 | struct files_struct *files; | ||
507 | |||
508 | task_lock(task); | ||
509 | files = task->files; | ||
510 | if (files) | ||
511 | atomic_inc(&files->count); | ||
512 | task_unlock(task); | ||
513 | |||
514 | return files; | ||
515 | } | ||
516 | |||
517 | void put_files_struct(struct files_struct *files) | ||
518 | { | ||
519 | struct fdtable *fdt; | ||
520 | |||
521 | if (atomic_dec_and_test(&files->count)) { | ||
522 | close_files(files); | ||
523 | /* | ||
524 | * Free the fd and fdset arrays if we expanded them. | ||
525 | * If the fdtable was embedded, pass files for freeing | ||
526 | * at the end of the RCU grace period. Otherwise, | ||
527 | * you can free files immediately. | ||
528 | */ | ||
529 | rcu_read_lock(); | ||
530 | fdt = files_fdtable(files); | ||
531 | if (fdt != &files->fdtab) | ||
532 | kmem_cache_free(files_cachep, files); | ||
533 | free_fdtable(fdt); | ||
534 | rcu_read_unlock(); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | void reset_files_struct(struct files_struct *files) | ||
539 | { | ||
540 | struct task_struct *tsk = current; | ||
541 | struct files_struct *old; | ||
542 | |||
543 | old = tsk->files; | ||
544 | task_lock(tsk); | ||
545 | tsk->files = files; | ||
546 | task_unlock(tsk); | ||
547 | put_files_struct(old); | ||
548 | } | ||
549 | |||
550 | void exit_files(struct task_struct *tsk) | ||
551 | { | ||
552 | struct files_struct * files = tsk->files; | ||
553 | |||
554 | if (files) { | ||
555 | task_lock(tsk); | ||
556 | tsk->files = NULL; | ||
557 | task_unlock(tsk); | ||
558 | put_files_struct(files); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | #ifdef CONFIG_MM_OWNER | 469 | #ifdef CONFIG_MM_OWNER |
563 | /* | 470 | /* |
564 | * A task is exiting. If it owned this mm, find a new owner for the mm. | 471 | * A task is exiting. If it owned this mm, find a new owner for the mm. |