diff options
author | 2014-06-13 01:48:51 +0000 | |
---|---|---|
committer | 2014-06-13 01:48:51 +0000 | |
commit | 7c15f335b2e8baba31f059cf0102f4d0564433b9 (patch) | |
tree | 858aa614e7f7293dfd72d33534465dae68dac9fc | |
parent | Fix ptrace() hanging hppa MP systems (diff) | |
download | wireguard-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.2 | 40 | ||||
-rw-r--r-- | sys/sys/mman.h | 5 | ||||
-rw-r--r-- | sys/uvm/uvm_extern.h | 4 | ||||
-rw-r--r-- | sys/uvm/uvm_map.c | 93 |
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); |