diff options
| author | JANAK DESAI <janak@us.ibm.com> | 2006-02-07 15:59:02 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-07 19:12:34 -0500 |
| commit | a016f3389c06606dd80e687942ff3c71d41823c4 (patch) | |
| tree | c6fdc00cc6762d98fea1fad64d851119d5e7aa45 /kernel | |
| parent | a0a7ec308f1be5957b20a1a535d21f683dfd83f0 (diff) | |
[PATCH] unshare system call -v5: unshare files
If the file descriptor structure is being shared, allocate a new one and copy
information from the current, shared, structure.
Signed-off-by: Janak Desai <janak@us.ibm.com>
Cc: Al Viro <viro@ftp.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Andi Kleen <ak@muc.de>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
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 | } |
