1650 lines · 39.7 KB · C
RawDownload
	init_sigpending(&p->pending); 	p->utime = cputime_zero;	p->stime = cputime_zero; 	p->sched_time = 0;	p->rchar = 0;		/* I/O counter: bytes read */	p->wchar = 0;		/* I/O counter: bytes written */	p->syscr = 0;		/* I/O counter: read syscalls */	p->syscw = 0;		/* I/O counter: write syscalls */	acct_clear_integrals(p);  	p->it_virt_expires = cputime_zero;	p->it_prof_expires = cputime_zero; 	p->it_sched_expires = 0; 	INIT_LIST_HEAD(&p->cpu_timers[0]); 	INIT_LIST_HEAD(&p->cpu_timers[1]); 	INIT_LIST_HEAD(&p->cpu_timers[2]); 	p->lock_depth = -1;		/* -1 = no lock */	do_posix_clock_monotonic_gettime(&p->start_time);	p->security = NULL;	p->io_context = NULL;	p->io_wait = NULL;	p->audit_context = NULL;	cpuset_fork(p);#ifdef CONFIG_NUMA 	p->mempolicy = mpol_copy(p->mempolicy); 	if (IS_ERR(p->mempolicy)) { 		retval = PTR_ERR(p->mempolicy); 		p->mempolicy = NULL; 		goto bad_fork_cleanup_cpuset; 	}	mpol_fix_fork_child_flag(p);#endif #ifdef CONFIG_DEBUG_MUTEXES	p->blocked_on = NULL; /* not blocked yet */#endif 	p->tgid = p->pid;	if (clone_flags & CLONE_THREAD)		p->tgid = current->tgid; 	if ((retval = security_task_alloc(p)))		goto bad_fork_cleanup_policy;	if ((retval = audit_alloc(p)))		goto bad_fork_cleanup_security;	/* copy all the process information */	if ((retval = copy_semundo(clone_flags, p)))		goto bad_fork_cleanup_audit;	if ((retval = copy_files(clone_flags, p)))		goto bad_fork_cleanup_semundo;	if ((retval = copy_fs(clone_flags, p)))		goto bad_fork_cleanup_files;	if ((retval = copy_sighand(clone_flags, p)))		goto bad_fork_cleanup_fs;	if ((retval = copy_signal(clone_flags, p)))		goto bad_fork_cleanup_sighand;	if ((retval = copy_mm(clone_flags, p)))		goto bad_fork_cleanup_signal;	if ((retval = copy_keys(clone_flags, p)))		goto bad_fork_cleanup_mm;	if ((retval = copy_namespace(clone_flags, p)))		goto bad_fork_cleanup_keys;	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);	if (retval)		goto bad_fork_cleanup_namespace; 	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;	/*	 * Clear TID on mm_release()?	 */	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;	p->robust_list = NULL;#ifdef CONFIG_COMPAT	p->compat_robust_list = NULL;#endif	/*	 * sigaltstack should be cleared when sharing the same VM	 */	if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)		p->sas_ss_sp = p->sas_ss_size = 0; 	/*	 * Syscall tracing should be turned off in the child regardless	 * of CLONE_PTRACE.	 */	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);#ifdef TIF_SYSCALL_EMU	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);#endif 	/* Our parent execution domain becomes current domain	   These must match for thread signalling to apply */	   	p->parent_exec_id = p->self_exec_id; 	/* ok, now we should be set up.. */	p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);	p->pdeath_signal = 0;	p->exit_state = 0; 	/*	 * Ok, make it visible to the rest of the system.	 * We dont wake it up yet.	 */	p->group_leader = p;	INIT_LIST_HEAD(&p->thread_group);	INIT_LIST_HEAD(&p->ptrace_children);	INIT_LIST_HEAD(&p->ptrace_list); 	/* Perform scheduler related setup. Assign this task to a CPU. */	sched_fork(p, clone_flags); 	/* Need tasklist lock for parent etc handling! */	write_lock_irq(&tasklist_lock); 	/*	 * The task hasn't been attached yet, so its cpus_allowed mask will	 * not be changed, nor will its assigned CPU.	 *	 * The cpus_allowed mask of the parent may have changed after it was	 * copied first time - so re-copy it here, then check the child's CPU	 * to ensure it is on a valid CPU (and if not, just force it back to	 * parent's CPU). This avoids alot of nasty races.	 */	p->cpus_allowed = current->cpus_allowed;	if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed) ||			!cpu_online(task_cpu(p))))		set_task_cpu(p, smp_processor_id()); 	/* CLONE_PARENT re-uses the old parent */	if (clone_flags & (CLONE_PARENT|CLONE_THREAD))		p->real_parent = current->real_parent;	else		p->real_parent = current;	p->parent = p->real_parent; 	spin_lock(&current->sighand->siglock); 	/*	 * Process group and session signals need to be delivered to just the	 * parent before the fork or both the parent and the child after the	 * fork. Restart if a signal comes in before we add the new process to	 * it's process group.	 * A fatal signal pending means that current will exit, so the new	 * thread can't slip out of an OOM kill (or normal SIGKILL). 	 */ 	recalc_sigpending();	if (signal_pending(current)) {		spin_unlock(&current->sighand->siglock);		write_unlock_irq(&tasklist_lock);		retval = -ERESTARTNOINTR;		goto bad_fork_cleanup_namespace;	} 	if (clone_flags & CLONE_THREAD) {		/*		 * Important: if an exit-all has been started then		 * do not create this new thread - the whole thread		 * group is supposed to exit anyway.		 */		if (current->signal->flags & SIGNAL_GROUP_EXIT) {			spin_unlock(&current->sighand->siglock);			write_unlock_irq(&tasklist_lock);			retval = -EAGAIN;			goto bad_fork_cleanup_namespace;		} 		p->group_leader = current->group_leader;		list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); 		if (!cputime_eq(current->signal->it_virt_expires,				cputime_zero) ||		    !cputime_eq(current->signal->it_prof_expires,				cputime_zero) ||		    current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY ||		    !list_empty(&current->signal->cpu_timers[0]) ||		    !list_empty(&current->signal->cpu_timers[1]) ||		    !list_empty(&current->signal->cpu_timers[2])) {			/*			 * Have child wake up on its first tick to check			 * for process CPU timers.			 */			p->it_prof_expires = jiffies_to_cputime(1);		}	} 	/*	 * inherit ioprio	 */	p->ioprio = current->ioprio; 	if (likely(p->pid)) {		add_parent(p);		if (unlikely(p->ptrace & PT_PTRACED))			__ptrace_link(p, current->parent); 		if (thread_group_leader(p)) {			p->signal->tty = current->signal->tty;			p->signal->pgrp = process_group(current);			p->signal->session = current->signal->session;			attach_pid(p, PIDTYPE_PGID, process_group(p));			attach_pid(p, PIDTYPE_SID, p->signal->session); 			list_add_tail_rcu(&p->tasks, &init_task.tasks);			__get_cpu_var(process_counts)++;		}		attach_pid(p, PIDTYPE_PID, p->pid);		nr_threads++;	} 	total_forks++;	spin_unlock(&current->sighand->siglock);	write_unlock_irq(&tasklist_lock);	proc_fork_connector(p);	return p; bad_fork_cleanup_namespace:	exit_namespace(p);bad_fork_cleanup_keys:	exit_keys(p);bad_fork_cleanup_mm:	if (p->mm)		mmput(p->mm);bad_fork_cleanup_signal:	cleanup_signal(p);bad_fork_cleanup_sighand:	__cleanup_sighand(p->sighand);bad_fork_cleanup_fs:	exit_fs(p); /* blocking */bad_fork_cleanup_files:	exit_files(p); /* blocking */bad_fork_cleanup_semundo:	exit_sem(p);bad_fork_cleanup_audit:	audit_free(p);bad_fork_cleanup_security:	security_task_free(p);bad_fork_cleanup_policy:#ifdef CONFIG_NUMA	mpol_free(p->mempolicy);bad_fork_cleanup_cpuset:#endif	cpuset_exit(p);bad_fork_cleanup:	if (p->binfmt)		module_put(p->binfmt->module);bad_fork_cleanup_put_domain:	module_put(task_thread_info(p)->exec_domain->module);bad_fork_cleanup_count:	put_group_info(p->group_info);	atomic_dec(&p->user->processes);	free_uid(p->user);bad_fork_free:	free_task(p);fork_out:	return ERR_PTR(retval);} struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs){	memset(regs, 0, sizeof(struct pt_regs));	return regs;} task_t * __devinit fork_idle(int cpu){	task_t *task;	struct pt_regs regs; 	task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL, 0);	if (!task)		return ERR_PTR(-ENOMEM);	init_idle(task, cpu); 	return task;} static inline int fork_traceflag (unsigned clone_flags){	if (clone_flags & CLONE_UNTRACED)		return 0;	else if (clone_flags & CLONE_VFORK) {		if (current->ptrace & PT_TRACE_VFORK)			return PTRACE_EVENT_VFORK;	} else if ((clone_flags & CSIGNAL) != SIGCHLD) {		if (current->ptrace & PT_TRACE_CLONE)			return PTRACE_EVENT_CLONE;	} else if (current->ptrace & PT_TRACE_FORK)		return PTRACE_EVENT_FORK; 	return 0;} /* *  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;	struct pid *pid = alloc_pid();	long nr; 	if (!pid)		return -EAGAIN;	nr = pid->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, parent_tidptr, child_tidptr, nr);	/*	 * 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; 		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) {			wait_for_completion(&vfork);			if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))				ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);		}	} else {		free_pid(pid);		nr = PTR_ERR(p);	}	return nr;} #ifndef ARCH_MIN_MMSTRUCT_ALIGN#define ARCH_MIN_MMSTRUCT_ALIGN 0#endif static void sighand_ctor(void *data, kmem_cache_t *cachep, unsigned long flags){	struct sighand_struct *sighand = data; 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==					SLAB_CTOR_CONSTRUCTOR)		spin_lock_init(&sighand->siglock);} void __init proc_caches_init(void){	sighand_cachep = kmem_cache_create("sighand_cache",			sizeof(struct sighand_struct), 0,			SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,			sighand_ctor, NULL);	signal_cachep = kmem_cache_create("signal_cache",			sizeof(struct signal_struct), 0,			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);	files_cachep = kmem_cache_create("files_cache", 			sizeof(struct files_struct), 0,			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);	fs_cachep = kmem_cache_create("fs_cache", 			sizeof(struct fs_struct), 0,			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);	vm_area_cachep = kmem_cache_create("vm_area_struct",			sizeof(struct vm_area_struct), 0,			SLAB_PANIC, NULL, NULL);	mm_cachep = kmem_cache_create("mm_struct",			sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);}  /* * Check constraints on flags passed to the unshare system call and * force unsharing of additional process context as appropriate. */static inline void check_unshare_flags(unsigned long *flags_ptr){	/*	 * If unsharing a thread from a thread group, must also	 * unshare vm.	 */	if (*flags_ptr & CLONE_THREAD)		*flags_ptr |= CLONE_VM; 	/*	 * If unsharing vm, must also unshare signal handlers.	 */	if (*flags_ptr & CLONE_VM)		*flags_ptr |= CLONE_SIGHAND; 	/*	 * If unsharing signal handlers and the task was created	 * using CLONE_THREAD, then must unshare the thread	 */	if ((*flags_ptr & CLONE_SIGHAND) &&	    (atomic_read(&current->signal->count) > 1))		*flags_ptr |= CLONE_THREAD; 	/*	 * If unsharing namespace, must also unshare filesystem information.	 */	if (*flags_ptr & CLONE_NEWNS)		*flags_ptr |= CLONE_FS;} /* * Unsharing of tasks created with CLONE_THREAD is not supported yet */static int unshare_thread(unsigned long unshare_flags){	if (unshare_flags & CLONE_THREAD)		return -EINVAL; 	return 0;} /* * Unshare the filesystem structure if it is being shared */static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp){	struct fs_struct *fs = current->fs; 	if ((unshare_flags & CLONE_FS) &&	    (fs && atomic_read(&fs->count) > 1)) {		*new_fsp = __copy_fs_struct(current->fs);		if (!*new_fsp)			return -ENOMEM;	} 	return 0;} /* * Unshare the namespace structure if it is being shared */static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs){	struct namespace *ns = current->namespace; 	if ((unshare_flags & CLONE_NEWNS) &&	    (ns && atomic_read(&ns->count) > 1)) {		if (!capable(CAP_SYS_ADMIN))			return -EPERM; 		*new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs);		if (!*new_nsp)			return -ENOMEM;	} 	return 0;} /* * Unsharing of sighand for tasks created with CLONE_SIGHAND is not * supported yet */static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp){	struct sighand_struct *sigh = current->sighand; 	if ((unshare_flags & CLONE_SIGHAND) &&	    (sigh && atomic_read(&sigh->count) > 1))		return -EINVAL;	else		return 0;} /*

Lines 1001–1500 of 1650. Previous lines