diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 77 |
1 files changed, 52 insertions, 25 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 8b20ab7d3aa2..3c31e874afad 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -352,6 +352,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | |||
352 | unsigned long charge; | 352 | unsigned long charge; |
353 | struct mempolicy *pol; | 353 | struct mempolicy *pol; |
354 | 354 | ||
355 | uprobe_start_dup_mmap(); | ||
355 | down_write(&oldmm->mmap_sem); | 356 | down_write(&oldmm->mmap_sem); |
356 | flush_cache_dup_mm(oldmm); | 357 | flush_cache_dup_mm(oldmm); |
357 | uprobe_dup_mmap(oldmm, mm); | 358 | uprobe_dup_mmap(oldmm, mm); |
@@ -469,6 +470,7 @@ out: | |||
469 | up_write(&mm->mmap_sem); | 470 | up_write(&mm->mmap_sem); |
470 | flush_tlb_mm(oldmm); | 471 | flush_tlb_mm(oldmm); |
471 | up_write(&oldmm->mmap_sem); | 472 | up_write(&oldmm->mmap_sem); |
473 | uprobe_end_dup_mmap(); | ||
472 | return retval; | 474 | return retval; |
473 | fail_nomem_anon_vma_fork: | 475 | fail_nomem_anon_vma_fork: |
474 | mpol_put(pol); | 476 | mpol_put(pol); |
@@ -1127,7 +1129,6 @@ static void posix_cpu_timers_init(struct task_struct *tsk) | |||
1127 | */ | 1129 | */ |
1128 | static struct task_struct *copy_process(unsigned long clone_flags, | 1130 | static struct task_struct *copy_process(unsigned long clone_flags, |
1129 | unsigned long stack_start, | 1131 | unsigned long stack_start, |
1130 | struct pt_regs *regs, | ||
1131 | unsigned long stack_size, | 1132 | unsigned long stack_size, |
1132 | int __user *child_tidptr, | 1133 | int __user *child_tidptr, |
1133 | struct pid *pid, | 1134 | struct pid *pid, |
@@ -1135,7 +1136,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1135 | { | 1136 | { |
1136 | int retval; | 1137 | int retval; |
1137 | struct task_struct *p; | 1138 | struct task_struct *p; |
1138 | int cgroup_callbacks_done = 0; | ||
1139 | 1139 | ||
1140 | if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) | 1140 | if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) |
1141 | return ERR_PTR(-EINVAL); | 1141 | return ERR_PTR(-EINVAL); |
@@ -1222,7 +1222,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1222 | p->utime = p->stime = p->gtime = 0; | 1222 | p->utime = p->stime = p->gtime = 0; |
1223 | p->utimescaled = p->stimescaled = 0; | 1223 | p->utimescaled = p->stimescaled = 0; |
1224 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 1224 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING |
1225 | p->prev_utime = p->prev_stime = 0; | 1225 | p->prev_cputime.utime = p->prev_cputime.stime = 0; |
1226 | #endif | 1226 | #endif |
1227 | #if defined(SPLIT_RSS_COUNTING) | 1227 | #if defined(SPLIT_RSS_COUNTING) |
1228 | memset(&p->rss_stat, 0, sizeof(p->rss_stat)); | 1228 | memset(&p->rss_stat, 0, sizeof(p->rss_stat)); |
@@ -1320,7 +1320,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1320 | retval = copy_io(clone_flags, p); | 1320 | retval = copy_io(clone_flags, p); |
1321 | if (retval) | 1321 | if (retval) |
1322 | goto bad_fork_cleanup_namespaces; | 1322 | goto bad_fork_cleanup_namespaces; |
1323 | retval = copy_thread(clone_flags, stack_start, stack_size, p, regs); | 1323 | retval = copy_thread(clone_flags, stack_start, stack_size, p); |
1324 | if (retval) | 1324 | if (retval) |
1325 | goto bad_fork_cleanup_io; | 1325 | goto bad_fork_cleanup_io; |
1326 | 1326 | ||
@@ -1393,12 +1393,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1393 | INIT_LIST_HEAD(&p->thread_group); | 1393 | INIT_LIST_HEAD(&p->thread_group); |
1394 | p->task_works = NULL; | 1394 | p->task_works = NULL; |
1395 | 1395 | ||
1396 | /* Now that the task is set up, run cgroup callbacks if | ||
1397 | * necessary. We need to run them before the task is visible | ||
1398 | * on the tasklist. */ | ||
1399 | cgroup_fork_callbacks(p); | ||
1400 | cgroup_callbacks_done = 1; | ||
1401 | |||
1402 | /* Need tasklist lock for parent etc handling! */ | 1396 | /* Need tasklist lock for parent etc handling! */ |
1403 | write_lock_irq(&tasklist_lock); | 1397 | write_lock_irq(&tasklist_lock); |
1404 | 1398 | ||
@@ -1503,7 +1497,7 @@ bad_fork_cleanup_cgroup: | |||
1503 | #endif | 1497 | #endif |
1504 | if (clone_flags & CLONE_THREAD) | 1498 | if (clone_flags & CLONE_THREAD) |
1505 | threadgroup_change_end(current); | 1499 | threadgroup_change_end(current); |
1506 | cgroup_exit(p, cgroup_callbacks_done); | 1500 | cgroup_exit(p, 0); |
1507 | delayacct_tsk_free(p); | 1501 | delayacct_tsk_free(p); |
1508 | module_put(task_thread_info(p)->exec_domain->module); | 1502 | module_put(task_thread_info(p)->exec_domain->module); |
1509 | bad_fork_cleanup_count: | 1503 | bad_fork_cleanup_count: |
@@ -1515,12 +1509,6 @@ fork_out: | |||
1515 | return ERR_PTR(retval); | 1509 | return ERR_PTR(retval); |
1516 | } | 1510 | } |
1517 | 1511 | ||
1518 | noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_regs *regs) | ||
1519 | { | ||
1520 | memset(regs, 0, sizeof(struct pt_regs)); | ||
1521 | return regs; | ||
1522 | } | ||
1523 | |||
1524 | static inline void init_idle_pids(struct pid_link *links) | 1512 | static inline void init_idle_pids(struct pid_link *links) |
1525 | { | 1513 | { |
1526 | enum pid_type type; | 1514 | enum pid_type type; |
@@ -1534,10 +1522,7 @@ static inline void init_idle_pids(struct pid_link *links) | |||
1534 | struct task_struct * __cpuinit fork_idle(int cpu) | 1522 | struct task_struct * __cpuinit fork_idle(int cpu) |
1535 | { | 1523 | { |
1536 | struct task_struct *task; | 1524 | struct task_struct *task; |
1537 | struct pt_regs regs; | 1525 | task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0); |
1538 | |||
1539 | task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, | ||
1540 | &init_struct_pid, 0); | ||
1541 | if (!IS_ERR(task)) { | 1526 | if (!IS_ERR(task)) { |
1542 | init_idle_pids(task->pids); | 1527 | init_idle_pids(task->pids); |
1543 | init_idle(task, cpu); | 1528 | init_idle(task, cpu); |
@@ -1554,7 +1539,6 @@ struct task_struct * __cpuinit fork_idle(int cpu) | |||
1554 | */ | 1539 | */ |
1555 | long do_fork(unsigned long clone_flags, | 1540 | long do_fork(unsigned long clone_flags, |
1556 | unsigned long stack_start, | 1541 | unsigned long stack_start, |
1557 | struct pt_regs *regs, | ||
1558 | unsigned long stack_size, | 1542 | unsigned long stack_size, |
1559 | int __user *parent_tidptr, | 1543 | int __user *parent_tidptr, |
1560 | int __user *child_tidptr) | 1544 | int __user *child_tidptr) |
@@ -1584,7 +1568,7 @@ long do_fork(unsigned long clone_flags, | |||
1584 | * requested, no event is reported; otherwise, report if the event | 1568 | * requested, no event is reported; otherwise, report if the event |
1585 | * for the type of forking is enabled. | 1569 | * for the type of forking is enabled. |
1586 | */ | 1570 | */ |
1587 | if (!(clone_flags & CLONE_UNTRACED) && likely(user_mode(regs))) { | 1571 | if (!(clone_flags & CLONE_UNTRACED)) { |
1588 | if (clone_flags & CLONE_VFORK) | 1572 | if (clone_flags & CLONE_VFORK) |
1589 | trace = PTRACE_EVENT_VFORK; | 1573 | trace = PTRACE_EVENT_VFORK; |
1590 | else if ((clone_flags & CSIGNAL) != SIGCHLD) | 1574 | else if ((clone_flags & CSIGNAL) != SIGCHLD) |
@@ -1596,7 +1580,7 @@ long do_fork(unsigned long clone_flags, | |||
1596 | trace = 0; | 1580 | trace = 0; |
1597 | } | 1581 | } |
1598 | 1582 | ||
1599 | p = copy_process(clone_flags, stack_start, regs, stack_size, | 1583 | p = copy_process(clone_flags, stack_start, stack_size, |
1600 | child_tidptr, NULL, trace); | 1584 | child_tidptr, NULL, trace); |
1601 | /* | 1585 | /* |
1602 | * Do this prior waking up the new thread - the thread pointer | 1586 | * Do this prior waking up the new thread - the thread pointer |
@@ -1640,11 +1624,54 @@ long do_fork(unsigned long clone_flags, | |||
1640 | */ | 1624 | */ |
1641 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | 1625 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) |
1642 | { | 1626 | { |
1643 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn, NULL, | 1627 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn, |
1644 | (unsigned long)arg, NULL, NULL); | 1628 | (unsigned long)arg, NULL, NULL); |
1645 | } | 1629 | } |
1646 | #endif | 1630 | #endif |
1647 | 1631 | ||
1632 | #ifdef __ARCH_WANT_SYS_FORK | ||
1633 | SYSCALL_DEFINE0(fork) | ||
1634 | { | ||
1635 | #ifdef CONFIG_MMU | ||
1636 | return do_fork(SIGCHLD, 0, 0, NULL, NULL); | ||
1637 | #else | ||
1638 | /* can not support in nommu mode */ | ||
1639 | return(-EINVAL); | ||
1640 | #endif | ||
1641 | } | ||
1642 | #endif | ||
1643 | |||
1644 | #ifdef __ARCH_WANT_SYS_VFORK | ||
1645 | SYSCALL_DEFINE0(vfork) | ||
1646 | { | ||
1647 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, | ||
1648 | 0, NULL, NULL); | ||
1649 | } | ||
1650 | #endif | ||
1651 | |||
1652 | #ifdef __ARCH_WANT_SYS_CLONE | ||
1653 | #ifdef CONFIG_CLONE_BACKWARDS | ||
1654 | SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, | ||
1655 | int __user *, parent_tidptr, | ||
1656 | int, tls_val, | ||
1657 | int __user *, child_tidptr) | ||
1658 | #elif defined(CONFIG_CLONE_BACKWARDS2) | ||
1659 | SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags, | ||
1660 | int __user *, parent_tidptr, | ||
1661 | int __user *, child_tidptr, | ||
1662 | int, tls_val) | ||
1663 | #else | ||
1664 | SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, | ||
1665 | int __user *, parent_tidptr, | ||
1666 | int __user *, child_tidptr, | ||
1667 | int, tls_val) | ||
1668 | #endif | ||
1669 | { | ||
1670 | return do_fork(clone_flags, newsp, 0, | ||
1671 | parent_tidptr, child_tidptr); | ||
1672 | } | ||
1673 | #endif | ||
1674 | |||
1648 | #ifndef ARCH_MIN_MMSTRUCT_ALIGN | 1675 | #ifndef ARCH_MIN_MMSTRUCT_ALIGN |
1649 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 | 1676 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 |
1650 | #endif | 1677 | #endif |