summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatthew <matthew@openbsd.org>2014-06-13 01:48:51 +0000
committermatthew <matthew@openbsd.org>2014-06-13 01:48:51 +0000
commit7c15f335b2e8baba31f059cf0102f4d0564433b9 (patch)
tree858aa614e7f7293dfd72d33534465dae68dac9fc
parentFix ptrace() hanging hppa MP systems (diff)
downloadwireguard-openbsd-7c15f335b2e8baba31f059cf0102f4d0564433b9.tar.xz
wireguard-openbsd-7c15f335b2e8baba31f059cf0102f4d0564433b9.zip
Add support for MAP_INHERIT_ZERO.
This provides a way for a process to designate pages in its address space that should be replaced by fresh, zero-initialized anonymous memory in forked child processes, rather than being copied or shared. ok jmc, kettenis, tedu, deraadt; positive feedback from many more
-rw-r--r--lib/libc/sys/minherit.240
-rw-r--r--sys/sys/mman.h5
-rw-r--r--sys/uvm/uvm_extern.h4
-rw-r--r--sys/uvm/uvm_map.c93
4 files changed, 96 insertions, 46 deletions
diff --git a/lib/libc/sys/minherit.2 b/lib/libc/sys/minherit.2
index 05ea31c61a4..d6d0784e60c 100644
--- a/lib/libc/sys/minherit.2
+++ b/lib/libc/sys/minherit.2
@@ -1,4 +1,4 @@
-.\" $OpenBSD: minherit.2,v 1.13 2007/05/31 19:19:33 jmc Exp $
+.\" $OpenBSD: minherit.2,v 1.14 2014/06/13 01:48:51 matthew Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" @(#)minherit.2 8.1 (Berkeley) 6/9/93
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: June 13 2014 $
.Dt MINHERIT 2
.Os
.Sh NAME
@@ -45,12 +45,25 @@ The
.Fn minherit
system call
changes the specified pages to have the inheritance characteristic
-.Fa inherit ,
-which can be set to
-.Dv MAP_INHERIT_NONE ,
-.Dv MAP_INHERIT_COPY ,
-or
-.Dv MAP_INHERIT_SHARE .
+.Fa inherit .
+A page's inheritance characteristic controls how it will be mapped
+in child processes as created by
+.Xr fork 2 .
+.Pp
+The possible inheritance characteristics are:
+.Pp
+.Bl -tag -width MAP_INHERIT_SHARE -offset indent -compact
+.It Dv MAP_INHERIT_NONE
+Pages are not mapped in the child process.
+.It Dv MAP_INHERIT_COPY
+Private copy of pages are mapped in the child process.
+.It Dv MAP_INHERIT_SHARE
+Mapped pages are shared between the parent and child processes.
+.It Dv MAP_INHERIT_ZERO
+New anonymous pages (initialized to all zero bytes)
+are mapped in the child process.
+.El
+.Pp
Not all implementations will guarantee that the inheritance characteristic
can be set on a page basis;
the granularity of changes may be as large as an entire region.
@@ -72,15 +85,10 @@ The virtual address range specified by the
and
.Fa len
arguments is not valid.
-.It Bq Er EACCES
-The flags specified by the
+.It Bq Er EINVAL
+The
.Fa inherit
-argument were not valid for the pages specified
-by the
-.Fa addr
-and
-.Fa len
-arguments.
+argument is invalid.
.El
.Sh SEE ALSO
.Xr madvise 2 ,
diff --git a/sys/sys/mman.h b/sys/sys/mman.h
index cc4fca178a8..899fb7e8af3 100644
--- a/sys/sys/mman.h
+++ b/sys/sys/mman.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mman.h,v 1.23 2013/05/31 18:41:26 tedu Exp $ */
+/* $OpenBSD: mman.h,v 1.24 2014/06/13 01:48:52 matthew Exp $ */
/* $NetBSD: mman.h,v 1.11 1995/03/26 20:24:23 jtc Exp $ */
/*-
@@ -107,8 +107,7 @@
#define MAP_INHERIT_SHARE 0 /* share with child */
#define MAP_INHERIT_COPY 1 /* copy into child */
#define MAP_INHERIT_NONE 2 /* absent from child */
-#define MAP_INHERIT_DONATE_COPY 3 /* copy and delete -- not
- implemented in UVM */
+#define MAP_INHERIT_ZERO 3 /* zero in child */
/*
* Flags to msync
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index 76b5946352f..42329bc9916 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.115 2014/05/15 03:52:25 guenther Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.116 2014/06/13 01:48:52 matthew Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -134,7 +134,7 @@ typedef struct vm_page *vm_page_t;
#define UVM_INH_SHARE 0x00 /* "share" */
#define UVM_INH_COPY 0x10 /* "copy" */
#define UVM_INH_NONE 0x20 /* "none" */
-#define UVM_INH_DONATE 0x30 /* "donate" << not used */
+#define UVM_INH_ZERO 0x30 /* "zero" */
/* 0x40, 0x80: not used */
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index 1648d40ec53..90cff04531b 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.c,v 1.168 2014/05/15 03:52:25 guenther Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.169 2014/06/13 01:48:52 matthew Exp $ */
/* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
/*
@@ -190,10 +190,13 @@ int uvm_mapent_bias(struct vm_map*, struct vm_map_entry*);
struct vm_map_entry *uvm_mapent_clone(struct vm_map*, vaddr_t, vsize_t,
vsize_t, struct vm_map_entry*,
struct uvm_map_deadq*, int, int);
-void uvm_mapent_forkshared(struct vmspace*, struct vm_map*,
+struct vm_map_entry *uvm_mapent_forkshared(struct vmspace*, struct vm_map*,
struct vm_map*, struct vm_map_entry*,
struct uvm_map_deadq*);
-void uvm_mapent_forkcopy(struct vmspace*, struct vm_map*,
+struct vm_map_entry *uvm_mapent_forkcopy(struct vmspace*, struct vm_map*,
+ struct vm_map*, struct vm_map_entry*,
+ struct uvm_map_deadq*);
+struct vm_map_entry *uvm_mapent_forkzero(struct vmspace*, struct vm_map*,
struct vm_map*, struct vm_map_entry*,
struct uvm_map_deadq*);
@@ -3158,7 +3161,7 @@ uvmspace_free(struct vmspace *vm)
* Space must be available.
* Reference counters are incremented.
*/
-struct vm_map_entry*
+struct vm_map_entry *
uvm_mapent_clone(struct vm_map *dstmap, vaddr_t dstaddr, vsize_t dstlen,
vsize_t off, struct vm_map_entry *old_entry, struct uvm_map_deadq *dead,
int mapent_flags, int amap_share_flags)
@@ -3209,7 +3212,7 @@ uvm_mapent_clone(struct vm_map *dstmap, vaddr_t dstaddr, vsize_t dstlen,
* share the mapping: this means we want the old and
* new entries to share amaps and backing objects.
*/
-void
+struct vm_map_entry *
uvm_mapent_forkshared(struct vmspace *new_vm, struct vm_map *new_map,
struct vm_map *old_map,
struct vm_map_entry *old_entry, struct uvm_map_deadq *dead)
@@ -3243,13 +3246,7 @@ uvm_mapent_forkshared(struct vmspace *new_vm, struct vm_map *new_map,
pmap_copy(new_map->pmap, old_map->pmap, new_entry->start,
(new_entry->end - new_entry->start), new_entry->start);
- /* Update process statistics. */
- if (!UVM_ET_ISHOLE(new_entry))
- new_map->size += new_entry->end - new_entry->start;
- if (!UVM_ET_ISOBJ(new_entry) && !UVM_ET_ISHOLE(new_entry)) {
- new_vm->vm_dused +=
- uvmspace_dused(new_map, new_entry->start, new_entry->end);
- }
+ return (new_entry);
}
/*
@@ -3259,7 +3256,7 @@ uvm_mapent_forkshared(struct vmspace *new_vm, struct vm_map *new_map,
* allocate new_entry, adjust reference counts.
* (note that new references are read-only).
*/
-void
+struct vm_map_entry *
uvm_mapent_forkcopy(struct vmspace *new_vm, struct vm_map *new_map,
struct vm_map *old_map,
struct vm_map_entry *old_entry, struct uvm_map_deadq *dead)
@@ -3396,13 +3393,42 @@ uvm_mapent_forkcopy(struct vmspace *new_vm, struct vm_map *new_map,
}
}
- /* Update process statistics. */
- if (!UVM_ET_ISHOLE(new_entry))
- new_map->size += new_entry->end - new_entry->start;
- if (!UVM_ET_ISOBJ(new_entry) && !UVM_ET_ISHOLE(new_entry)) {
- new_vm->vm_dused +=
- uvmspace_dused(new_map, new_entry->start, new_entry->end);
+ return (new_entry);
+}
+
+/*
+ * zero the mapping: the new entry will be zero initialized
+ */
+struct vm_map_entry *
+uvm_mapent_forkzero(struct vmspace *new_vm, struct vm_map *new_map,
+ struct vm_map *old_map,
+ struct vm_map_entry *old_entry, struct uvm_map_deadq *dead)
+{
+ struct vm_map_entry *new_entry;
+
+ new_entry = uvm_mapent_clone(new_map, old_entry->start,
+ old_entry->end - old_entry->start, 0, old_entry,
+ dead, 0, 0);
+
+ new_entry->etype |=
+ (UVM_ET_COPYONWRITE|UVM_ET_NEEDSCOPY);
+
+ if (new_entry->aref.ar_amap) {
+ amap_unref(new_entry->aref.ar_amap, new_entry->aref.ar_pageoff,
+ atop(new_entry->end - new_entry->start), 0);
+ new_entry->aref.ar_amap = NULL;
+ new_entry->aref.ar_pageoff = 0;
}
+
+ if (UVM_ET_ISOBJ(new_entry)) {
+ if (new_entry->object.uvm_obj->pgops->pgo_detach)
+ new_entry->object.uvm_obj->pgops->pgo_detach(
+ new_entry->object.uvm_obj);
+ new_entry->object.uvm_obj = NULL;
+ new_entry->etype &= ~UVM_ET_OBJ;
+ }
+
+ return (new_entry);
}
/*
@@ -3418,7 +3444,7 @@ uvmspace_fork(struct process *pr)
struct vmspace *vm2;
struct vm_map *old_map = &vm1->vm_map;
struct vm_map *new_map;
- struct vm_map_entry *old_entry;
+ struct vm_map_entry *old_entry, *new_entry;
struct uvm_map_deadq dead;
vm_map_lock(old_map);
@@ -3450,13 +3476,29 @@ uvmspace_fork(struct process *pr)
}
/* Apply inheritance. */
- if (old_entry->inheritance == MAP_INHERIT_SHARE) {
- uvm_mapent_forkshared(vm2, new_map,
+ switch (old_entry->inheritance) {
+ case MAP_INHERIT_SHARE:
+ new_entry = uvm_mapent_forkshared(vm2, new_map,
old_map, old_entry, &dead);
- }
- if (old_entry->inheritance == MAP_INHERIT_COPY) {
- uvm_mapent_forkcopy(vm2, new_map,
+ break;
+ case MAP_INHERIT_COPY:
+ new_entry = uvm_mapent_forkcopy(vm2, new_map,
+ old_map, old_entry, &dead);
+ break;
+ case MAP_INHERIT_ZERO:
+ new_entry = uvm_mapent_forkzero(vm2, new_map,
old_map, old_entry, &dead);
+ break;
+ default:
+ continue;
+ }
+
+ /* Update process statistics. */
+ if (!UVM_ET_ISHOLE(new_entry))
+ new_map->size += new_entry->end - new_entry->start;
+ if (!UVM_ET_ISOBJ(new_entry) && !UVM_ET_ISHOLE(new_entry)) {
+ vm2->vm_dused += uvmspace_dused(
+ new_map, new_entry->start, new_entry->end);
}
}
@@ -3670,6 +3712,7 @@ uvm_map_inherit(struct vm_map *map, vaddr_t start, vaddr_t end,
case MAP_INHERIT_NONE:
case MAP_INHERIT_COPY:
case MAP_INHERIT_SHARE:
+ case MAP_INHERIT_ZERO:
break;
default:
return (EINVAL);