From owner-freebsd-arm@FreeBSD.ORG Wed Jul 23 16:27:58 2014 Return-Path: Delivered-To: arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A63A258D; Wed, 23 Jul 2014 16:27:58 +0000 (UTC) Received: from pp2.rice.edu (proofpoint2.mail.rice.edu [128.42.201.101]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 65D342F3D; Wed, 23 Jul 2014 16:27:57 +0000 (UTC) Received: from pps.filterd (pp2.rice.edu [127.0.0.1]) by pp2.rice.edu (8.14.5/8.14.5) with SMTP id s6NGQqL1023777; Wed, 23 Jul 2014 11:27:50 -0500 Received: from mh1.mail.rice.edu (mh1.mail.rice.edu [128.42.201.20]) by pp2.rice.edu with ESMTP id 1na225g8q1-1; Wed, 23 Jul 2014 11:27:49 -0500 X-Virus-Scanned: by amavis-2.7.0 at mh1.mail.rice.edu, auth channel Received: from 108-254-203-201.lightspeed.hstntx.sbcglobal.net (108-254-203-201.lightspeed.hstntx.sbcglobal.net [108.254.203.201]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (No client certificate requested) (Authenticated sender: alc) by mh1.mail.rice.edu (Postfix) with ESMTPSA id 6BC1F460110; Wed, 23 Jul 2014 11:27:49 -0500 (CDT) Message-ID: <53CFE285.9040101@rice.edu> Date: Wed, 23 Jul 2014 11:27:49 -0500 From: Alan Cox User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:24.0) Gecko/20100101 Thunderbird/24.2.0 MIME-Version: 1.0 To: "arm@freebsd.org" Subject: testing new pmap code X-Enigmail-Version: 1.6 Content-Type: multipart/mixed; boundary="------------020007010401020701030001" X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 kscore.is_bulkscore=0 kscore.compositescore=0 circleOfTrustscore=0 compositescore=0.713890987064109 urlsuspect_oldscore=0.713890987064109 suspectscore=3 recipient_domain_to_sender_totalscore=0 phishscore=0 bulkscore=0 kscore.is_spamscore=1 recipient_to_sender_totalscore=0 recipient_domain_to_sender_domain_totalscore=0 rbsscore=0.713890987064109 spamscore=0 recipient_to_sender_domain_totalscore=0 urlsuspectscore=0.9 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=7.0.1-1402240000 definitions=main-1407230199 Cc: Konstantin Belousov , Alan Cox X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "Porting FreeBSD to ARM processors." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Jul 2014 16:27:58 -0000 This is a multi-part message in MIME format. --------------020007010401020701030001 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Folks, About a week ago I committed some new pmap code on all architectures, including arm. However, that code isn't "active" until the attached patch is committed. Before I commit this patch, I'd like to ask people to test it on arm "classic" and especially v6. (The v6 pmap changes were more complicated.) Here is how to test it. Before you apply the kernel patch, compile and run the attached program, mlockall2A.c, in a loop. Something like this: # while ( 1 ) while? ./mlockall2A while? sysctl vm.stats.vm.v_wire_count while? sleep 7 while? end You should see the wire count steadily increase, because there is a wired page leak. Now, apply the kernel patch, and repeat the same test. This time, the wire count should stabilize. If you're testing on arm v6, substitute sysctl vm.stats.vm.v_wire_count vm.pmap.section for sysctl vm.stats.vm.v_wire_count so that I can verify that we're handling superpages correctly. Thanks, Alan --------------020007010401020701030001 Content-Type: text/plain; charset=ISO-8859-15; name="vm_map_entry_unwire7.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="vm_map_entry_unwire7.patch" Index: vm/vm_extern.h =================================================================== --- vm/vm_extern.h (revision 268597) +++ vm/vm_extern.h (working copy) @@ -81,7 +81,6 @@ int vm_fault_hold(vm_map_t map, vm_offset_t vaddr, int fault_flags, vm_page_t *m_hold); int vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len, vm_prot_t prot, vm_page_t *ma, int max_count); -void vm_fault_unwire(vm_map_t, vm_offset_t, vm_offset_t, boolean_t); int vm_fault_wire(vm_map_t, vm_offset_t, vm_offset_t, boolean_t); int vm_forkproc(struct thread *, struct proc *, struct thread *, struct vmspace *, int); void vm_waitproc(struct proc *); Index: vm/vm_fault.c =================================================================== --- vm/vm_fault.c (revision 268597) +++ vm/vm_fault.c (working copy) @@ -106,6 +106,7 @@ __FBSDID("$FreeBSD$"); #define PFFOR 4 static int vm_fault_additional_pages(vm_page_t, int, int, vm_page_t *, int *); +static void vm_fault_unwire(vm_map_t, vm_offset_t, vm_offset_t, boolean_t); #define VM_FAULT_READ_BEHIND 8 #define VM_FAULT_READ_MAX (1 + VM_FAULT_READ_AHEAD_MAX) @@ -1186,7 +1187,7 @@ vm_fault_wire(vm_map_t map, vm_offset_t start, vm_ * * Unwire a range of virtual addresses in a map. */ -void +static void vm_fault_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, boolean_t fictitious) { Index: vm/vm_map.c =================================================================== --- vm/vm_map.c (revision 268597) +++ vm/vm_map.c (working copy) @@ -132,6 +132,7 @@ static void _vm_map_init(vm_map_t map, pmap_t pmap vm_offset_t max); static void vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map); static void vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry); +static void vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry); #ifdef INVARIANTS static void vm_map_zdtor(void *mem, int size, void *arg); static void vmspace_zdtor(void *mem, int size, void *arg); @@ -2393,16 +2394,10 @@ done: (entry->eflags & MAP_ENTRY_USER_WIRED))) { if (user_unwire) entry->eflags &= ~MAP_ENTRY_USER_WIRED; - entry->wired_count--; - if (entry->wired_count == 0) { - /* - * Retain the map lock. - */ - vm_fault_unwire(map, entry->start, entry->end, - entry->object.vm_object != NULL && - (entry->object.vm_object->flags & - OBJ_FICTITIOUS) != 0); - } + if (entry->wired_count == 1) + vm_map_entry_unwire(map, entry); + else + entry->wired_count--; } KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, ("vm_map_unwire: in-transition flag missing %p", entry)); @@ -2635,19 +2630,12 @@ done: * unnecessary. */ entry->wired_count = 0; - } else { - if (!user_wire || - (entry->eflags & MAP_ENTRY_USER_WIRED) == 0) + } else if (!user_wire || + (entry->eflags & MAP_ENTRY_USER_WIRED) == 0) { + if (entry->wired_count == 1) + vm_map_entry_unwire(map, entry); + else entry->wired_count--; - if (entry->wired_count == 0) { - /* - * Retain the map lock. - */ - vm_fault_unwire(map, entry->start, entry->end, - entry->object.vm_object != NULL && - (entry->object.vm_object->flags & - OBJ_FICTITIOUS) != 0); - } } next_entry_done: KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, @@ -2783,9 +2771,11 @@ vm_map_sync( static void vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry) { - vm_fault_unwire(map, entry->start, entry->end, - entry->object.vm_object != NULL && - (entry->object.vm_object->flags & OBJ_FICTITIOUS) != 0); + + VM_MAP_ASSERT_LOCKED(map); + pmap_unwire(map->pmap, entry->start, entry->end); + vm_object_unwire(entry->object.vm_object, entry->offset, entry->end - + entry->start, PQ_ACTIVE); entry->wired_count = 0; } Index: vm/vm_object.c =================================================================== --- vm/vm_object.c (revision 268597) +++ vm/vm_object.c (working copy) @@ -2200,6 +2200,78 @@ vm_object_set_writeable_dirty(vm_object_t object) vm_object_set_flag(object, OBJ_MIGHTBEDIRTY); } +/* + * vm_object_unwire: + * + * For each page offset within the specified range of the given object, + * find the highest-level page in the shadow chain and unwire it. A page + * must exist at every page offset, and the highest-level page must be + * wired. + */ +void +vm_object_unwire(vm_object_t object, vm_ooffset_t offset, vm_size_t length, + uint8_t queue) +{ + vm_object_t tobject; + vm_page_t m, tm; + vm_pindex_t end_pindex, pindex, tpindex; + int depth, locked_depth; + + KASSERT((offset & PAGE_MASK) == 0, + ("vm_object_unwire: offset is not page aligned")); + KASSERT((length & PAGE_MASK) == 0, + ("vm_object_unwire: length is not a multiple of PAGE_SIZE")); + /* The wired count of a fictitious page never changes. */ + if ((object->flags & OBJ_FICTITIOUS) != 0) + return; + pindex = OFF_TO_IDX(offset); + end_pindex = pindex + atop(length); + locked_depth = 1; + VM_OBJECT_RLOCK(object); + m = vm_page_find_least(object, pindex); + while (pindex < end_pindex) { + if (m == NULL || pindex < m->pindex) { + /* + * The first object in the shadow chain doesn't + * contain a page at the current index. Therefore, + * the page must exist in a backing object. + */ + tobject = object; + tpindex = pindex; + depth = 0; + do { + tpindex += + OFF_TO_IDX(tobject->backing_object_offset); + tobject = tobject->backing_object; + KASSERT(tobject != NULL, + ("vm_object_unwire: missing page")); + if ((tobject->flags & OBJ_FICTITIOUS) != 0) + goto next_page; + depth++; + if (depth == locked_depth) { + locked_depth++; + VM_OBJECT_RLOCK(tobject); + } + } while ((tm = vm_page_lookup(tobject, tpindex)) == + NULL); + } else { + tm = m; + m = TAILQ_NEXT(m, listq); + } + vm_page_lock(tm); + vm_page_unwire(tm, queue); + vm_page_unlock(tm); +next_page: + pindex++; + } + /* Release the accumulated object locks. */ + for (depth = 0; depth < locked_depth; depth++) { + tobject = object->backing_object; + VM_OBJECT_RUNLOCK(object); + object = tobject; + } +} + #include "opt_ddb.h" #ifdef DDB #include Index: vm/vm_object.h =================================================================== --- vm/vm_object.h (revision 268597) +++ vm/vm_object.h (working copy) @@ -290,6 +290,8 @@ void vm_object_shadow (vm_object_t *, vm_ooffset_t void vm_object_split(vm_map_entry_t); boolean_t vm_object_sync(vm_object_t, vm_ooffset_t, vm_size_t, boolean_t, boolean_t); +void vm_object_unwire(vm_object_t object, vm_ooffset_t offset, + vm_size_t length, uint8_t queue); #endif /* _KERNEL */ #endif /* _VM_OBJECT_ */ --------------020007010401020701030001 Content-Type: text/plain; charset=ISO-8859-15; name="mlockall2A.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="mlockall2A.c" #include #include #include int main(void) { size_t pagesize[2]; void *p; int flags = MAP_ANON | MAP_PRIVATE, sizes; if ((sizes = getpagesizes(pagesize, 2)) == -1) err(1, "getpagesizes"); if (sizes < 2) { pagesize[1] = 4 * 1024 * 1024; warnx("Faking pagesize[1] as %zu", pagesize[1]); } if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) err(1, "mlock"); if ((p = mmap(NULL, 3 * pagesize[1], PROT_READ | PROT_WRITE, flags, -1, 0)) == MAP_FAILED) err(1, "mmap"); if (mprotect(p, pagesize[1] + pagesize[0], PROT_NONE) == -1) err(1, "mprotect"); return (0); } --------------020007010401020701030001--