aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c81
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
623static 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 */
627static 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;
730out: 713out:
731 return error; 714 return newf;
732 715
733out_release: 716out_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
724static 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;
754out:
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 */
1468static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) 1485static 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}