diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fork.c | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index d1aceaea3f33..8e88b374cee9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -620,32 +620,17 @@ out: | |||
620 | return newf; | 620 | return newf; |
621 | } | 621 | } |
622 | 622 | ||
623 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | 623 | /* |
624 | * Allocate a new files structure and copy contents from the | ||
625 | * passed in files structure. | ||
626 | */ | ||
627 | static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | ||
624 | { | 628 | { |
625 | struct files_struct *oldf, *newf; | 629 | struct files_struct *newf; |
626 | struct file **old_fds, **new_fds; | 630 | struct file **old_fds, **new_fds; |
627 | int open_files, size, i, error = 0, expand; | 631 | int open_files, size, i, expand; |
628 | struct fdtable *old_fdt, *new_fdt; | 632 | struct fdtable *old_fdt, *new_fdt; |
629 | 633 | ||
630 | /* | ||
631 | * A background process may not have any files ... | ||
632 | */ | ||
633 | oldf = current->files; | ||
634 | if (!oldf) | ||
635 | goto out; | ||
636 | |||
637 | if (clone_flags & CLONE_FILES) { | ||
638 | atomic_inc(&oldf->count); | ||
639 | goto out; | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * Note: we may be using current for both targets (See exec.c) | ||
644 | * This works because we cache current->files (old) as oldf. Don't | ||
645 | * break this. | ||
646 | */ | ||
647 | tsk->files = NULL; | ||
648 | error = -ENOMEM; | ||
649 | newf = alloc_files(); | 634 | newf = alloc_files(); |
650 | if (!newf) | 635 | if (!newf) |
651 | goto out; | 636 | goto out; |
@@ -674,9 +659,9 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
674 | if (expand) { | 659 | if (expand) { |
675 | spin_unlock(&oldf->file_lock); | 660 | spin_unlock(&oldf->file_lock); |
676 | spin_lock(&newf->file_lock); | 661 | spin_lock(&newf->file_lock); |
677 | error = expand_files(newf, open_files-1); | 662 | *errorp = expand_files(newf, open_files-1); |
678 | spin_unlock(&newf->file_lock); | 663 | spin_unlock(&newf->file_lock); |
679 | if (error < 0) | 664 | if (*errorp < 0) |
680 | goto out_release; | 665 | goto out_release; |
681 | new_fdt = files_fdtable(newf); | 666 | new_fdt = files_fdtable(newf); |
682 | /* | 667 | /* |
@@ -725,10 +710,8 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
725 | memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); | 710 | memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); |
726 | } | 711 | } |
727 | 712 | ||
728 | tsk->files = newf; | ||
729 | error = 0; | ||
730 | out: | 713 | out: |
731 | return error; | 714 | return newf; |
732 | 715 | ||
733 | out_release: | 716 | out_release: |
734 | free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset); | 717 | free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset); |
@@ -738,6 +721,40 @@ out_release: | |||
738 | goto out; | 721 | goto out; |
739 | } | 722 | } |
740 | 723 | ||
724 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | ||
725 | { | ||
726 | struct files_struct *oldf, *newf; | ||
727 | int error = 0; | ||
728 | |||
729 | /* | ||
730 | * A background process may not have any files ... | ||
731 | */ | ||
732 | oldf = current->files; | ||
733 | if (!oldf) | ||
734 | goto out; | ||
735 | |||
736 | if (clone_flags & CLONE_FILES) { | ||
737 | atomic_inc(&oldf->count); | ||
738 | goto out; | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * Note: we may be using current for both targets (See exec.c) | ||
743 | * This works because we cache current->files (old) as oldf. Don't | ||
744 | * break this. | ||
745 | */ | ||
746 | tsk->files = NULL; | ||
747 | error = -ENOMEM; | ||
748 | newf = dup_fd(oldf, &error); | ||
749 | if (!newf) | ||
750 | goto out; | ||
751 | |||
752 | tsk->files = newf; | ||
753 | error = 0; | ||
754 | out: | ||
755 | return error; | ||
756 | } | ||
757 | |||
741 | /* | 758 | /* |
742 | * Helper to unshare the files of the current task. | 759 | * Helper to unshare the files of the current task. |
743 | * We don't want to expose copy_files internals to | 760 | * We don't want to expose copy_files internals to |
@@ -1463,15 +1480,19 @@ static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp) | |||
1463 | } | 1480 | } |
1464 | 1481 | ||
1465 | /* | 1482 | /* |
1466 | * Unsharing of files for tasks created with CLONE_FILES is not supported yet | 1483 | * Unshare file descriptor table if it is being shared |
1467 | */ | 1484 | */ |
1468 | static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) | 1485 | static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) |
1469 | { | 1486 | { |
1470 | struct files_struct *fd = current->files; | 1487 | struct files_struct *fd = current->files; |
1488 | int error = 0; | ||
1471 | 1489 | ||
1472 | if ((unshare_flags & CLONE_FILES) && | 1490 | if ((unshare_flags & CLONE_FILES) && |
1473 | (fd && atomic_read(&fd->count) > 1)) | 1491 | (fd && atomic_read(&fd->count) > 1)) { |
1474 | return -EINVAL; | 1492 | *new_fdp = dup_fd(fd, &error); |
1493 | if (!*new_fdp) | ||
1494 | return error; | ||
1495 | } | ||
1475 | 1496 | ||
1476 | return 0; | 1497 | return 0; |
1477 | } | 1498 | } |