Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Mar 2018 03:53:33 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r330827 - user/jeff/numa/sys/vm
Message-ID:  <201803130353.w2D3rXIc029673@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Tue Mar 13 03:53:33 2018
New Revision: 330827
URL: https://svnweb.freebsd.org/changeset/base/330827

Log:
  Fix a smattering of bugs in my lockless free_count work and a recent
  merge.  There was an overflow bug in vm_domain_allocate().  Some double
  counting of frees, and a locking bug in reclaim_run that may exist in
  CURRENT.
  
  Reported by:	pho

Modified:
  user/jeff/numa/sys/vm/vm_page.c
  user/jeff/numa/sys/vm/vm_reserv.c

Modified: user/jeff/numa/sys/vm/vm_page.c
==============================================================================
--- user/jeff/numa/sys/vm/vm_page.c	Tue Mar 13 03:02:09 2018	(r330826)
+++ user/jeff/numa/sys/vm/vm_page.c	Tue Mar 13 03:53:33 2018	(r330827)
@@ -184,7 +184,7 @@ static uma_zone_t fakepg_zone;
 static void vm_page_alloc_check(vm_page_t m);
 static void vm_page_clear_dirty_mask(vm_page_t m, vm_page_bits_t pagebits);
 static void vm_page_enqueue(uint8_t queue, vm_page_t m);
-static void vm_page_free_phys(struct vm_domain *vmd, vm_page_t m);
+static int vm_page_free_phys(struct vm_domain *vmd, vm_page_t m);
 static void vm_page_init(void *dummy);
 static int vm_page_insert_after(vm_page_t m, vm_object_t object,
     vm_pindex_t pindex, vm_page_t mpred);
@@ -1733,11 +1733,12 @@ vm_domain_allocate(struct vm_domain *vmd, int req, int
 	/*
 	 * Attempt to reserve the pages.  Fail if we're below the limit.
 	 */
+	limit += npages;
 	do {
 		old = vmd->vmd_free_count;
-		new = old - npages;
-		if (new < limit)
+		if (old < limit)
 			return (0);
+		new = old - npages;
 	} while (atomic_cmpset_int(&vmd->vmd_free_count, old, new) == 0);
 
 	/* Wake the page daemon if we've crossed the threshold. */
@@ -2233,7 +2234,7 @@ vm_page_release(void *arg, void **store, int cnt)
 		vm_phys_free_pages(m, 0);
 	}
 	vm_domain_free_unlock(vmd);
-	vm_domain_freecnt_inc(vmd, i);
+	vm_domain_freecnt_inc(vmd, cnt);
 }
 
 #define	VPSC_ANY	0	/* No restrictions. */
@@ -2584,7 +2585,12 @@ retry:
 					    m->pindex, m);
 					m->valid = 0;
 					vm_page_undirty(m);
-
+					m->oflags = VPO_UNMANAGED;
+#if VM_NRESERVLEVEL > 0
+					if (!vm_reserv_free_page(m))
+#endif
+						SLIST_INSERT_HEAD(&free, m,
+						    plinks.s.ss);
 					/*
 					 * The new page must be deactivated
 					 * before the object is unlocked.
@@ -2597,19 +2603,20 @@ retry:
 					vm_page_remove(m);
 					KASSERT(m->dirty == 0,
 					    ("page %p is dirty", m));
-				}
+					m->oflags = VPO_UNMANAGED;
 #if VM_NRESERVLEVEL > 0
-				if (!vm_reserv_free_page(m))
+					if (!vm_reserv_free_page(m))
 #endif
-					SLIST_INSERT_HEAD(&free, m,
-					    plinks.s.ss);
+						SLIST_INSERT_HEAD(&free, m,
+						    plinks.s.ss);
+				}
 			} else
 				error = EBUSY;
 unlock:
 			VM_OBJECT_WUNLOCK(object);
 		} else {
 			MPASS(vm_phys_domain(m) == domain);
-			vm_page_lock(m);
+			/* XXX order unsynchronized? */
 			order = m->order;
 			if (order < VM_NFREEORDER) {
 				/*
@@ -2626,7 +2633,6 @@ unlock:
 			else if (vm_reserv_is_page_free(m))
 				order = 0;
 #endif
-			vm_page_unlock(m);
 			if (order == VM_NFREEORDER)
 				error = EINVAL;
 		}
@@ -3284,16 +3290,18 @@ vm_page_free_prep(vm_page_t m, bool pagequeue_locked)
  * queues.  This is the last step to free a page.  The caller is
  * responsible for adjusting the free page count.
  */
-static void
+static int
 vm_page_free_phys(struct vm_domain *vmd, vm_page_t m)
 {
 
 	vm_domain_free_assert_locked(vmd);
 
 #if VM_NRESERVLEVEL > 0
-	if (!vm_reserv_free_page(m))
+	if (vm_reserv_free_page(m))
+		return (0);
 #endif
-		vm_phys_free_pages(m, 0);
+	vm_phys_free_pages(m, 0);
+	return (1);
 }
 
 void
@@ -3317,8 +3325,7 @@ vm_page_free_phys_pglist(struct pglist *tq)
 			vmd = vm_pagequeue_domain(m);
 			vm_domain_free_lock(vmd);
 		}
-		vm_page_free_phys(vmd, m);
-		cnt++;
+		cnt += vm_page_free_phys(vmd, m);
 	}
 	if (vmd != NULL) {
 		vm_domain_free_unlock(vmd);
@@ -3339,14 +3346,16 @@ void
 vm_page_free_toq(vm_page_t m)
 {
 	struct vm_domain *vmd;
+	int freed;
 
 	if (!vm_page_free_prep(m, false))
 		return;
 	vmd = vm_pagequeue_domain(m);
 	vm_domain_free_lock(vmd);
-	vm_page_free_phys(vmd, m);
+	freed = vm_page_free_phys(vmd, m);
 	vm_domain_free_unlock(vmd);
-	vm_domain_freecnt_inc(vmd, 1);
+	if (freed)
+		vm_domain_freecnt_inc(vmd, 1);
 }
 
 /*
@@ -3374,11 +3383,8 @@ vm_page_free_pages_toq(struct spglist *free, bool upda
 	while ((m = SLIST_FIRST(free)) != NULL) {
 		count++;
 		SLIST_REMOVE_HEAD(free, plinks.s.ss);
-		/* XXX batch locks. */
-		vm_page_lock(m);
 		if (vm_page_free_prep(m, false))
 			TAILQ_INSERT_TAIL(&pgl, m, listq);
-		vm_page_unlock(m);
 	}
 
 	vm_page_free_phys_pglist(&pgl);

Modified: user/jeff/numa/sys/vm/vm_reserv.c
==============================================================================
--- user/jeff/numa/sys/vm/vm_reserv.c	Tue Mar 13 03:02:09 2018	(r330826)
+++ user/jeff/numa/sys/vm/vm_reserv.c	Tue Mar 13 03:53:33 2018	(r330827)
@@ -455,20 +455,8 @@ vm_reserv_depopulate(vm_reserv_t rv, int index)
 static __inline vm_reserv_t
 vm_reserv_from_page(vm_page_t m)
 {
-	vm_reserv_t rv;
 
-	rv = &vm_reserv_array[VM_PAGE_TO_PHYS(m) >> VM_LEVEL_0_SHIFT];
-#if 0
-	if (rv->pages == NULL)
-		panic("vm_reserv_from_page: Bad reservation %p page %p phys %p segind %d start %p end %p first page %p domain %d\n",
-		    rv, m, (void *)m->phys_addr, m->segind,
-		    (void *)vm_phys_segs[m->segind].start,
-		    (void *)vm_phys_segs[m->segind].end,
-		    vm_phys_segs[m->segind].first_page,
-		    vm_phys_segs[m->segind].domain);
-#endif
-
-	return (rv);
+	return (&vm_reserv_array[VM_PAGE_TO_PHYS(m) >> VM_LEVEL_0_SHIFT]);
 }
 
 /*
@@ -790,14 +778,14 @@ vm_reserv_alloc_contig(int req, vm_object_t object, vm
 	 */
 	m = NULL;
 	vmd = VM_DOMAIN(domain);
-	if (vm_domain_allocate(vmd, req, allocpages)) {
+	if (vm_domain_allocate(vmd, req, npages)) {
 		vm_domain_free_lock(vmd);
 		m = vm_phys_alloc_contig(domain, allocpages, low, high,
 		    ulmax(alignment, VM_LEVEL_0_SIZE),
 		    boundary > VM_LEVEL_0_SIZE ? boundary : 0);
 		vm_domain_free_unlock(vmd);
 		if (m == NULL) {
-			vm_domain_freecnt_inc(vmd, allocpages);
+			vm_domain_freecnt_inc(vmd, npages);
 			return (NULL);
 		}
 	} else



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803130353.w2D3rXIc029673>