summaryrefslogtreecommitdiff
path: root/sys/compat/linux/common/linux_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/common/linux_exec.c')
-rw-r--r--sys/compat/linux/common/linux_exec.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/sys/compat/linux/common/linux_exec.c b/sys/compat/linux/common/linux_exec.c
index e286cd0bf99..2f4d1f50adf 100644
--- a/sys/compat/linux/common/linux_exec.c
+++ b/sys/compat/linux/common/linux_exec.c
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_exec.c,v 1.70 2003/12/20 19:01:30 fvdl Exp $ */
+/* $NetBSD: linux_exec.c,v 1.71 2004/08/08 09:40:50 jdolecek Exp $ */
/*-
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.70 2003/12/20 19:01:30 fvdl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.71 2004/08/08 09:40:50 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -75,9 +75,9 @@ extern const char * const linux_syscallnames[];
extern char linux_sigcode[], linux_esigcode[];
static void linux_e_proc_exec __P((struct proc *, struct exec_package *));
-static void linux_e_proc_fork __P((struct proc *, struct proc *));
+static void linux_e_proc_fork __P((struct proc *, struct proc *, int));
static void linux_e_proc_exit __P((struct proc *));
-static void linux_e_proc_init __P((struct proc *, struct vmspace *));
+static void linux_e_proc_init __P((struct proc *, struct proc *, int));
/*
* Execve(2). Just check the alternate emulation path, and pass it on
@@ -147,25 +147,54 @@ const struct emul emul_linux = {
};
static void
-linux_e_proc_init(p, vmspace)
- struct proc *p;
- struct vmspace *vmspace;
+linux_e_proc_init(p, parent, forkflags)
+ struct proc *p, *parent;
+ int forkflags;
{
- if (!p->p_emuldata) {
+ struct linux_emuldata *e = p->p_emuldata;
+ struct linux_emuldata_shared *s;
+
+ if (!e) {
/* allocate new Linux emuldata */
- MALLOC(p->p_emuldata, void *, sizeof(struct linux_emuldata),
+ MALLOC(e, void *, sizeof(struct linux_emuldata),
M_EMULDATA, M_WAITOK);
+ } else {
+ e->s->refs++;
+ if (e->s->refs == 0)
+ FREE(e->s, M_EMULDATA);
}
- memset(p->p_emuldata, '\0', sizeof(struct linux_emuldata));
-
- /* Set the process idea of the break to the real value */
- ((struct linux_emuldata*)(p->p_emuldata))->p_break =
- vmspace->vm_daddr + ctob(vmspace->vm_dsize);
+ memset(e, '\0', sizeof(struct linux_emuldata));
+
+ if (forkflags & CLONE_VM) {
+ struct linux_emuldata *e2 = parent->p_emuldata;
+ s = e2->s;
+ s->refs++;
+ } else {
+ struct vmspace *vm;
+
+ MALLOC(s, void *, sizeof(struct linux_emuldata_shared),
+ M_EMULDATA, M_WAITOK);
+ s->refs = 1;
+
+ /*
+ * Set the process idea of the break to the real value.
+ * For fork, we use parent's vmspace since our's
+ * is not setup at the time of this call and is going
+ * to be copy of parent's anyway. For exec, just
+ * use our own vmspace.
+ */
+ vm = (parent) ? parent->p_vmspace : p->p_vmspace;
+ s->p_break = vm->vm_daddr + ctob(vm->vm_dsize);
+
+ }
+
+ e->s = s;
+ p->p_emuldata = e;
}
/*
- * Allocate per-process structures. Called when executing Linux
+ * Allocate new per-process structures. Called when executing Linux
* process. We can reuse the old emuldata - if it's not null,
* the executed process is of same emulation as original forked one.
*/
@@ -175,7 +204,7 @@ linux_e_proc_exec(p, epp)
struct exec_package *epp;
{
/* exec, use our vmspace */
- linux_e_proc_init(p, p->p_vmspace);
+ linux_e_proc_init(p, NULL, 0);
}
/*
@@ -185,8 +214,13 @@ static void
linux_e_proc_exit(p)
struct proc *p;
{
+ struct linux_emuldata *e = p->p_emuldata;
+
/* free Linux emuldata and set the pointer to null */
- FREE(p->p_emuldata, M_EMULDATA);
+ e->s->refs--;
+ if (e->s->refs == 0)
+ FREE(e->s, M_EMULDATA);
+ FREE(e, M_EMULDATA);
p->p_emuldata = NULL;
}
@@ -194,16 +228,16 @@ linux_e_proc_exit(p)
* Emulation fork hook.
*/
static void
-linux_e_proc_fork(p, parent)
+linux_e_proc_fork(p, parent, forkflags)
struct proc *p, *parent;
+ int forkflags;
{
/*
- * It could be desirable to copy some stuff from parent's
- * emuldata. We don't need anything like that for now.
- * So just allocate new emuldata for the new process.
+ * The new process might share some vmspace-related stuff
+ * with parent, depending on fork flags (CLONE_VM et.al).
+ * Force allocation of new base emuldata, and share the
+ * VM-related parts only if necessary.
*/
p->p_emuldata = NULL;
-
- /* fork, use parent's vmspace (our vmspace may not be setup yet) */
- linux_e_proc_init(p, parent->p_vmspace);
+ linux_e_proc_init(p, parent, forkflags);
}