lwproc.c revision 1.42 1 /* $NetBSD: lwproc.c,v 1.42 2019/05/17 03:34:26 ozaki-r Exp $ */
2
3 /*
4 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #define RUMP__CURLWP_PRIVATE
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: lwproc.c,v 1.42 2019/05/17 03:34:26 ozaki-r Exp $");
32
33 #include <sys/param.h>
34 #include <sys/atomic.h>
35 #include <sys/filedesc.h>
36 #include <sys/fstrans.h>
37 #include <sys/kauth.h>
38 #include <sys/kmem.h>
39 #include <sys/lwp.h>
40 #include <sys/ktrace.h>
41 #include <sys/pool.h>
42 #include <sys/proc.h>
43 #include <sys/queue.h>
44 #include <sys/resourcevar.h>
45 #include <sys/uidinfo.h>
46 #include <sys/psref.h>
47
48 #include <rump-sys/kern.h>
49
50 #include <rump/rumpuser.h>
51
52 #include "rump_curlwp.h"
53
54 struct lwp lwp0 = {
55 .l_lid = 1,
56 .l_proc = &proc0,
57 .l_fd = &filedesc0,
58 };
59 struct lwplist alllwp = LIST_HEAD_INITIALIZER(alllwp);
60
61 u_int nprocs = 1;
62
63 struct emul *emul_default = &emul_netbsd;
64
65 void
66 lwp_unsleep(lwp_t *l, bool cleanup)
67 {
68
69 KASSERT(mutex_owned(l->l_mutex));
70
71 (*l->l_syncobj->sobj_unsleep)(l, cleanup);
72 }
73
74 /*
75 * Look up a live LWP within the specified process.
76 *
77 * Must be called with p->p_lock held.
78 */
79 struct lwp *
80 lwp_find(struct proc *p, lwpid_t id)
81 {
82 struct lwp *l;
83
84 KASSERT(mutex_owned(p->p_lock));
85
86 LIST_FOREACH(l, &p->p_lwps, l_sibling) {
87 if (l->l_lid == id)
88 break;
89 }
90
91 /*
92 * No need to lock - all of these conditions will
93 * be visible with the process level mutex held.
94 */
95 if (l != NULL && (l->l_stat == LSIDL || l->l_stat == LSZOMB))
96 l = NULL;
97
98 return l;
99 }
100
101 void
102 lwp_update_creds(struct lwp *l)
103 {
104 struct proc *p;
105 kauth_cred_t oldcred;
106
107 p = l->l_proc;
108 oldcred = l->l_cred;
109 l->l_prflag &= ~LPR_CRMOD;
110
111 mutex_enter(p->p_lock);
112 kauth_cred_hold(p->p_cred);
113 l->l_cred = p->p_cred;
114 mutex_exit(p->p_lock);
115
116 if (oldcred != NULL)
117 kauth_cred_free(oldcred);
118 }
119
120 void
121 rump_lwproc_init(void)
122 {
123
124 lwproc_curlwpop(RUMPUSER_LWP_CREATE, &lwp0);
125 }
126
127 struct lwp *
128 rump_lwproc_curlwp_hypercall(void)
129 {
130
131 return rumpuser_curlwp();
132 }
133
134 void
135 rump_lwproc_curlwp_set(struct lwp *l)
136 {
137
138 KASSERT(curlwp == NULL);
139 lwproc_curlwpop(RUMPUSER_LWP_SET, l);
140 }
141
142 void
143 rump_lwproc_curlwp_clear(struct lwp *l)
144 {
145
146 KASSERT(l == curlwp);
147 lwproc_curlwpop(RUMPUSER_LWP_CLEAR, l);
148 }
149
150 static void
151 lwproc_proc_free(struct proc *p)
152 {
153 kauth_cred_t cred;
154 struct proc *child;
155
156 KASSERT(p->p_stat == SDYING || p->p_stat == SDEAD);
157
158 #ifdef KTRACE
159 if (p->p_tracep) {
160 mutex_enter(&ktrace_lock);
161 ktrderef(p);
162 mutex_exit(&ktrace_lock);
163 }
164 #endif
165
166 mutex_enter(proc_lock);
167
168 /* childranee eunt initus */
169 while ((child = LIST_FIRST(&p->p_children)) != NULL) {
170 LIST_REMOVE(child, p_sibling);
171 child->p_pptr = initproc;
172 child->p_ppid = 1;
173 LIST_INSERT_HEAD(&initproc->p_children, child, p_sibling);
174 }
175
176 KASSERT(p->p_nlwps == 0);
177 KASSERT(LIST_EMPTY(&p->p_lwps));
178
179 LIST_REMOVE(p, p_list);
180 LIST_REMOVE(p, p_sibling);
181 proc_free_pid(p->p_pid); /* decrements nprocs */
182 proc_leavepgrp(p); /* releases proc_lock */
183
184 cred = p->p_cred;
185 chgproccnt(kauth_cred_getuid(cred), -1);
186 rump_proc_vfs_release(p);
187
188 doexithooks(p);
189 lim_free(p->p_limit);
190 pstatsfree(p->p_stats);
191 kauth_cred_free(p->p_cred);
192 proc_finispecific(p);
193
194 mutex_obj_free(p->p_lock);
195 mutex_destroy(&p->p_stmutex);
196 mutex_destroy(&p->p_auxlock);
197 rw_destroy(&p->p_reflock);
198 cv_destroy(&p->p_waitcv);
199 cv_destroy(&p->p_lwpcv);
200
201 /* non-local vmspaces are not shared */
202 if (!RUMP_LOCALPROC_P(p)) {
203 struct rump_spctl *ctl = (struct rump_spctl *)p->p_vmspace;
204 KASSERT(p->p_vmspace->vm_refcnt == 1);
205 kmem_free(ctl, sizeof(*ctl));
206 }
207
208 proc_free_mem(p);
209 }
210
211 /*
212 * Allocate a new process. Mostly mimic fork by
213 * copying the properties of the parent. However, there are some
214 * differences.
215 *
216 * Switch to the new lwp and return a pointer to it.
217 */
218 static struct proc *
219 lwproc_newproc(struct proc *parent, struct vmspace *vm, int flags)
220 {
221 uid_t uid = kauth_cred_getuid(parent->p_cred);
222 struct proc *p;
223
224 /* maxproc not enforced */
225 atomic_inc_uint(&nprocs);
226
227 /* allocate process */
228 p = proc_alloc();
229 memset(&p->p_startzero, 0,
230 offsetof(struct proc, p_endzero)
231 - offsetof(struct proc, p_startzero));
232 memcpy(&p->p_startcopy, &parent->p_startcopy,
233 offsetof(struct proc, p_endcopy)
234 - offsetof(struct proc, p_startcopy));
235
236 /* some other garbage we need to zero */
237 p->p_sigacts = NULL;
238 p->p_aio = NULL;
239 p->p_dtrace = NULL;
240 p->p_mqueue_cnt = p->p_exitsig = 0;
241 p->p_flag = p->p_sflag = p->p_slflag = p->p_lflag = p->p_stflag = 0;
242 p->p_trace_enabled = 0;
243 p->p_xsig = p->p_xexit = p->p_acflag = 0;
244 p->p_stackbase = 0;
245
246 p->p_stats = pstatscopy(parent->p_stats);
247
248 p->p_vmspace = vm;
249 p->p_emul = emul_default;
250 #ifdef __HAVE_SYSCALL_INTERN
251 p->p_emul->e_syscall_intern(p);
252 #endif
253 if (*parent->p_comm)
254 strcpy(p->p_comm, parent->p_comm);
255 else
256 strcpy(p->p_comm, "rumproc");
257
258 if ((flags & RUMP_RFCFDG) == 0)
259 KASSERT(parent == curproc);
260 if (flags & RUMP_RFFDG)
261 p->p_fd = fd_copy();
262 else if (flags & RUMP_RFCFDG)
263 p->p_fd = fd_init(NULL);
264 else
265 fd_share(p);
266
267 lim_addref(parent->p_limit);
268 p->p_limit = parent->p_limit;
269
270 LIST_INIT(&p->p_lwps);
271 LIST_INIT(&p->p_children);
272
273 p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
274 mutex_init(&p->p_stmutex, MUTEX_DEFAULT, IPL_HIGH);
275 mutex_init(&p->p_auxlock, MUTEX_DEFAULT, IPL_NONE);
276 rw_init(&p->p_reflock);
277 cv_init(&p->p_waitcv, "pwait");
278 cv_init(&p->p_lwpcv, "plwp");
279
280 p->p_pptr = parent;
281 p->p_ppid = parent->p_pid;
282 p->p_stat = SACTIVE;
283
284 kauth_proc_fork(parent, p);
285
286 /* initialize cwd in rump kernels with vfs */
287 rump_proc_vfs_init(p);
288
289 chgproccnt(uid, 1); /* not enforced */
290
291 /* publish proc various proc lists */
292 mutex_enter(proc_lock);
293 LIST_INSERT_HEAD(&allproc, p, p_list);
294 LIST_INSERT_HEAD(&parent->p_children, p, p_sibling);
295 LIST_INSERT_AFTER(parent, p, p_pglist);
296 mutex_exit(proc_lock);
297
298 return p;
299 }
300
301 static void
302 lwproc_freelwp(struct lwp *l)
303 {
304 struct proc *p;
305
306 p = l->l_proc;
307 mutex_enter(p->p_lock);
308
309 KASSERT(l->l_flag & LW_WEXIT);
310 KASSERT(l->l_refcnt == 0);
311
312 /* ok, zero references, continue with nuke */
313 LIST_REMOVE(l, l_sibling);
314 KASSERT(p->p_nlwps >= 1);
315 if (--p->p_nlwps == 0) {
316 KASSERT(p != &proc0);
317 p->p_stat = SDEAD;
318 } else {
319 chglwpcnt(kauth_cred_getuid(p->p_cred), -1);
320 }
321 cv_broadcast(&p->p_lwpcv); /* nobody sleeps on this in a rump kernel? */
322 kauth_cred_free(l->l_cred);
323 mutex_exit(p->p_lock);
324
325 mutex_enter(proc_lock);
326 LIST_REMOVE(l, l_list);
327 mutex_exit(proc_lock);
328
329 if (l->l_name)
330 kmem_free(l->l_name, MAXCOMLEN);
331 fstrans_lwp_dtor(l);
332 lwp_finispecific(l);
333
334 lwproc_curlwpop(RUMPUSER_LWP_DESTROY, l);
335 membar_exit();
336 kmem_free(l, sizeof(*l));
337
338 if (p->p_stat == SDEAD)
339 lwproc_proc_free(p);
340 }
341
342 extern kmutex_t unruntime_lock;
343
344 /*
345 * called with p_lock held, releases lock before return
346 */
347 static void
348 lwproc_makelwp(struct proc *p, struct lwp *l, bool doswitch, bool procmake)
349 {
350
351 /*
352 * Account the new lwp to the owner of the process.
353 * For some reason, NetBSD doesn't count the first lwp
354 * in a process as a lwp, so skip that.
355 */
356 if (p->p_nlwps++) {
357 chglwpcnt(kauth_cred_getuid(p->p_cred), 1);
358 }
359
360 l->l_refcnt = 1;
361 l->l_proc = p;
362
363 l->l_lid = p->p_nlwpid++;
364 LIST_INSERT_HEAD(&p->p_lwps, l, l_sibling);
365
366 l->l_fd = p->p_fd;
367 l->l_cpu = &rump_bootcpu;
368 l->l_target_cpu = &rump_bootcpu; /* Initial target CPU always same */
369 l->l_stat = LSRUN;
370 l->l_mutex = &unruntime_lock;
371 TAILQ_INIT(&l->l_ld_locks);
372 mutex_exit(p->p_lock);
373
374 lwp_update_creds(l);
375 lwp_initspecific(l);
376 PSREF_DEBUG_INIT_LWP(l);
377
378 membar_enter();
379 lwproc_curlwpop(RUMPUSER_LWP_CREATE, l);
380 if (doswitch) {
381 rump_lwproc_switch(l);
382 }
383
384 /* filedesc already has refcount 1 when process is created */
385 if (!procmake) {
386 fd_hold(l);
387 }
388
389 mutex_enter(proc_lock);
390 LIST_INSERT_HEAD(&alllwp, l, l_list);
391 mutex_exit(proc_lock);
392 }
393
394 struct lwp *
395 rump__lwproc_alloclwp(struct proc *p)
396 {
397 struct lwp *l;
398 bool newproc = false;
399
400 if (p == NULL) {
401 p = lwproc_newproc(&proc0, rump_vmspace_local, RUMP_RFCFDG);
402 newproc = true;
403 }
404
405 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
406
407 mutex_enter(p->p_lock);
408 KASSERT((p->p_sflag & PS_RUMP_LWPEXIT) == 0);
409 lwproc_makelwp(p, l, false, newproc);
410
411 return l;
412 }
413
414 int
415 rump_lwproc_newlwp(pid_t pid)
416 {
417 struct proc *p;
418 struct lwp *l;
419
420 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
421 mutex_enter(proc_lock);
422 p = proc_find_raw(pid);
423 if (p == NULL) {
424 mutex_exit(proc_lock);
425 kmem_free(l, sizeof(*l));
426 return ESRCH;
427 }
428 mutex_enter(p->p_lock);
429 if (p->p_sflag & PS_RUMP_LWPEXIT) {
430 mutex_exit(proc_lock);
431 mutex_exit(p->p_lock);
432 kmem_free(l, sizeof(*l));
433 return EBUSY;
434 }
435 mutex_exit(proc_lock);
436 lwproc_makelwp(p, l, true, false);
437
438 return 0;
439 }
440
441 int
442 rump_lwproc_rfork_vmspace(struct vmspace *vm, int flags)
443 {
444 struct proc *p;
445 struct lwp *l;
446
447 if (flags & ~(RUMP_RFFDG|RUMP_RFCFDG) ||
448 (~flags & (RUMP_RFFDG|RUMP_RFCFDG)) == 0)
449 return EINVAL;
450
451 p = lwproc_newproc(curproc, vm, flags);
452 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
453 mutex_enter(p->p_lock);
454 KASSERT((p->p_sflag & PS_RUMP_LWPEXIT) == 0);
455 lwproc_makelwp(p, l, true, true);
456
457 return 0;
458 }
459
460 int
461 rump_lwproc_rfork(int flags)
462 {
463
464 return rump_lwproc_rfork_vmspace(rump_vmspace_local, flags);
465 }
466
467 /*
468 * Switch to a new process/thread. Release previous one if
469 * deemed to be exiting. This is considered a slow path for
470 * rump kernel entry.
471 */
472 void
473 rump_lwproc_switch(struct lwp *newlwp)
474 {
475 struct lwp *l = curlwp;
476
477 KASSERT(!(l->l_flag & LW_WEXIT) || newlwp);
478
479 if (__predict_false(newlwp && (newlwp->l_pflag & LP_RUNNING)))
480 panic("lwp %p (%d:%d) already running",
481 newlwp, newlwp->l_proc->p_pid, newlwp->l_lid);
482
483 if (newlwp == NULL) {
484 l->l_pflag &= ~LP_RUNNING;
485 l->l_flag |= LW_RUMP_CLEAR;
486 return;
487 }
488
489 /* fd_free() must be called from curlwp context. talk about ugh */
490 if (l->l_flag & LW_WEXIT) {
491 fd_free();
492 }
493
494 KERNEL_UNLOCK_ALL(NULL, &l->l_biglocks);
495 lwproc_curlwpop(RUMPUSER_LWP_CLEAR, l);
496
497 newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu;
498 newlwp->l_mutex = l->l_mutex;
499 newlwp->l_pflag |= LP_RUNNING;
500
501 lwproc_curlwpop(RUMPUSER_LWP_SET, newlwp);
502 curcpu()->ci_curlwp = newlwp;
503 KERNEL_LOCK(newlwp->l_biglocks, NULL);
504
505 /*
506 * Check if the thread should get a signal. This is
507 * mostly to satisfy the "record" rump sigmodel.
508 */
509 mutex_enter(newlwp->l_proc->p_lock);
510 if (sigispending(newlwp, 0)) {
511 newlwp->l_flag |= LW_PENDSIG;
512 }
513 mutex_exit(newlwp->l_proc->p_lock);
514
515 l->l_mutex = &unruntime_lock;
516 l->l_pflag &= ~LP_RUNNING;
517 l->l_flag &= ~LW_PENDSIG;
518 l->l_stat = LSRUN;
519
520 if (l->l_flag & LW_WEXIT) {
521 lwproc_freelwp(l);
522 }
523 }
524
525 /*
526 * Mark the current thread to be released upon return from
527 * kernel.
528 */
529 void
530 rump_lwproc_releaselwp(void)
531 {
532 struct lwp *l = curlwp;
533
534 if (l->l_refcnt == 0 || l->l_flag & LW_WEXIT)
535 panic("releasing non-pertinent lwp");
536
537 rump__lwproc_lwprele();
538 KASSERT(l->l_refcnt == 0 && (l->l_flag & LW_WEXIT));
539 }
540
541 /*
542 * In-kernel routines used to add and remove references for the
543 * current thread. The main purpose is to make it possible for
544 * implicit threads to persist over scheduling operations in
545 * rump kernel drivers. Note that we don't need p_lock in a
546 * rump kernel, since we do refcounting only for curlwp.
547 */
548 void
549 rump__lwproc_lwphold(void)
550 {
551 struct lwp *l = curlwp;
552
553 l->l_refcnt++;
554 l->l_flag &= ~LW_WEXIT;
555 }
556
557 void
558 rump__lwproc_lwprele(void)
559 {
560 struct lwp *l = curlwp;
561
562 l->l_refcnt--;
563 if (l->l_refcnt == 0)
564 l->l_flag |= LW_WEXIT;
565 }
566
567 struct lwp *
568 rump_lwproc_curlwp(void)
569 {
570 struct lwp *l = curlwp;
571
572 if (l->l_flag & LW_WEXIT)
573 return NULL;
574 return l;
575 }
576
577 /* this interface is under construction (like the proverbial 90's web page) */
578 int rump_i_know_what_i_am_doing_with_sysents = 0;
579 void
580 rump_lwproc_sysent_usenative()
581 {
582
583 if (!rump_i_know_what_i_am_doing_with_sysents)
584 panic("don't use rump_lwproc_sysent_usenative()");
585 curproc->p_emul = &emul_netbsd;
586 }
587