diff options
author | kib <kib@FreeBSD.org> | 2007-11-05 11:36:16 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2007-11-05 11:36:16 +0000 |
commit | 9ae733819b7cdf0eef51ba1b18d39feb136a9dbf (patch) | |
tree | cccec36134d2cab5ce1eabb67dcaab5981e9beb0 /sys/kern/kern_thread.c | |
parent | f3f033b9b90ea07350fbe7483af3d9636cb31d1d (diff) | |
download | FreeBSD-src-9ae733819b7cdf0eef51ba1b18d39feb136a9dbf.zip FreeBSD-src-9ae733819b7cdf0eef51ba1b18d39feb136a9dbf.tar.gz |
Fix for the panic("vm_thread_new: kstack allocation failed") and
silent NULL pointer dereference in the i386 and sparc64 pmap_pinit()
when the kmem_alloc_nofault() failed to allocate address space. Both
functions now return error instead of panicing or dereferencing NULL.
As consequence, vmspace_exec() and vmspace_unshare() returns the errno
int. struct vmspace arg was added to vm_forkproc() to avoid dealing
with failed allocation when most of the fork1() job is already done.
The kernel stack for the thread is now set up in the thread_alloc(),
that itself may return NULL. Also, allocation of the first process
thread is performed in the fork1() to properly deal with stack
allocation failure. proc_linkup() is separated into proc_linkup()
called from fork1(), and proc_linkup0(), that is used to set up the
kernel process (was known as swapper).
In collaboration with: Peter Holm
Reviewed by: jhb
Diffstat (limited to 'sys/kern/kern_thread.c')
-rw-r--r-- | sys/kern/kern_thread.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 2a28823..cde764f 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -181,13 +181,12 @@ thread_init(void *mem, int size, int flags) td = (struct thread *)mem; - vm_thread_new(td, 0); - cpu_thread_setup(td); td->td_sleepqueue = sleepq_alloc(); td->td_turnstile = turnstile_alloc(); td->td_sched = (struct td_sched *)&td[1]; sched_newthread(td); umtx_thread_init(td); + td->td_kstack = 0; return (0); } @@ -203,7 +202,6 @@ thread_fini(void *mem, int size) turnstile_free(td->td_turnstile); sleepq_free(td->td_sleepqueue); umtx_thread_fini(td); - vm_thread_dispose(td); } /* @@ -215,10 +213,16 @@ thread_fini(void *mem, int size) * proc_init() */ void +proc_linkup0(struct proc *p, struct thread *td) +{ + TAILQ_INIT(&p->p_threads); /* all threads in proc */ + proc_linkup(p, td); +} + +void proc_linkup(struct proc *p, struct thread *td) { - TAILQ_INIT(&p->p_threads); /* all threads in proc */ #ifdef KSE TAILQ_INIT(&p->p_upcalls); /* upcall list */ #endif @@ -310,9 +314,18 @@ thread_reap(void) struct thread * thread_alloc(void) { + struct thread *td; thread_reap(); /* check if any zombies to get */ - return (uma_zalloc(thread_zone, M_WAITOK)); + + td = (struct thread *)uma_zalloc(thread_zone, M_WAITOK); + KASSERT(td->td_kstack == 0, ("thread_alloc got thread with kstack")); + if (!vm_thread_new(td, 0)) { + uma_zfree(thread_zone, td); + return (NULL); + } + cpu_thread_setup(td); + return (td); } @@ -324,6 +337,10 @@ thread_free(struct thread *td) { cpu_thread_clean(td); + if (td->td_altkstack != 0) + vm_thread_dispose_altkstack(td); + if (td->td_kstack != 0) + vm_thread_dispose(td); uma_zfree(thread_zone, td); } |