diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 82 |
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) | |||
568 | static int count_open_files(struct files_struct *files, int size) | 568 | static 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 | ||
583 | static 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]; | ||
602 | out: | ||
603 | return newf; | ||
604 | } | ||
605 | |||
581 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | 606 | static 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 | ||
691 | out_release: | 709 | out_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 | } |