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.
This commit is contained in:
parent
8bd0e17595
commit
4ea6a9a28f
@ -257,8 +257,8 @@ trap(struct trapframe *frame)
|
|||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
td->td_frame = frame;
|
td->td_frame = frame;
|
||||||
addr = frame->tf_rip;
|
addr = frame->tf_rip;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case T_PRIVINFLT: /* privileged instruction fault */
|
case T_PRIVINFLT: /* privileged instruction fault */
|
||||||
|
@ -395,8 +395,8 @@ abort_handler(struct trapframe *tf, int prefetch)
|
|||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
if (usermode) {
|
if (usermode) {
|
||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke the appropriate handler, if necessary. */
|
/* Invoke the appropriate handler, if necessary. */
|
||||||
|
@ -214,8 +214,8 @@ abort_handler(struct trapframe *tf, int type)
|
|||||||
if (user) {
|
if (user) {
|
||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
td->td_frame = tf;
|
td->td_frame = tf;
|
||||||
if (td->td_ucred != td->td_proc->p_ucred)
|
if (td->td_cowgen != td->td_proc->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
|
|
||||||
}
|
}
|
||||||
/* Grab the current pcb */
|
/* Grab the current pcb */
|
||||||
@ -644,8 +644,8 @@ prefetch_abort_handler(struct trapframe *tf)
|
|||||||
|
|
||||||
if (TRAP_USERMODE(tf)) {
|
if (TRAP_USERMODE(tf)) {
|
||||||
td->td_frame = tf;
|
td->td_frame = tf;
|
||||||
if (td->td_ucred != td->td_proc->p_ucred)
|
if (td->td_cowgen != td->td_proc->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
}
|
}
|
||||||
fault_pc = tf->tf_pc;
|
fault_pc = tf->tf_pc;
|
||||||
if (td->td_md.md_spinlock_count == 0) {
|
if (td->td_md.md_spinlock_count == 0) {
|
||||||
|
@ -306,8 +306,8 @@ trap(struct trapframe *frame)
|
|||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
td->td_frame = frame;
|
td->td_frame = frame;
|
||||||
addr = frame->tf_eip;
|
addr = frame->tf_eip;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case T_PRIVINFLT: /* privileged instruction fault */
|
case T_PRIVINFLT: /* privileged instruction fault */
|
||||||
|
@ -523,8 +523,6 @@ proc0_init(void *dummy __unused)
|
|||||||
#ifdef MAC
|
#ifdef MAC
|
||||||
mac_cred_create_swapper(newcred);
|
mac_cred_create_swapper(newcred);
|
||||||
#endif
|
#endif
|
||||||
td->td_ucred = crhold(newcred);
|
|
||||||
|
|
||||||
/* Create sigacts. */
|
/* Create sigacts. */
|
||||||
p->p_sigacts = sigacts_alloc();
|
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_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = pageablemem;
|
||||||
p->p_cpulimit = RLIM_INFINITY;
|
p->p_cpulimit = RLIM_INFINITY;
|
||||||
|
|
||||||
|
PROC_LOCK(p);
|
||||||
|
thread_cow_get_proc(td, p);
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
|
||||||
/* Initialize resource accounting structures. */
|
/* Initialize resource accounting structures. */
|
||||||
racct_create(&p->p_racct);
|
racct_create(&p->p_racct);
|
||||||
|
|
||||||
@ -843,10 +845,10 @@ create_init(const void *udata __unused)
|
|||||||
audit_cred_proc1(newcred);
|
audit_cred_proc1(newcred);
|
||||||
#endif
|
#endif
|
||||||
proc_set_cred(initproc, newcred);
|
proc_set_cred(initproc, newcred);
|
||||||
|
cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
|
||||||
PROC_UNLOCK(initproc);
|
PROC_UNLOCK(initproc);
|
||||||
sx_xunlock(&proctree_lock);
|
sx_xunlock(&proctree_lock);
|
||||||
crfree(oldcred);
|
crfree(oldcred);
|
||||||
cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
|
|
||||||
cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
|
cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
|
||||||
}
|
}
|
||||||
SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);
|
SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);
|
||||||
|
@ -496,7 +496,6 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
|
|||||||
p2->p_swtick = ticks;
|
p2->p_swtick = ticks;
|
||||||
if (p1->p_flag & P_PROFIL)
|
if (p1->p_flag & P_PROFIL)
|
||||||
startprofclock(p2);
|
startprofclock(p2);
|
||||||
td2->td_ucred = crhold(p2->p_ucred);
|
|
||||||
|
|
||||||
if (flags & RFSIGSHARE) {
|
if (flags & RFSIGSHARE) {
|
||||||
p2->p_sigacts = sigacts_hold(p1->p_sigacts);
|
p2->p_sigacts = sigacts_hold(p1->p_sigacts);
|
||||||
@ -526,6 +525,8 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
|
|||||||
*/
|
*/
|
||||||
lim_fork(p1, p2);
|
lim_fork(p1, p2);
|
||||||
|
|
||||||
|
thread_cow_get_proc(td2, p2);
|
||||||
|
|
||||||
pstats_fork(p1->p_stats, p2->p_stats);
|
pstats_fork(p1->p_stats, p2->p_stats);
|
||||||
|
|
||||||
PROC_UNLOCK(p1);
|
PROC_UNLOCK(p1);
|
||||||
|
@ -289,7 +289,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p,
|
|||||||
cpu_set_fork_handler(newtd, func, arg);
|
cpu_set_fork_handler(newtd, func, arg);
|
||||||
|
|
||||||
newtd->td_pflags |= TDP_KTHREAD;
|
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 */
|
/* this code almost the same as create_thread() in kern_thr.c */
|
||||||
p->p_flag |= P_HADTHREADS;
|
p->p_flag |= P_HADTHREADS;
|
||||||
|
@ -1946,9 +1946,8 @@ cred_update_thread(struct thread *td)
|
|||||||
|
|
||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
cred = td->td_ucred;
|
cred = td->td_ucred;
|
||||||
PROC_LOCK(p);
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||||
td->td_ucred = crhold(p->p_ucred);
|
td->td_ucred = crhold(p->p_ucred);
|
||||||
PROC_UNLOCK(p);
|
|
||||||
if (cred != NULL)
|
if (cred != NULL)
|
||||||
crfree(cred);
|
crfree(cred);
|
||||||
}
|
}
|
||||||
@ -1987,6 +1986,8 @@ proc_set_cred(struct proc *p, struct ucred *newcred)
|
|||||||
|
|
||||||
oldcred = p->p_ucred;
|
oldcred = p->p_ucred;
|
||||||
p->p_ucred = newcred;
|
p->p_ucred = newcred;
|
||||||
|
if (newcred != NULL)
|
||||||
|
PROC_UPDATE_COW(p);
|
||||||
return (oldcred);
|
return (oldcred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
#include <sys/sx.h>
|
#include <sys/sx.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/sysent.h>
|
#include <sys/sysent.h>
|
||||||
|
@ -220,13 +220,13 @@ create_thread(struct thread *td, mcontext_t *ctx,
|
|||||||
bcopy(&td->td_startcopy, &newtd->td_startcopy,
|
bcopy(&td->td_startcopy, &newtd->td_startcopy,
|
||||||
__rangeof(struct thread, td_startcopy, td_endcopy));
|
__rangeof(struct thread, td_startcopy, td_endcopy));
|
||||||
newtd->td_proc = td->td_proc;
|
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 */
|
if (ctx != NULL) { /* old way to set user context */
|
||||||
error = set_mcontext(newtd, ctx);
|
error = set_mcontext(newtd, ctx);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
thread_cow_free(newtd);
|
||||||
thread_free(newtd);
|
thread_free(newtd);
|
||||||
crfree(td->td_ucred);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -238,8 +238,8 @@ create_thread(struct thread *td, mcontext_t *ctx,
|
|||||||
/* Setup user TLS address and TLS pointer register. */
|
/* Setup user TLS address and TLS pointer register. */
|
||||||
error = cpu_set_user_tls(newtd, tls_base);
|
error = cpu_set_user_tls(newtd, tls_base);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
thread_cow_free(newtd);
|
||||||
thread_free(newtd);
|
thread_free(newtd);
|
||||||
crfree(td->td_ucred);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,8 +327,7 @@ thread_reap(void)
|
|||||||
mtx_unlock_spin(&zombie_lock);
|
mtx_unlock_spin(&zombie_lock);
|
||||||
while (td_first) {
|
while (td_first) {
|
||||||
td_next = TAILQ_NEXT(td_first, td_slpq);
|
td_next = TAILQ_NEXT(td_first, td_slpq);
|
||||||
if (td_first->td_ucred)
|
thread_cow_free(td_first);
|
||||||
crfree(td_first->td_ucred);
|
|
||||||
thread_free(td_first);
|
thread_free(td_first);
|
||||||
td_first = td_next;
|
td_first = td_next;
|
||||||
}
|
}
|
||||||
@ -384,6 +383,44 @@ thread_free(struct thread *td)
|
|||||||
uma_zfree(thread_zone, 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.
|
* Discard the current thread and exit from its context.
|
||||||
* Always called with scheduler locked.
|
* Always called with scheduler locked.
|
||||||
@ -521,7 +558,7 @@ thread_wait(struct proc *p)
|
|||||||
cpuset_rel(td->td_cpuset);
|
cpuset_rel(td->td_cpuset);
|
||||||
td->td_cpuset = NULL;
|
td->td_cpuset = NULL;
|
||||||
cpu_thread_clean(td);
|
cpu_thread_clean(td);
|
||||||
crfree(td->td_ucred);
|
thread_cow_free(td);
|
||||||
thread_reap(); /* check for zombie threads etc. */
|
thread_reap(); /* check for zombie threads etc. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +61,8 @@ syscallenter(struct thread *td, struct syscall_args *sa)
|
|||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
|
|
||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
if (p->p_flag & P_TRACED) {
|
if (p->p_flag & P_TRACED) {
|
||||||
traced = 1;
|
traced = 1;
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
|
@ -220,8 +220,8 @@ ast(struct trapframe *framep)
|
|||||||
thread_unlock(td);
|
thread_unlock(td);
|
||||||
PCPU_INC(cnt.v_trap);
|
PCPU_INC(cnt.v_trap);
|
||||||
|
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
if (td->td_pflags & TDP_OWEUPC && p->p_flag & P_PROFIL) {
|
if (td->td_pflags & TDP_OWEUPC && p->p_flag & P_PROFIL) {
|
||||||
addupc_task(td, td->td_profil_addr, td->td_profil_ticks);
|
addupc_task(td, td->td_profil_addr, td->td_profil_ticks);
|
||||||
td->td_profil_ticks = 0;
|
td->td_profil_ticks = 0;
|
||||||
|
@ -196,8 +196,8 @@ trap(struct trapframe *frame)
|
|||||||
if (user) {
|
if (user) {
|
||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
td->td_frame = frame;
|
td->td_frame = frame;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
|
|
||||||
/* User Mode Traps */
|
/* User Mode Traps */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -277,8 +277,8 @@ trap(struct trapframe *tf)
|
|||||||
td->td_pticks = 0;
|
td->td_pticks = 0;
|
||||||
td->td_frame = tf;
|
td->td_frame = tf;
|
||||||
addr = tf->tf_tpc;
|
addr = tf->tf_tpc;
|
||||||
if (td->td_ucred != p->p_ucred)
|
if (td->td_cowgen != p->p_cowgen)
|
||||||
cred_update_thread(td);
|
thread_cow_update(td);
|
||||||
|
|
||||||
switch (tf->tf_type) {
|
switch (tf->tf_type) {
|
||||||
case T_DATA_MISS:
|
case T_DATA_MISS:
|
||||||
|
@ -308,6 +308,7 @@ struct thread {
|
|||||||
off_t tdu_off;
|
off_t tdu_off;
|
||||||
} td_uretoff; /* (k) Syscall aux returns. */
|
} td_uretoff; /* (k) Syscall aux returns. */
|
||||||
#define td_retval td_uretoff.tdu_retval
|
#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 callout td_slpcallout; /* (h) Callout for sleep. */
|
||||||
struct trapframe *td_frame; /* (k) */
|
struct trapframe *td_frame; /* (k) */
|
||||||
struct vm_object *td_kstack_obj;/* (a) Kstack object. */
|
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 */
|
pid_t p_oppid; /* (c + e) Save ppid in ptrace. XXX */
|
||||||
struct vmspace *p_vmspace; /* (b) Address space. */
|
struct vmspace *p_vmspace; /* (b) Address space. */
|
||||||
u_int p_swtick; /* (c) Tick when swapped in or out. */
|
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 itimerval p_realtimer; /* (c) Alarm timer. */
|
||||||
struct rusage p_ru; /* (a) Exit information. */
|
struct rusage p_ru; /* (a) Exit information. */
|
||||||
struct rusage_ext p_rux; /* (cu) Internal resource usage. */
|
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")); \
|
KASSERT((p)->p_lock == 0, ("process held")); \
|
||||||
} while (0)
|
} 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. */
|
/* Check whether a thread is safe to be swapped out. */
|
||||||
#define thread_safetoswapout(td) ((td)->td_flags & TDF_CANSWAP)
|
#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 *);
|
void cpu_thread_swapout(struct thread *);
|
||||||
struct thread *thread_alloc(int pages);
|
struct thread *thread_alloc(int pages);
|
||||||
int thread_alloc_stack(struct thread *, 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_exit(void) __dead2;
|
||||||
void thread_free(struct thread *td);
|
void thread_free(struct thread *td);
|
||||||
void thread_link(struct thread *td, struct proc *p);
|
void thread_link(struct thread *td, struct proc *p);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user