1650 lines · 39.7 KB · C
RawDownload
 * Unshare vm if it is being shared */static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp){	struct mm_struct *mm = current->mm; 	if ((unshare_flags & CLONE_VM) &&	    (mm && atomic_read(&mm->mm_users) > 1)) {		return -EINVAL;	} 	return 0;} /* * Unshare file descriptor table if it is being shared */static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp){	struct files_struct *fd = current->files;	int error = 0; 	if ((unshare_flags & CLONE_FILES) &&	    (fd && atomic_read(&fd->count) > 1)) {		*new_fdp = dup_fd(fd, &error);		if (!*new_fdp)			return error;	} 	return 0;} /* * Unsharing of semundo for tasks created with CLONE_SYSVSEM is not * supported yet */static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **new_ulistp){	if (unshare_flags & CLONE_SYSVSEM)		return -EINVAL; 	return 0;} /* * unshare allows a process to 'unshare' part of the process * context which was originally shared using clone.  copy_* * functions used by do_fork() cannot be used here directly * because they modify an inactive task_struct that is being * constructed. Here we are modifying the current, active, * task_struct. */asmlinkage long sys_unshare(unsigned long unshare_flags){	int err = 0;	struct fs_struct *fs, *new_fs = NULL;	struct namespace *ns, *new_ns = NULL;	struct sighand_struct *sigh, *new_sigh = NULL;	struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;	struct files_struct *fd, *new_fd = NULL;	struct sem_undo_list *new_ulist = NULL; 	check_unshare_flags(&unshare_flags); 	/* Return -EINVAL for all unsupported flags */	err = -EINVAL;	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM))		goto bad_unshare_out; 	if ((err = unshare_thread(unshare_flags)))		goto bad_unshare_out;	if ((err = unshare_fs(unshare_flags, &new_fs)))		goto bad_unshare_cleanup_thread;	if ((err = unshare_namespace(unshare_flags, &new_ns, new_fs)))		goto bad_unshare_cleanup_fs;	if ((err = unshare_sighand(unshare_flags, &new_sigh)))		goto bad_unshare_cleanup_ns;	if ((err = unshare_vm(unshare_flags, &new_mm)))		goto bad_unshare_cleanup_sigh;	if ((err = unshare_fd(unshare_flags, &new_fd)))		goto bad_unshare_cleanup_vm;	if ((err = unshare_semundo(unshare_flags, &new_ulist)))		goto bad_unshare_cleanup_fd; 	if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { 		task_lock(current); 		if (new_fs) {			fs = current->fs;			current->fs = new_fs;			new_fs = fs;		} 		if (new_ns) {			ns = current->namespace;			current->namespace = new_ns;			new_ns = ns;		} 		if (new_sigh) {			sigh = current->sighand;			rcu_assign_pointer(current->sighand, new_sigh);			new_sigh = sigh;		} 		if (new_mm) {			mm = current->mm;			active_mm = current->active_mm;			current->mm = new_mm;			current->active_mm = new_mm;			activate_mm(active_mm, new_mm);			new_mm = mm;		} 		if (new_fd) {			fd = current->files;			current->files = new_fd;			new_fd = fd;		} 		task_unlock(current);	} bad_unshare_cleanup_fd:	if (new_fd)		put_files_struct(new_fd); bad_unshare_cleanup_vm:	if (new_mm)		mmput(new_mm); bad_unshare_cleanup_sigh:	if (new_sigh)		if (atomic_dec_and_test(&new_sigh->count))			kmem_cache_free(sighand_cachep, new_sigh); bad_unshare_cleanup_ns:	if (new_ns)		put_namespace(new_ns); bad_unshare_cleanup_fs:	if (new_fs)		put_fs_struct(new_fs); bad_unshare_cleanup_thread:bad_unshare_out:	return err;}

Lines 1501–1650 of 1650. Previous lines