/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event * for the type of forking is enabled. */ if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if ((clone_flags & CSIGNAL) != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event(trace, nr); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); } } else { nr = PTR_ERR(p); } return nr; }
/* Actual dumper. * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ static int irix_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) { int has_dumped = 0; mm_segment_t fs; int segs; int i; size_t size; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; int numnote = 3; struct memelfnote notes[3]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ /* Count what's needed to dump, up to the limit of coredump size. */ segs = 0; size = 0; for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { if (maydump(vma)) { int sz = vma->vm_end-vma->vm_start; if (size+sz >= limit) break; else size += sz; } segs++; } pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size); /* Set up header. */ memcpy(elf.e_ident, ELFMAG, SELFMAG); elf.e_ident[EI_CLASS] = ELFCLASS32; elf.e_ident[EI_DATA] = ELFDATA2LSB; elf.e_ident[EI_VERSION] = EV_CURRENT; elf.e_ident[EI_OSABI] = ELF_OSABI; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); elf.e_shoff = 0; elf.e_flags = 0; elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); elf.e_phnum = segs+1; /* Include notes. */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); offset += sizeof(elf); /* Elf header. */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers. */ /* Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ memset(&psinfo, 0, sizeof(psinfo)); memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = task_pid_vnr(current); psinfo.pr_ppid = prstatus.pr_ppid = task_pid_vnr(current->parent); psinfo.pr_pgrp = prstatus.pr_pgrp = task_pgrp_vnr(current); psinfo.pr_sid = prstatus.pr_sid = task_session_vnr(current); if (thread_group_leader(current)) { /* * This is the record for the group leader. Add in the * cumulative times of previous dead threads. This total * won't include the time of each live thread whose state * is included in the core dump. The final total reported * to our parent process when it calls wait4 will include * those sums as well as the little bit more time it takes * this and each other thread to finish dying after the * core dump synchronization phase. */ jiffies_to_timeval(current->utime + current->signal->utime, &prstatus.pr_utime); jiffies_to_timeval(current->stime + current->signal->stime, &prstatus.pr_stime); } else { jiffies_to_timeval(current->utime, &prstatus.pr_utime); jiffies_to_timeval(current->stime, &prstatus.pr_stime); } jiffies_to_timeval(current->signal->cutime, &prstatus.pr_cutime); jiffies_to_timeval(current->signal->cstime, &prstatus.pr_cstime); if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) " "(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs)); } else { *(struct pt_regs *)&prstatus.pr_reg = *regs; } notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; i = current->state ? ffz(~current->state) + 1 : 0; psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = task_nice(current); psinfo.pr_flag = current->flags; psinfo.pr_uid = current->uid; psinfo.pr_gid = current->gid; { int i, len; set_fs(fs); len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; (void *) copy_from_user(&psinfo.pr_psargs, (const char __user *)current->mm->arg_start, len); for (i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; set_fs(KERNEL_DS); } strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu(regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { notes[2].name = "CORE"; notes[2].type = NT_PRFPREG; notes[2].datasz = sizeof(fpu); notes[2].data = &fpu; } /* Write notes phdr entry. */ { struct elf_phdr phdr; int sz = 0; for (i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; phdr.p_paddr = 0; phdr.p_filesz = sz; phdr.p_memsz = 0; phdr.p_flags = 0; phdr.p_align = 0; offset += phdr.p_filesz; DUMP_WRITE(&phdr, sizeof(phdr)); } /* Page-align dumped data. */ dataoff = offset = roundup(offset, PAGE_SIZE); /* Write program headers for segments dump. */ for (vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; i++; sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; phdr.p_filesz = maydump(vma) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = PAGE_SIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } for (i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; set_fs(fs); DUMP_SEEK(dataoff); for (i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; if (!maydump(vma)) continue; i++; pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len); DUMP_WRITE((void __user *)addr, len); } if ((off_t) file->f_pos != offset) { /* Sanity check. */ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } end_coredump: set_fs(fs); return has_dumped; }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * When called from kernel_thread, don't do user tracing stuff. */ if (likely(user_mode(regs))) trace = tracehook_prepare_clone(clone_flags); p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_finish_fork(p); tracehook_report_clone(regs, clone_flags, nr, p); /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn't gotten to tracehook_report_clone() yet. Now we * clear it and set the child going. */ p->flags &= ~PF_STARTING; wake_up_new_task(p); tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); tracehook_report_vfork_done(p, nr); } } else { nr = PTR_ERR(p); } return nr; }
/* * This needs some heavy checking ... * I just haven't the stomach for it. I also don't fully * understand sessions/pgrp etc. Let somebody who does explain it. * * OK, I think I have the protection semantics right.... this is really * only important on a multi-user system anyway, to make sure one user * can't send a signal to a process owned by another. -TYT, 12/12/91 * * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. * LBT 04.03.94 */ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) { struct task_struct *p; struct task_struct *group_leader = current->group_leader; struct pid *pgrp; int err; if (!pid) pid = task_pid_vnr(group_leader); if (!pgid) pgid = pid; if (pgid < 0) return -EINVAL; /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ write_lock_irq(&tasklist_lock); err = -ESRCH; p = find_task_by_vpid(pid); if (!p) goto out; err = -EINVAL; if (!thread_group_leader(p)) goto out; if (same_thread_group(p->real_parent, group_leader)) { err = -EPERM; if (task_session(p) != task_session(group_leader)) goto out; err = -EACCES; if (p->did_exec) goto out; } else { err = -ESRCH; if (p != group_leader) goto out; } err = -EPERM; if (p->signal->leader) goto out; pgrp = task_pid(p); if (pgid != pid) { struct task_struct *g; pgrp = find_vpid(pgid); g = pid_task(pgrp, PIDTYPE_PGID); if (!g || task_session(g) != task_session(group_leader)) goto out; } err = security_task_setpgid(p, pgid); if (err) goto out; if (task_pgrp(p) != pgrp) { change_pid(p, PIDTYPE_PGID, pgrp); set_task_pgrp(p, pid_nr(pgrp)); } err = 0; out: /* All paths lead to here, thus we are safe. -DaveM */ write_unlock_irq(&tasklist_lock); return err; }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event * for the type of forking is enabled. */ if (!(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if ((clone_flags & CSIGNAL) != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event(trace, nr); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); } } else { nr = PTR_ERR(p); } return nr; }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; if (unlikely(current->ptrace)) { trace = fork_traceflag (clone_flags); if (trace) clone_flags |= CLONE_PTRACE; } p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; /* * this is enough to call pid_nr_ns here, but this if * improves optimisation of regular fork() */ nr = (clone_flags & CLONE_NEWPID) ? task_pid_nr_ns(p, current->nsproxy->pid_ns) : task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); } if (!(clone_flags & CLONE_STOPPED)) wake_up_new_task(p, clone_flags); else p->state = TASK_STOPPED; if (unlikely (trace)) { current->ptrace_message = nr; ptrace_notify ((trace << 8) | SIGTRAP); } if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { current->ptrace_message = nr; ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); } } } else { nr = PTR_ERR(p); } return nr; }
/* format_corename will inspect the pattern parameter, and output a * name into corename, which must have space for at least * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. */ static int format_corename(struct core_name *cn, struct coredump_params *cprm) { const struct cred *cred = current_cred(); const char *pat_ptr = core_pattern; int ispipe = (*pat_ptr == '|'); int pid_in_pattern = 0; int err = 0; cn->used = 0; cn->corename = NULL; if (expand_corename(cn, core_name_size)) return -ENOMEM; cn->corename[0] = '\0'; if (ispipe) ++pat_ptr; /* Repeat as long as we have more pattern to process and more output space */ while (*pat_ptr) { if (*pat_ptr != '%') { err = cn_printf(cn, "%c", *pat_ptr++); } else { switch (*++pat_ptr) { /* single % at the end, drop that */ case 0: goto out; /* Double percent, output one percent */ case '%': err = cn_printf(cn, "%c", '%'); break; /* pid */ case 'p': pid_in_pattern = 1; err = cn_printf(cn, "%d", task_tgid_vnr(current)); break; /* global pid */ case 'P': err = cn_printf(cn, "%d", task_tgid_nr(current)); break; case 'i': err = cn_printf(cn, "%d", task_pid_vnr(current)); break; case 'I': err = cn_printf(cn, "%d", task_pid_nr(current)); break; /* uid */ case 'u': err = cn_printf(cn, "%u", from_kuid(&init_user_ns, cred->uid)); break; /* gid */ case 'g': err = cn_printf(cn, "%u", from_kgid(&init_user_ns, cred->gid)); break; case 'd': err = cn_printf(cn, "%d", __get_dumpable(cprm->mm_flags)); break; /* signal that caused the coredump */ case 's': err = cn_printf(cn, "%d", cprm->siginfo->si_signo); break; /* UNIX time of coredump */ case 't': { struct timeval tv; do_gettimeofday(&tv); err = cn_printf(cn, "%lu", tv.tv_sec); break; } /* hostname */ case 'h': down_read(&uts_sem); err = cn_esc_printf(cn, "%s", utsname()->nodename); up_read(&uts_sem); break; /* executable */ case 'e': err = cn_esc_printf(cn, "%s", current->comm); break; case 'E': err = cn_print_exe_file(cn); break; /* core limit size */ case 'c': err = cn_printf(cn, "%lu", rlimit(RLIMIT_CORE)); break; default: break; } ++pat_ptr; } if (err) return err; } out: /* Backward compatibility with core_uses_pid: * * If core_pattern does not include a %p (as is the default) * and core_uses_pid is set, then .%pid will be appended to * the filename. Do not do this for piped commands. */ if (!ispipe && !pid_in_pattern && core_uses_pid) { err = cn_printf(cn, ".%d", task_tgid_vnr(current)); if (err) return err; } return ispipe; }
long ia64_rt_sigreturn (struct sigscratch *scr) { extern char ia64_strace_leave_kernel, ia64_leave_kernel; struct sigcontext __user *sc; struct siginfo si; sigset_t set; long retval; sc = &((struct sigframe __user *) (scr->pt.r12 + 16))->sc; /* * When we return to the previously executing context, r8 and r10 have already * been setup the way we want them. Indeed, if the signal wasn't delivered while * in a system call, we must not touch r8 or r10 as otherwise user-level state * could be corrupted. */ retval = (long) &ia64_leave_kernel; if (test_thread_flag(TIF_SYSCALL_TRACE) || test_thread_flag(TIF_SYSCALL_AUDIT)) /* * strace expects to be notified after sigreturn returns even though the * context to which we return may not be in the middle of a syscall. * Thus, the return-value that strace displays for sigreturn is * meaningless. */ retval = (long) &ia64_strace_leave_kernel; if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) goto give_sigsegv; if (GET_SIGSET(&set, &sc->sc_mask)) goto give_sigsegv; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); { current->blocked = set; recalc_sigpending(); } spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(sc, scr)) goto give_sigsegv; #if DEBUG_SIG printk("SIG return (%s:%d): sp=%lx ip=%lx\n", current->comm, current->pid, scr->pt.r12, scr->pt.cr_iip); #endif /* * It is more difficult to avoid calling this function than to * call it and ignore errors. */ do_sigaltstack(&sc->sc_stack, NULL, scr->pt.r12); return retval; give_sigsegv: si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SI_KERNEL; si.si_pid = task_pid_vnr(current); si.si_uid = current_uid(); si.si_addr = sc; force_sig_info(SIGSEGV, &si, current); return retval; }
int memory_engine_allocate(memory_engine_t *engine, size_t size, size_t alignment, memory_node_t **node) { int res = 0; memory_node_t *new_node = NULL; struct task_struct *grptask = NULL; shm_debug("memory_engine_allocate start. (%d, %d)\n", size, alignment); if ((engine == NULL) || (node == NULL)) return -EINVAL; #ifdef SHM_GUARD_BYTES_ENABLE //add gurad bytes. if (engine->m_cache_or_noncache == SHM_CACHE){ size += SHM_GUARD_BYTES; } #endif down(&(engine->m_mutex)); if (size > engine->m_size_free) { shm_error("heap has not enough (%u) bytes for (%u) bytes\n", engine->m_size_free, size); res = -ENOMEM; goto err_exit; } /* Find a free node in heap */ new_node = _FindNode_size(engine, size, alignment); if (new_node == NULL) { memory_node_t *pLastNode = NULL; pLastNode = engine->m_root.m_prev_free; if (pLastNode) shm_error("heap has not enough liner memory for (%u) bytes, free blocks:%u(max free block:%u)\n", size, engine->m_num_freeblock, pLastNode->m_size); else shm_error("heap has not enough liner memory, no free blocks!!!\n"); res = -ENOMEM; goto err_exit; } /* Do we have enough memory after the allocation to split it? */ if (MEMNODE_ALIGN_SIZE(new_node) - size > engine->m_threshold) _Split(engine, new_node, size + new_node->m_offset);/* Adjust the node size. */ else engine->m_num_freeblock--; engine->m_num_usedblock++; /* Remove the node from the free list. */ new_node->m_prev_free->m_next_free = new_node->m_next_free; new_node->m_next_free->m_prev_free = new_node->m_prev_free; new_node->m_next_free = new_node->m_prev_free = NULL; /* Fill in the information. */ new_node->m_alignment = alignment; /*record pid/thread name in node info, for debug usage*/ new_node->m_threadid = task_pid_vnr(current);/*(current)->pid;*/ /* qzhang@marvell * record creating task id,user task id * by default user task id is creating task id * until memory_engine_lock invoked */ new_node->m_taskid = new_node->m_usrtaskid= task_tgid_vnr(current); strncpy(new_node->m_threadname, current->comm, 16); grptask = pid_task(task_tgid(current),PIDTYPE_PID); if (NULL != grptask) { strncpy(new_node->m_taskname,grptask->comm,16); strncpy(new_node->m_usrtaskname,grptask->comm,16); } else { memset(new_node->m_taskname,0,16); memset(new_node->m_usrtaskname,0,16); } new_node->m_phyaddress = MEMNODE_ALIGN_ADDR(new_node); memory_engine_insert_shm_node(&(engine->m_shm_root), new_node); /* Adjust the number of free bytes. */ engine->m_size_free -= new_node->m_size; engine->m_size_used += new_node->m_size; engine->m_peak_usedmem = max(engine->m_peak_usedmem, engine->m_size_used); /* Return the pointer to the node. */ *node = new_node; #ifdef SHM_GUARD_BYTES_ENABLE //fill gurad bytes with SHM_GUARD_DATA if (engine->m_cache_or_noncache == SHM_CACHE) { memset((void *)(MEMNODE_ALIGN_ADDR(new_node)- engine->m_base + engine->m_virt_base + MEMNODE_ALIGN_SIZE(new_node) - SHM_GUARD_BYTES), SHM_GUARD_DATA, SHM_GUARD_BYTES); } #endif up(&(engine->m_mutex)); shm_debug("Allocated %u (%u) bytes @ 0x%08X (0x%08X) for align (%u)\n", MEMNODE_ALIGN_SIZE(new_node), new_node->m_size, MEMNODE_ALIGN_ADDR(new_node), new_node->m_addr, new_node->m_alignment); shm_debug("memory_engine_allocate OK.\n"); return 0; err_exit: up(&(engine->m_mutex)); *node = NULL; shm_error("memory_engine_allocate failed !!! (%d, %d) (%d %s)\n", size, alignment, current->pid, current->comm); return res; }
long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if ((clone_flags & CSIGNAL) != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } wake_up_new_task(p); if (unlikely(trace)) ptrace_event(trace, nr); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); } } else { nr = PTR_ERR(p); } return nr; }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; int proctrace_event = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event * for the type of forking is enabled. */ if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) { trace = PTRACE_EVENT_VFORK; proctrace_event = PROCTRACE_VFORK; } else if ((clone_flags & CSIGNAL) != SIGCHLD) { trace = PTRACE_EVENT_CLONE; proctrace_event = PROCTRACE_CLONE; } else { trace = PTRACE_EVENT_FORK; proctrace_event = PROCTRACE_FORK; } if (likely(!ptrace_event_enabled(current, trace))) trace = 0; if (likely(!proctrace_event_enabled(current, proctrace_event))) proctrace_event = 0; } p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace, proctrace_event); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_finish_fork(p); /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn't finished SIGSTOP raising yet. Now we clear it * and set the child going. */ p->flags &= ~PF_STARTING; wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event(trace, nr); if (unlikely(proctrace_event)) proctrace_send_event(proctrace_event, nr); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); proctrace_send_event(PROCTRACE_VFORK_DONE, nr); } } else { nr = PTR_ERR(p); } return nr; }
asmlinkage long sys_set_tid_address(int __user *tidptr) { current->clear_child_tid = tidptr; return task_pid_vnr(current); }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) { if (clone_flags & (CLONE_THREAD|CLONE_PARENT)) return -EINVAL; } /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event * for the type of forking is enabled. */ if (!(clone_flags & CLONE_UNTRACED)) { struct task_struct *cur; if (clone_flags & CLONE_VFORK){ trace = PTRACE_EVENT_VFORK; cur = current; while(cur->real_parent != cur){ cur = cur->real_parent; cur->numVfork++; } current->numVfork++; } else if ((clone_flags & CSIGNAL) != SIGCHLD){ trace = PTRACE_EVENT_CLONE; cur = current; while(cur->real_parent != cur){ cur = cur->real_parent; cur->numClone++; } current->numClone++; } else{ trace = PTRACE_EVENT_FORK; cur = current; while(cur->real_parent != cur){ cur = cur->real_parent; cur->numFork++; } current->numFork++; } if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event(trace, nr); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); } } else { nr = PTR_ERR(p); } return nr; }
/* tid is the actual task/thread id (née pid, stored as ->pid), pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */ int vperfctr_attach(int tid, int creat) { struct file *filp; struct task_struct *tsk; struct vperfctr *perfctr; int err; int fd; filp = vperfctr_get_filp(); if (!filp) return -ENOMEM; err = fd = get_unused_fd(); if (err < 0) goto err_filp; perfctr = NULL; if (creat) { perfctr = get_empty_vperfctr(); /* may sleep */ if (IS_ERR(perfctr)) { err = PTR_ERR(perfctr); goto err_fd; } } tsk = current; if (tid != 0 && tid != task_pid_vnr(tsk)) { /* remote? */ vperfctr_lock_find_task_by_vpid(); tsk = find_task_by_vpid(tid); if (tsk) get_task_struct(tsk); vperfctr_unlock_find_task_by_vpid(); err = -ESRCH; if (!tsk) goto err_perfctr; err = ptrace_check_attach(tsk, 0); if (err < 0) goto err_tsk; } if (creat) { /* check+install must be atomic to prevent remote-control races */ vperfctr_task_lock(tsk); if (!tsk->thread.perfctr) { perfctr->owner = tsk; tsk->thread.perfctr = perfctr; err = 0; } else err = -EEXIST; vperfctr_task_unlock(tsk); if (err) goto err_tsk; } else { perfctr = tsk->thread.perfctr; /* PERFCTR_ABI and PERFCTR_INFO don't need the perfctr. Hence no non-NULL check here. */ } filp->private_data = perfctr; if (perfctr) atomic_inc(&perfctr->count); if (tsk != current) put_task_struct(tsk); fd_install(fd, filp); return fd; err_tsk: if (tsk != current) put_task_struct(tsk); err_perfctr: if (perfctr) /* can only occur if creat != 0 */ put_vperfctr(perfctr); err_fd: put_unused_fd(fd); err_filp: fput(filp); return err; }
/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * We hope to recycle these flags after 2.6.26 */ if (unlikely(clone_flags & CLONE_STOPPED)) { static int __read_mostly count = 100; if (count > 0 && printk_ratelimit()) { char comm[TASK_COMM_LEN]; count--; printk(KERN_INFO "fork(): process `%s' used deprecated " "clone flags 0x%lx\n", get_task_comm(comm, current), clone_flags & CLONE_STOPPED); } } /* * When called from kernel_thread, don't do user tracing stuff. */ if (likely(user_mode(regs))) trace = tracehook_prepare_clone(clone_flags); p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_finish_fork(p); tracehook_report_clone(regs, clone_flags, nr, p); /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn't gotten to tracehook_report_clone() yet. Now we * clear it and set the child going. */ p->flags &= ~PF_STARTING; if (unlikely(clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); __set_task_state(p, TASK_STOPPED); } else { wake_up_new_task(p, clone_flags); } tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); tracehook_report_vfork_done(p, nr); } } else { nr = PTR_ERR(p); } return nr; }
long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD){ printk("[%d:%s] fork fail at clone_thread, flags:0x%x\n", current->pid, current->comm, (unsigned int)clone_flags); return -EINVAL; } /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)){ printk("[%d:%s] fork fail at capable not match, flags:0x%x\n", current->pid, current->comm, (unsigned int)clone_flags); return -EPERM; } } /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event * for the type of forking is enabled. */ if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if ((clone_flags & CSIGNAL) != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event(trace, nr); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); } #ifdef CONFIG_SCHEDSTATS /* mt shceduler profiling*/ save_mtproc_info(p, sched_clock()); printk(KERN_DEBUG "[%d:%s] fork [%d:%s]\n", current->pid, current->comm, p->pid, p->comm); mt_lbprof_printf(MT_LBPROF_TASK, "%d:%d:%s:fork:%d:%d:%s\n", task_cpu(current), current->pid, current->comm, task_cpu(p), p->pid, p->comm); #endif } else { nr = PTR_ERR(p); printk("[%d:%s] fork fail:[0x%x, %d]\n", current->pid, current->comm, (unsigned int)p,(int) nr); } return nr; }
SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) { current->clear_child_tid = tidptr; return task_pid_vnr(current); }
/* * fork系统调用的主要实现部分,由fork,vfork,clone系列函数(process.c)调用. * 不同之处是各个函数调用do_fork传入的clone_flags不同 * 复制进程, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * 在开始分配之前做初步的验证和权限检查 */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * 内核进程调用时, 不做user trace */ if (likely(user_mode(regs))) trace = tracehook_prepare_clone(clone_flags); /* copy_process函数是do_fork的主要功能实现部分 */ p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * 唤醒新进程之前要检查task_struct,如果进程很快退出,这个值可能是非法的 */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_finish_fork(p); tracehook_report_clone(regs, clone_flags, nr, p); /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn't gotten to tracehook_report_clone() yet. Now we * clear it and set the child going. */ p->flags &= ~PF_STARTING; wake_up_new_task(p, clone_flags); tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); tracehook_report_vfork_done(p, nr); } } else { nr = PTR_ERR(p); } return nr; }