Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Jun 2015 10:44:00 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r284214 - in head/sys: amd64/amd64 arm/arm i386/i386 kern powerpc/powerpc sparc64/sparc64 sys
Message-ID:  <201506101044.t5AAi0fn028782@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Wed Jun 10 10:43:59 2015
New Revision: 284214
URL: https://svnweb.freebsd.org/changeset/base/284214

Log:
  Generalised support for copy-on-write structures shared by threads.
  
  Thread credentials are maintained as follows: each thread has a pointer to
  creds and a reference on them. The pointer is compared with proc's creds on
  userspace<->kernel boundary and updated if needed.
  
  This patch introduces a counter which can be compared instead, so that more
  structures can use this scheme without adding more comparisons on the boundary.

Modified:
  head/sys/amd64/amd64/trap.c
  head/sys/arm/arm/trap-v6.c
  head/sys/arm/arm/trap.c
  head/sys/i386/i386/trap.c
  head/sys/kern/init_main.c
  head/sys/kern/kern_fork.c
  head/sys/kern/kern_kthread.c
  head/sys/kern/kern_prot.c
  head/sys/kern/kern_syscalls.c
  head/sys/kern/kern_thr.c
  head/sys/kern/kern_thread.c
  head/sys/kern/subr_syscall.c
  head/sys/kern/subr_trap.c
  head/sys/powerpc/powerpc/trap.c
  head/sys/sparc64/sparc64/trap.c
  head/sys/sys/proc.h

Modified: head/sys/amd64/amd64/trap.c
==============================================================================
--- head/sys/amd64/amd64/trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/amd64/amd64/trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -257,8 +257,8 @@ trap(struct trapframe *frame)
 		td->td_pticks = 0;
 		td->td_frame = frame;
 		addr = frame->tf_rip;
-		if (td->td_ucred != p->p_ucred) 
-			cred_update_thread(td);
+		if (td->td_cowgen != p->p_cowgen)
+			thread_cow_update(td);
 
 		switch (type) {
 		case T_PRIVINFLT:	/* privileged instruction fault */

Modified: head/sys/arm/arm/trap-v6.c
==============================================================================
--- head/sys/arm/arm/trap-v6.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/arm/arm/trap-v6.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -395,8 +395,8 @@ abort_handler(struct trapframe *tf, int 
 	p = td->td_proc;
 	if (usermode) {
 		td->td_pticks = 0;
-		if (td->td_ucred != p->p_ucred)
-			cred_update_thread(td);
+		if (td->td_cowgen != p->p_cowgen)
+			thread_cow_update(td);
 	}
 
 	/* Invoke the appropriate handler, if necessary. */

Modified: head/sys/arm/arm/trap.c
==============================================================================
--- head/sys/arm/arm/trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/arm/arm/trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -214,8 +214,8 @@ abort_handler(struct trapframe *tf, int 
 	if (user) {
 		td->td_pticks = 0;
 		td->td_frame = tf;
-		if (td->td_ucred != td->td_proc->p_ucred)
-			cred_update_thread(td);
+		if (td->td_cowgen != td->td_proc->p_cowgen)
+			thread_cow_update(td);
 
 	}
 	/* Grab the current pcb */
@@ -644,8 +644,8 @@ prefetch_abort_handler(struct trapframe 
 
 	if (TRAP_USERMODE(tf)) {
 		td->td_frame = tf;
-		if (td->td_ucred != td->td_proc->p_ucred)
-			cred_update_thread(td);
+		if (td->td_cowgen != td->td_proc->p_cowgen)
+			thread_cow_update(td);
 	}
 	fault_pc = tf->tf_pc;
 	if (td->td_md.md_spinlock_count == 0) {

Modified: head/sys/i386/i386/trap.c
==============================================================================
--- head/sys/i386/i386/trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/i386/i386/trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -306,8 +306,8 @@ trap(struct trapframe *frame)
 		td->td_pticks = 0;
 		td->td_frame = frame;
 		addr = frame->tf_eip;
-		if (td->td_ucred != p->p_ucred) 
-			cred_update_thread(td);
+		if (td->td_cowgen != p->p_cowgen)
+			thread_cow_update(td);
 
 		switch (type) {
 		case T_PRIVINFLT:	/* privileged instruction fault */

Modified: head/sys/kern/init_main.c
==============================================================================
--- head/sys/kern/init_main.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/init_main.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -523,8 +523,6 @@ proc0_init(void *dummy __unused)
 #ifdef MAC
 	mac_cred_create_swapper(newcred);
 #endif
-	td->td_ucred = crhold(newcred);
-
 	/* Create sigacts. */
 	p->p_sigacts = sigacts_alloc();
 
@@ -556,6 +554,10 @@ proc0_init(void *dummy __unused)
 	p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = pageablemem;
 	p->p_cpulimit = RLIM_INFINITY;
 
+	PROC_LOCK(p);
+	thread_cow_get_proc(td, p);
+	PROC_UNLOCK(p);
+
 	/* Initialize resource accounting structures. */
 	racct_create(&p->p_racct);
 
@@ -843,10 +845,10 @@ create_init(const void *udata __unused)
 	audit_cred_proc1(newcred);
 #endif
 	proc_set_cred(initproc, newcred);
+	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
 	PROC_UNLOCK(initproc);
 	sx_xunlock(&proctree_lock);
 	crfree(oldcred);
-	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
 	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
 }
 SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);

Modified: head/sys/kern/kern_fork.c
==============================================================================
--- head/sys/kern/kern_fork.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_fork.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -496,7 +496,6 @@ do_fork(struct thread *td, int flags, st
 	p2->p_swtick = ticks;
 	if (p1->p_flag & P_PROFIL)
 		startprofclock(p2);
-	td2->td_ucred = crhold(p2->p_ucred);
 
 	if (flags & RFSIGSHARE) {
 		p2->p_sigacts = sigacts_hold(p1->p_sigacts);
@@ -526,6 +525,8 @@ do_fork(struct thread *td, int flags, st
 	 */
 	lim_fork(p1, p2);
 
+	thread_cow_get_proc(td2, p2);
+
 	pstats_fork(p1->p_stats, p2->p_stats);
 
 	PROC_UNLOCK(p1);

Modified: head/sys/kern/kern_kthread.c
==============================================================================
--- head/sys/kern/kern_kthread.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_kthread.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -289,7 +289,7 @@ kthread_add(void (*func)(void *), void *
 	cpu_set_fork_handler(newtd, func, arg);
 
 	newtd->td_pflags |= TDP_KTHREAD;
-	newtd->td_ucred = crhold(p->p_ucred);
+	thread_cow_get_proc(newtd, p);
 
 	/* this code almost the same as create_thread() in kern_thr.c */
 	p->p_flag |= P_HADTHREADS;

Modified: head/sys/kern/kern_prot.c
==============================================================================
--- head/sys/kern/kern_prot.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_prot.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -1946,9 +1946,8 @@ cred_update_thread(struct thread *td)
 
 	p = td->td_proc;
 	cred = td->td_ucred;
-	PROC_LOCK(p);
+	PROC_LOCK_ASSERT(p, MA_OWNED);
 	td->td_ucred = crhold(p->p_ucred);
-	PROC_UNLOCK(p);
 	if (cred != NULL)
 		crfree(cred);
 }
@@ -1987,6 +1986,8 @@ proc_set_cred(struct proc *p, struct ucr
 
 	oldcred = p->p_ucred;
 	p->p_ucred = newcred;
+	if (newcred != NULL)
+		PROC_UPDATE_COW(p);
 	return (oldcred);
 }
 

Modified: head/sys/kern/kern_syscalls.c
==============================================================================
--- head/sys/kern/kern_syscalls.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_syscalls.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
 #include <sys/sx.h>
 #include <sys/syscall.h>
 #include <sys/sysent.h>

Modified: head/sys/kern/kern_thr.c
==============================================================================
--- head/sys/kern/kern_thr.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_thr.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -220,13 +220,13 @@ create_thread(struct thread *td, mcontex
 	bcopy(&td->td_startcopy, &newtd->td_startcopy,
 	    __rangeof(struct thread, td_startcopy, td_endcopy));
 	newtd->td_proc = td->td_proc;
-	newtd->td_ucred = crhold(td->td_ucred);
+	thread_cow_get(newtd, td);
 
 	if (ctx != NULL) { /* old way to set user context */
 		error = set_mcontext(newtd, ctx);
 		if (error != 0) {
+			thread_cow_free(newtd);
 			thread_free(newtd);
-			crfree(td->td_ucred);
 			goto fail;
 		}
 	} else {
@@ -238,8 +238,8 @@ create_thread(struct thread *td, mcontex
 		/* Setup user TLS address and TLS pointer register. */
 		error = cpu_set_user_tls(newtd, tls_base);
 		if (error != 0) {
+			thread_cow_free(newtd);
 			thread_free(newtd);
-			crfree(td->td_ucred);
 			goto fail;
 		}
 	}

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/kern_thread.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -327,8 +327,7 @@ thread_reap(void)
 		mtx_unlock_spin(&zombie_lock);
 		while (td_first) {
 			td_next = TAILQ_NEXT(td_first, td_slpq);
-			if (td_first->td_ucred)
-				crfree(td_first->td_ucred);
+			thread_cow_free(td_first);
 			thread_free(td_first);
 			td_first = td_next;
 		}
@@ -384,6 +383,44 @@ thread_free(struct thread *td)
 	uma_zfree(thread_zone, td);
 }
 
+void
+thread_cow_get_proc(struct thread *newtd, struct proc *p)
+{
+
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+	newtd->td_ucred = crhold(p->p_ucred);
+	newtd->td_cowgen = p->p_cowgen;
+}
+
+void
+thread_cow_get(struct thread *newtd, struct thread *td)
+{
+
+	newtd->td_ucred = crhold(td->td_ucred);
+	newtd->td_cowgen = td->td_cowgen;
+}
+
+void
+thread_cow_free(struct thread *td)
+{
+
+	if (td->td_ucred)
+		crfree(td->td_ucred);
+}
+
+void
+thread_cow_update(struct thread *td)
+{
+	struct proc *p;
+
+	p = td->td_proc;
+	PROC_LOCK(p);
+	if (td->td_ucred != p->p_ucred)
+		cred_update_thread(td);
+	td->td_cowgen = p->p_cowgen;
+	PROC_UNLOCK(p);
+}
+
 /*
  * Discard the current thread and exit from its context.
  * Always called with scheduler locked.
@@ -521,7 +558,7 @@ thread_wait(struct proc *p)
 	cpuset_rel(td->td_cpuset);
 	td->td_cpuset = NULL;
 	cpu_thread_clean(td);
-	crfree(td->td_ucred);
+	thread_cow_free(td);
 	thread_reap();	/* check for zombie threads etc. */
 }
 

Modified: head/sys/kern/subr_syscall.c
==============================================================================
--- head/sys/kern/subr_syscall.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/subr_syscall.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -61,8 +61,8 @@ syscallenter(struct thread *td, struct s
 	p = td->td_proc;
 
 	td->td_pticks = 0;
-	if (td->td_ucred != p->p_ucred)
-		cred_update_thread(td);
+	if (td->td_cowgen != p->p_cowgen)
+		thread_cow_update(td);
 	if (p->p_flag & P_TRACED) {
 		traced = 1;
 		PROC_LOCK(p);

Modified: head/sys/kern/subr_trap.c
==============================================================================
--- head/sys/kern/subr_trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/kern/subr_trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -220,8 +220,8 @@ ast(struct trapframe *framep)
 	thread_unlock(td);
 	PCPU_INC(cnt.v_trap);
 
-	if (td->td_ucred != p->p_ucred) 
-		cred_update_thread(td);
+	if (td->td_cowgen != p->p_cowgen)
+		thread_cow_update(td);
 	if (td->td_pflags & TDP_OWEUPC && p->p_flag & P_PROFIL) {
 		addupc_task(td, td->td_profil_addr, td->td_profil_ticks);
 		td->td_profil_ticks = 0;

Modified: head/sys/powerpc/powerpc/trap.c
==============================================================================
--- head/sys/powerpc/powerpc/trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/powerpc/powerpc/trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -196,8 +196,8 @@ trap(struct trapframe *frame)
 	if (user) {
 		td->td_pticks = 0;
 		td->td_frame = frame;
-		if (td->td_ucred != p->p_ucred)
-			cred_update_thread(td);
+		if (td->td_cowgen != p->p_cowgen)
+			thread_cow_update(td);
 
 		/* User Mode Traps */
 		switch (type) {

Modified: head/sys/sparc64/sparc64/trap.c
==============================================================================
--- head/sys/sparc64/sparc64/trap.c	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/sparc64/sparc64/trap.c	Wed Jun 10 10:43:59 2015	(r284214)
@@ -277,8 +277,8 @@ trap(struct trapframe *tf)
 		td->td_pticks = 0;
 		td->td_frame = tf;
 		addr = tf->tf_tpc;
-		if (td->td_ucred != p->p_ucred)
-			cred_update_thread(td);
+		if (td->td_cowgen != p->p_cowgen)
+			thread_cow_update(td);
 
 		switch (tf->tf_type) {
 		case T_DATA_MISS:

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Wed Jun 10 09:59:26 2015	(r284213)
+++ head/sys/sys/proc.h	Wed Jun 10 10:43:59 2015	(r284214)
@@ -308,6 +308,7 @@ struct thread {
 		off_t		tdu_off;	
 	} td_uretoff;			/* (k) Syscall aux returns. */
 #define td_retval	td_uretoff.tdu_retval
+	u_int		td_cowgen;	/* (k) Generation of COW pointers. */
 	struct callout	td_slpcallout;	/* (h) Callout for sleep. */
 	struct trapframe *td_frame;	/* (k) */
 	struct vm_object *td_kstack_obj;/* (a) Kstack object. */
@@ -533,6 +534,7 @@ struct proc {
 	pid_t		p_oppid;	/* (c + e) Save ppid in ptrace. XXX */
 	struct vmspace	*p_vmspace;	/* (b) Address space. */
 	u_int		p_swtick;	/* (c) Tick when swapped in or out. */
+	u_int		p_cowgen;	/* (c) Generation of COW pointers. */
 	struct itimerval p_realtimer;	/* (c) Alarm timer. */
 	struct rusage	p_ru;		/* (a) Exit information. */
 	struct rusage_ext p_rux;	/* (cu) Internal resource usage. */
@@ -833,6 +835,11 @@ extern pid_t pid_max;
 	KASSERT((p)->p_lock == 0, ("process held"));			\
 } while (0)
 
+#define	PROC_UPDATE_COW(p) do {						\
+	PROC_LOCK_ASSERT((p), MA_OWNED);				\
+	(p)->p_cowgen++;						\
+} while (0)
+
 /* Check whether a thread is safe to be swapped out. */
 #define	thread_safetoswapout(td)	((td)->td_flags & TDF_CANSWAP)
 
@@ -977,6 +984,10 @@ void	cpu_thread_swapin(struct thread *);
 void	cpu_thread_swapout(struct thread *);
 struct	thread *thread_alloc(int pages);
 int	thread_alloc_stack(struct thread *, int pages);
+void	thread_cow_get_proc(struct thread *newtd, struct proc *p);
+void	thread_cow_get(struct thread *newtd, struct thread *td);
+void	thread_cow_free(struct thread *td);
+void	thread_cow_update(struct thread *td);
 void	thread_exit(void) __dead2;
 void	thread_free(struct thread *td);
 void	thread_link(struct thread *td, struct proc *p);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506101044.t5AAi0fn028782>