diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-06-25 06:32:01 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-06-25 06:32:01 -0400 |
| commit | da7878d75b8520c9ae00d27dfbbce546a7bfdfbb (patch) | |
| tree | 547fd497a80818a60ac36831377d5df97868173c /kernel/fork.c | |
| parent | 0e50a4c6ab94ffe7e5515b86b5df9e5abc8c6b13 (diff) | |
| parent | 543cf4cb3fe6f6cae3651ba918b9c56200b257d0 (diff) | |
Merge branch 'linus' into x86/pebs
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 130 |
1 files changed, 0 insertions, 130 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 933e60ebccae..19908b26cf80 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -660,136 +660,6 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) | |||
| 660 | return 0; | 660 | return 0; |
| 661 | } | 661 | } |
| 662 | 662 | ||
| 663 | static int count_open_files(struct fdtable *fdt) | ||
| 664 | { | ||
| 665 | int size = fdt->max_fds; | ||
| 666 | int i; | ||
| 667 | |||
| 668 | /* Find the last open fd */ | ||
| 669 | for (i = size/(8*sizeof(long)); i > 0; ) { | ||
| 670 | if (fdt->open_fds->fds_bits[--i]) | ||
| 671 | break; | ||
| 672 | } | ||
| 673 | i = (i+1) * 8 * sizeof(long); | ||
| 674 | return i; | ||
| 675 | } | ||
| 676 | |||
| 677 | static struct files_struct *alloc_files(void) | ||
| 678 | { | ||
| 679 | struct files_struct *newf; | ||
| 680 | struct fdtable *fdt; | ||
| 681 | |||
| 682 | newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); | ||
| 683 | if (!newf) | ||
| 684 | goto out; | ||
| 685 | |||
| 686 | atomic_set(&newf->count, 1); | ||
| 687 | |||
| 688 | spin_lock_init(&newf->file_lock); | ||
| 689 | newf->next_fd = 0; | ||
| 690 | fdt = &newf->fdtab; | ||
| 691 | fdt->max_fds = NR_OPEN_DEFAULT; | ||
| 692 | fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; | ||
| 693 | fdt->open_fds = (fd_set *)&newf->open_fds_init; | ||
| 694 | fdt->fd = &newf->fd_array[0]; | ||
| 695 | INIT_RCU_HEAD(&fdt->rcu); | ||
| 696 | fdt->next = NULL; | ||
| 697 | rcu_assign_pointer(newf->fdt, fdt); | ||
| 698 | out: | ||
| 699 | return newf; | ||
| 700 | } | ||
| 701 | |||
| 702 | /* | ||
| 703 | * Allocate a new files structure and copy contents from the | ||
| 704 | * passed in files structure. | ||
| 705 | * errorp will be valid only when the returned files_struct is NULL. | ||
| 706 | */ | ||
| 707 | static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | ||
| 708 | { | ||
| 709 | struct files_struct *newf; | ||
| 710 | struct file **old_fds, **new_fds; | ||
| 711 | int open_files, size, i; | ||
| 712 | struct fdtable *old_fdt, *new_fdt; | ||
| 713 | |||
| 714 | *errorp = -ENOMEM; | ||
| 715 | newf = alloc_files(); | ||
| 716 | if (!newf) | ||
| 717 | goto out; | ||
| 718 | |||
| 719 | spin_lock(&oldf->file_lock); | ||
| 720 | old_fdt = files_fdtable(oldf); | ||
| 721 | new_fdt = files_fdtable(newf); | ||
| 722 | open_files = count_open_files(old_fdt); | ||
| 723 | |||
| 724 | /* | ||
| 725 | * Check whether we need to allocate a larger fd array and fd set. | ||
| 726 | * Note: we're not a clone task, so the open count won't change. | ||
| 727 | */ | ||
| 728 | if (open_files > new_fdt->max_fds) { | ||
| 729 | new_fdt->max_fds = 0; | ||
| 730 | spin_unlock(&oldf->file_lock); | ||
| 731 | spin_lock(&newf->file_lock); | ||
| 732 | *errorp = expand_files(newf, open_files-1); | ||
| 733 | spin_unlock(&newf->file_lock); | ||
| 734 | if (*errorp < 0) | ||
| 735 | goto out_release; | ||
| 736 | new_fdt = files_fdtable(newf); | ||
| 737 | /* | ||
| 738 | * Reacquire the oldf lock and a pointer to its fd table | ||
| 739 | * who knows it may have a new bigger fd table. We need | ||
| 740 | * the latest pointer. | ||
| 741 | */ | ||
| 742 | spin_lock(&oldf->file_lock); | ||
| 743 | old_fdt = files_fdtable(oldf); | ||
| 744 | } | ||
| 745 | |||
| 746 | old_fds = old_fdt->fd; | ||
| 747 | new_fds = new_fdt->fd; | ||
| 748 | |||
| 749 | memcpy(new_fdt->open_fds->fds_bits, | ||
| 750 | old_fdt->open_fds->fds_bits, open_files/8); | ||
| 751 | memcpy(new_fdt->close_on_exec->fds_bits, | ||
| 752 | old_fdt->close_on_exec->fds_bits, open_files/8); | ||
| 753 | |||
| 754 | for (i = open_files; i != 0; i--) { | ||
| 755 | struct file *f = *old_fds++; | ||
| 756 | if (f) { | ||
| 757 | get_file(f); | ||
| 758 | } else { | ||
| 759 | /* | ||
| 760 | * The fd may be claimed in the fd bitmap but not yet | ||
| 761 | * instantiated in the files array if a sibling thread | ||
| 762 | * is partway through open(). So make sure that this | ||
| 763 | * fd is available to the new process. | ||
| 764 | */ | ||
| 765 | FD_CLR(open_files - i, new_fdt->open_fds); | ||
| 766 | } | ||
| 767 | rcu_assign_pointer(*new_fds++, f); | ||
| 768 | } | ||
| 769 | spin_unlock(&oldf->file_lock); | ||
| 770 | |||
| 771 | /* compute the remainder to be cleared */ | ||
| 772 | size = (new_fdt->max_fds - open_files) * sizeof(struct file *); | ||
| 773 | |||
| 774 | /* This is long word aligned thus could use a optimized version */ | ||
| 775 | memset(new_fds, 0, size); | ||
| 776 | |||
| 777 | if (new_fdt->max_fds > open_files) { | ||
| 778 | int left = (new_fdt->max_fds-open_files)/8; | ||
| 779 | int start = open_files / (8 * sizeof(unsigned long)); | ||
| 780 | |||
| 781 | memset(&new_fdt->open_fds->fds_bits[start], 0, left); | ||
| 782 | memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); | ||
| 783 | } | ||
| 784 | |||
| 785 | return newf; | ||
| 786 | |||
| 787 | out_release: | ||
| 788 | kmem_cache_free(files_cachep, newf); | ||
| 789 | out: | ||
| 790 | return NULL; | ||
| 791 | } | ||
| 792 | |||
| 793 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | 663 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) |
| 794 | { | 664 | { |
| 795 | struct files_struct *oldf, *newf; | 665 | struct files_struct *oldf, *newf; |
