aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c82
1 files changed, 50 insertions, 32 deletions
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}