aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDipankar Sarma <dipankar@in.ibm.com>2005-09-09 16:04:10 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:57:55 -0400
commitbadf16621c1f9d1ac753be056fce11b43d6e0be5 (patch)
tree3fdf833fdf2e3d3a439090743539680449ec3428 /kernel
parentc0dfb2905126e9e94edebbce8d3e05001301f52d (diff)
[PATCH] files: break up files struct
In order for the RCU to work, the file table array, sets and their sizes must be updated atomically. Instead of ensuring this through too many memory barriers, we put the arrays and their sizes in a separate structure. This patch takes the first step of putting the file table elements in a separate structure fdtable that is embedded withing files_struct. It also changes all the users to refer to the file table using files_fdtable() macro. Subsequent applciation of RCU becomes easier after this. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c21
-rw-r--r--kernel/fork.c82
2 files changed, 63 insertions, 40 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 5b0fb9f09f21..83beb1e93b18 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -368,17 +368,19 @@ EXPORT_SYMBOL(daemonize);
368static inline void close_files(struct files_struct * files) 368static 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 fdt = files_fdtable(files);
373 for (;;) { 375 for (;;) {
374 unsigned long set; 376 unsigned long set;
375 i = j * __NFDBITS; 377 i = j * __NFDBITS;
376 if (i >= files->max_fdset || i >= files->max_fds) 378 if (i >= fdt->max_fdset || i >= fdt->max_fds)
377 break; 379 break;
378 set = files->open_fds->fds_bits[j++]; 380 set = fdt->open_fds->fds_bits[j++];
379 while (set) { 381 while (set) {
380 if (set & 1) { 382 if (set & 1) {
381 struct file * file = xchg(&files->fd[i], NULL); 383 struct file * file = xchg(&fdt->fd[i], NULL);
382 if (file) 384 if (file)
383 filp_close(file, files); 385 filp_close(file, files);
384 } 386 }
@@ -403,16 +405,19 @@ struct files_struct *get_files_struct(struct task_struct *task)
403 405
404void fastcall put_files_struct(struct files_struct *files) 406void fastcall put_files_struct(struct files_struct *files)
405{ 407{
408 struct fdtable *fdt;
409
406 if (atomic_dec_and_test(&files->count)) { 410 if (atomic_dec_and_test(&files->count)) {
407 close_files(files); 411 close_files(files);
408 /* 412 /*
409 * Free the fd and fdset arrays if we expanded them. 413 * Free the fd and fdset arrays if we expanded them.
410 */ 414 */
411 if (files->fd != &files->fd_array[0]) 415 fdt = files_fdtable(files);
412 free_fd_array(files->fd, files->max_fds); 416 if (fdt->fd != &files->fd_array[0])
413 if (files->max_fdset > __FD_SETSIZE) { 417 free_fd_array(fdt->fd, fdt->max_fds);
414 free_fdset(files->open_fds, files->max_fdset); 418 if (fdt->max_fdset > __FD_SETSIZE) {
415 free_fdset(files->close_on_exec, files->max_fdset); 419 free_fdset(fdt->open_fds, fdt->max_fdset);
420 free_fdset(fdt->close_on_exec, fdt->max_fdset);
416 } 421 }
417 kmem_cache_free(files_cachep, files); 422 kmem_cache_free(files_cachep, files);
418 } 423 }
diff --git a/kernel/fork.c b/kernel/fork.c
index b25802065031..ecc694debb50 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -568,21 +568,47 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
568static int count_open_files(struct files_struct *files, int size) 568static int count_open_files(struct files_struct *files, int size)
569{ 569{
570 int i; 570 int i;
571 struct fdtable *fdt;
571 572
572 /* Find the last open fd */ 573 /* Find the last open fd */
574 fdt = files_fdtable(files);
573 for (i = size/(8*sizeof(long)); i > 0; ) { 575 for (i = size/(8*sizeof(long)); i > 0; ) {
574 if (files->open_fds->fds_bits[--i]) 576 if (fdt->open_fds->fds_bits[--i])
575 break; 577 break;
576 } 578 }
577 i = (i+1) * 8 * sizeof(long); 579 i = (i+1) * 8 * sizeof(long);
578 return i; 580 return i;
579} 581}
580 582
583static struct files_struct *alloc_files(void)
584{
585 struct files_struct *newf;
586 struct fdtable *fdt;
587
588 newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
589 if (!newf)
590 goto out;
591
592 atomic_set(&newf->count, 1);
593
594 spin_lock_init(&newf->file_lock);
595 fdt = files_fdtable(newf);
596 fdt->next_fd = 0;
597 fdt->max_fds = NR_OPEN_DEFAULT;
598 fdt->max_fdset = __FD_SETSIZE;
599 fdt->close_on_exec = &newf->close_on_exec_init;
600 fdt->open_fds = &newf->open_fds_init;
601 fdt->fd = &newf->fd_array[0];
602out:
603 return newf;
604}
605
581static int copy_files(unsigned long clone_flags, struct task_struct * tsk) 606static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
582{ 607{
583 struct files_struct *oldf, *newf; 608 struct files_struct *oldf, *newf;
584 struct file **old_fds, **new_fds; 609 struct file **old_fds, **new_fds;
585 int open_files, size, i, error = 0, expand; 610 int open_files, size, i, error = 0, expand;
611 struct fdtable *old_fdt, *new_fdt;
586 612
587 /* 613 /*
588 * A background process may not have any files ... 614 * A background process may not have any files ...
@@ -603,35 +629,27 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
603 */ 629 */
604 tsk->files = NULL; 630 tsk->files = NULL;
605 error = -ENOMEM; 631 error = -ENOMEM;
606 newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); 632 newf = alloc_files();
607 if (!newf) 633 if (!newf)
608 goto out; 634 goto out;
609 635
610 atomic_set(&newf->count, 1);
611
612 spin_lock_init(&newf->file_lock);
613 newf->next_fd = 0;
614 newf->max_fds = NR_OPEN_DEFAULT;
615 newf->max_fdset = __FD_SETSIZE;
616 newf->close_on_exec = &newf->close_on_exec_init;
617 newf->open_fds = &newf->open_fds_init;
618 newf->fd = &newf->fd_array[0];
619
620 spin_lock(&oldf->file_lock); 636 spin_lock(&oldf->file_lock);
621 637 old_fdt = files_fdtable(oldf);
622 open_files = count_open_files(oldf, oldf->max_fdset); 638 new_fdt = files_fdtable(newf);
639 size = old_fdt->max_fdset;
640 open_files = count_open_files(oldf, old_fdt->max_fdset);
623 expand = 0; 641 expand = 0;
624 642
625 /* 643 /*
626 * Check whether we need to allocate a larger fd array or fd set. 644 * Check whether we need to allocate a larger fd array or fd set.
627 * Note: we're not a clone task, so the open count won't change. 645 * Note: we're not a clone task, so the open count won't change.
628 */ 646 */
629 if (open_files > newf->max_fdset) { 647 if (open_files > new_fdt->max_fdset) {
630 newf->max_fdset = 0; 648 new_fdt->max_fdset = 0;
631 expand = 1; 649 expand = 1;
632 } 650 }
633 if (open_files > newf->max_fds) { 651 if (open_files > new_fdt->max_fds) {
634 newf->max_fds = 0; 652 new_fdt->max_fds = 0;
635 expand = 1; 653 expand = 1;
636 } 654 }
637 655
@@ -646,11 +664,11 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
646 spin_lock(&oldf->file_lock); 664 spin_lock(&oldf->file_lock);
647 } 665 }
648 666
649 old_fds = oldf->fd; 667 old_fds = old_fdt->fd;
650 new_fds = newf->fd; 668 new_fds = new_fdt->fd;
651 669
652 memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); 670 memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8);
653 memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); 671 memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8);
654 672
655 for (i = open_files; i != 0; i--) { 673 for (i = open_files; i != 0; i--) {
656 struct file *f = *old_fds++; 674 struct file *f = *old_fds++;
@@ -663,24 +681,24 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
663 * is partway through open(). So make sure that this 681 * is partway through open(). So make sure that this
664 * fd is available to the new process. 682 * fd is available to the new process.
665 */ 683 */
666 FD_CLR(open_files - i, newf->open_fds); 684 FD_CLR(open_files - i, new_fdt->open_fds);
667 } 685 }
668 *new_fds++ = f; 686 *new_fds++ = f;
669 } 687 }
670 spin_unlock(&oldf->file_lock); 688 spin_unlock(&oldf->file_lock);
671 689
672 /* compute the remainder to be cleared */ 690 /* compute the remainder to be cleared */
673 size = (newf->max_fds - open_files) * sizeof(struct file *); 691 size = (new_fdt->max_fds - open_files) * sizeof(struct file *);
674 692
675 /* This is long word aligned thus could use a optimized version */ 693 /* This is long word aligned thus could use a optimized version */
676 memset(new_fds, 0, size); 694 memset(new_fds, 0, size);
677 695
678 if (newf->max_fdset > open_files) { 696 if (new_fdt->max_fdset > open_files) {
679 int left = (newf->max_fdset-open_files)/8; 697 int left = (new_fdt->max_fdset-open_files)/8;
680 int start = open_files / (8 * sizeof(unsigned long)); 698 int start = open_files / (8 * sizeof(unsigned long));
681 699
682 memset(&newf->open_fds->fds_bits[start], 0, left); 700 memset(&new_fdt->open_fds->fds_bits[start], 0, left);
683 memset(&newf->close_on_exec->fds_bits[start], 0, left); 701 memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
684 } 702 }
685 703
686 tsk->files = newf; 704 tsk->files = newf;
@@ -689,9 +707,9 @@ out:
689 return error; 707 return error;
690 708
691out_release: 709out_release:
692 free_fdset (newf->close_on_exec, newf->max_fdset); 710 free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset);
693 free_fdset (newf->open_fds, newf->max_fdset); 711 free_fdset (new_fdt->open_fds, new_fdt->max_fdset);
694 free_fd_array(newf->fd, newf->max_fds); 712 free_fd_array(new_fdt->fd, new_fdt->max_fds);
695 kmem_cache_free(files_cachep, newf); 713 kmem_cache_free(files_cachep, newf);
696 goto out; 714 goto out;
697} 715}