Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Aug 2009 15:48:59 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r196590 - in stable/7/sys: . contrib/pf vm
Message-ID:  <200908271548.n7RFmxVj000457@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Thu Aug 27 15:48:58 2009
New Revision: 196590
URL: http://svn.freebsd.org/changeset/base/196590

Log:
  MFC 181019, 183474, 191277, and 191626:
  - Move the code for doing out-of-memory grass from vm_pageout_scan()
    into the separate function vm_pageout_oom(). Supply a parameter for
    vm_pageout_oom() describing a reason for the call.
  - Call vm_pageout_oom() from the swp_pager_meta_build() when swap zone
    is exhausted.
  - In both pageout oom handler and vm_daemon, acquire the reference to
    the vmspace of the examined process instead of directly accessing its
    vmspace, that may change. Also, as an optimization, check for P_INEXEC
    flag before examining the process.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/vm/swap_pager.c
  stable/7/sys/vm/vm_pageout.c
  stable/7/sys/vm/vm_pageout.h

Modified: stable/7/sys/vm/swap_pager.c
==============================================================================
--- stable/7/sys/vm/swap_pager.c	Thu Aug 27 15:24:26 2009	(r196589)
+++ stable/7/sys/vm/swap_pager.c	Thu Aug 27 15:48:58 2009	(r196590)
@@ -1711,9 +1711,12 @@ retry:
 		if (swap == NULL) {
 			mtx_unlock(&swhash_mtx);
 			VM_OBJECT_UNLOCK(object);
-			if (uma_zone_exhausted(swap_zone))
+			if (uma_zone_exhausted(swap_zone)) {
 				printf("swap zone exhausted, increase kern.maxswzone\n");
-			VM_WAIT;
+				vm_pageout_oom(VM_OOM_SWAPZ);
+				pause("swzonex", 10);
+			} else
+				VM_WAIT;
 			VM_OBJECT_LOCK(object);
 			goto retry;
 		}

Modified: stable/7/sys/vm/vm_pageout.c
==============================================================================
--- stable/7/sys/vm/vm_pageout.c	Thu Aug 27 15:24:26 2009	(r196589)
+++ stable/7/sys/vm/vm_pageout.c	Thu Aug 27 15:48:58 2009	(r196590)
@@ -681,9 +681,6 @@ vm_pageout_scan(int pass)
 	struct vm_page marker;
 	int page_shortage, maxscan, pcount;
 	int addl_page_shortage, addl_page_shortage_init;
-	struct proc *p, *bigproc;
-	struct thread *td;
-	vm_offset_t size, bigsize;
 	vm_object_t object;
 	int actcount;
 	int vnodes_skipped = 0;
@@ -1173,7 +1170,23 @@ unlock_and_continue:
 	 * doing this on the first pass in order to give ourselves a
 	 * chance to flush out dirty vnode-backed pages and to allow
 	 * active pages to be moved to the inactive queue and reclaimed.
-	 *
+	 */
+	if (pass != 0 &&
+	    ((swap_pager_avail < 64 && vm_page_count_min()) ||
+	     (swap_pager_full && vm_paging_target() > 0)))
+		vm_pageout_oom(VM_OOM_MEM);
+}
+
+
+void
+vm_pageout_oom(int shortage)
+{
+	struct proc *p, *bigproc;
+	vm_offset_t size, bigsize;
+	struct thread *td;
+	struct vmspace *vm;
+
+	/*
 	 * We keep the process bigproc locked once we find it to keep anyone
 	 * from messing with it; however, there is a possibility of
 	 * deadlock if process B is bigproc and one of it's child processes
@@ -1181,79 +1194,83 @@ unlock_and_continue:
 	 * lock while walking this list.  To avoid this, we don't block on
 	 * the process lock but just skip a process if it is already locked.
 	 */
-	if (pass != 0 &&
-	    ((swap_pager_avail < 64 && vm_page_count_min()) ||
-	     (swap_pager_full && vm_paging_target() > 0))) {
-		bigproc = NULL;
-		bigsize = 0;
-		sx_slock(&allproc_lock);
-		FOREACH_PROC_IN_SYSTEM(p) {
-			int breakout;
+	bigproc = NULL;
+	bigsize = 0;
+	sx_slock(&allproc_lock);
+	FOREACH_PROC_IN_SYSTEM(p) {
+		int breakout;
 
-			if (PROC_TRYLOCK(p) == 0)
-				continue;
-			/*
-			 * If this is a system or protected process, skip it.
-			 */
-			if ((p->p_flag & P_SYSTEM) || (p->p_pid == 1) ||
-			    (p->p_flag & P_PROTECTED) ||
-			    ((p->p_pid < 48) && (swap_pager_avail != 0))) {
-				PROC_UNLOCK(p);
-				continue;
-			}
-			/*
-			 * If the process is in a non-running type state,
-			 * don't touch it.  Check all the threads individually.
-			 */
-			PROC_SLOCK(p);
-			breakout = 0;
-			FOREACH_THREAD_IN_PROC(p, td) {
-				thread_lock(td);
-				if (!TD_ON_RUNQ(td) &&
-				    !TD_IS_RUNNING(td) &&
-				    !TD_IS_SLEEPING(td)) {
-					thread_unlock(td);
-					breakout = 1;
-					break;
-				}
+		if (PROC_TRYLOCK(p) == 0)
+			continue;
+		/*
+		 * If this is a system or protected process, skip it.
+		 */
+		if ((p->p_flag & (P_INEXEC | P_PROTECTED | P_SYSTEM)) ||
+		    (p->p_pid == 1) ||
+		    ((p->p_pid < 48) && (swap_pager_avail != 0))) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+		/*
+		 * If the process is in a non-running type state,
+		 * don't touch it.  Check all the threads individually.
+		 */
+		PROC_SLOCK(p);
+		breakout = 0;
+		FOREACH_THREAD_IN_PROC(p, td) {
+			thread_lock(td);
+			if (!TD_ON_RUNQ(td) &&
+			    !TD_IS_RUNNING(td) &&
+			    !TD_IS_SLEEPING(td)) {
 				thread_unlock(td);
+				breakout = 1;
+				break;
 			}
-			PROC_SUNLOCK(p);
-			if (breakout) {
-				PROC_UNLOCK(p);
-				continue;
-			}
-			/*
-			 * get the process size
-			 */
-			if (!vm_map_trylock_read(&p->p_vmspace->vm_map)) {
-				PROC_UNLOCK(p);
-				continue;
-			}
-			size = vmspace_swap_count(p->p_vmspace);
-			vm_map_unlock_read(&p->p_vmspace->vm_map);
-			size += vmspace_resident_count(p->p_vmspace);
-			/*
-			 * if the this process is bigger than the biggest one
-			 * remember it.
-			 */
-			if (size > bigsize) {
-				if (bigproc != NULL)
-					PROC_UNLOCK(bigproc);
-				bigproc = p;
-				bigsize = size;
-			} else
-				PROC_UNLOCK(p);
+			thread_unlock(td);
 		}
-		sx_sunlock(&allproc_lock);
-		if (bigproc != NULL) {
-			killproc(bigproc, "out of swap space");
-			PROC_SLOCK(bigproc);
-			sched_nice(bigproc, PRIO_MIN);
-			PROC_SUNLOCK(bigproc);
-			PROC_UNLOCK(bigproc);
-			wakeup(&cnt.v_free_count);
+		PROC_SUNLOCK(p);
+		if (breakout) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+		/*
+		 * get the process size
+		 */
+		vm = vmspace_acquire_ref(p);
+		if (vm == NULL) {
+			PROC_UNLOCK(p);
+			continue;
 		}
+		if (!vm_map_trylock_read(&vm->vm_map)) {
+			vmspace_free(vm);
+			PROC_UNLOCK(p);
+			continue;
+		}
+		size = vmspace_swap_count(vm);
+		vm_map_unlock_read(&vm->vm_map);
+		if (shortage == VM_OOM_MEM)
+			size += vmspace_resident_count(vm);
+		vmspace_free(vm);
+		/*
+		 * if the this process is bigger than the biggest one
+		 * remember it.
+		 */
+		if (size > bigsize) {
+			if (bigproc != NULL)
+				PROC_UNLOCK(bigproc);
+			bigproc = p;
+			bigsize = size;
+		} else
+			PROC_UNLOCK(p);
+	}
+	sx_sunlock(&allproc_lock);
+	if (bigproc != NULL) {
+		killproc(bigproc, "out of swap space");
+		PROC_SLOCK(bigproc);
+		sched_nice(bigproc, PRIO_MIN);
+		PROC_SUNLOCK(bigproc);
+		PROC_UNLOCK(bigproc);
+		wakeup(&cnt.v_free_count);
 	}
 }
 
@@ -1528,6 +1545,7 @@ vm_daemon()
 	struct rlimit rsslim;
 	struct proc *p;
 	struct thread *td;
+	struct vmspace *vm;
 	int breakout, swapout_flags;
 
 	while (TRUE) {
@@ -1552,7 +1570,7 @@ vm_daemon()
 			 * looked at this process, skip it.
 			 */
 			PROC_LOCK(p);
-			if (p->p_flag & (P_SYSTEM | P_WEXIT)) {
+			if (p->p_flag & (P_INEXEC | P_SYSTEM | P_WEXIT)) {
 				PROC_UNLOCK(p);
 				continue;
 			}
@@ -1592,13 +1610,17 @@ vm_daemon()
 			 */
 			if ((p->p_flag & P_INMEM) == 0)
 				limit = 0;	/* XXX */
+			vm = vmspace_acquire_ref(p);
 			PROC_UNLOCK(p);
+			if (vm == NULL)
+				continue;
 
-			size = vmspace_resident_count(p->p_vmspace);
+			size = vmspace_resident_count(vm);
 			if (limit >= 0 && size >= limit) {
 				vm_pageout_map_deactivate_pages(
-				    &p->p_vmspace->vm_map, limit);
+				    &vm->vm_map, limit);
 			}
+			vmspace_free(vm);
 		}
 		sx_sunlock(&allproc_lock);
 	}

Modified: stable/7/sys/vm/vm_pageout.h
==============================================================================
--- stable/7/sys/vm/vm_pageout.h	Thu Aug 27 15:24:26 2009	(r196589)
+++ stable/7/sys/vm/vm_pageout.h	Thu Aug 27 15:48:58 2009	(r196590)
@@ -83,6 +83,9 @@ extern int vm_pageout_page_count;
 #define VM_SWAP_NORMAL 1
 #define VM_SWAP_IDLE 2
 
+#define	VM_OOM_MEM	1
+#define	VM_OOM_SWAPZ	2
+
 /*
  *	Exported routines.
  */
@@ -100,5 +103,6 @@ extern void vm_waitpfault(void);
 #ifdef _KERNEL
 boolean_t vm_pageout_fallback_object_lock(vm_page_t, vm_page_t *);
 int vm_pageout_flush(vm_page_t *, int, int);
+void vm_pageout_oom(int shortage);
 #endif
 #endif	/* _VM_VM_PAGEOUT_H_ */



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