aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/file.c100
-rw-r--r--include/linux/fdtable.h6
-rw-r--r--kernel/exit.c93
3 files changed, 99 insertions, 100 deletions
diff --git a/fs/file.c b/fs/file.c
index a3a0705f8f51..0be423cadb26 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -84,7 +84,7 @@ static void free_fdtable_work(struct work_struct *work)
84 } 84 }
85} 85}
86 86
87void free_fdtable_rcu(struct rcu_head *rcu) 87static 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
119static 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
396static 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
431struct 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
444void 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
465void 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
477void 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
391static void __devinit fdtable_defer_list_init(int cpu) 489static 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;
94struct dentry; 94struct dentry;
95 95
96extern int expand_files(struct files_struct *, int nr); 96extern int expand_files(struct files_struct *, int nr);
97extern void free_fdtable_rcu(struct rcu_head *rcu);
98extern void __init files_defer_init(void); 97extern void __init files_defer_init(void);
99 98
100static inline void free_fdtable(struct fdtable *fdt)
101{
102 call_rcu(&fdt->rcu, free_fdtable_rcu);
103}
104
105static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) 99static 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
467EXPORT_SYMBOL(daemonize); 467EXPORT_SYMBOL(daemonize);
468 468
469static 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
504struct 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
517void 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
538void 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
550void 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.