Author: attilio
Date: Fri Mar 19 22:39:27 2010
New Revision: 205349
URL: http://svn.freebsd.org/changeset/base/205349

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.
  
  Sponsored by: Sandvine Incorporated
  Reviewed by:  emaste

Modified:
  stable/6/sys/vm/swap_pager.c
  stable/6/sys/vm/vm_pageout.c
  stable/6/sys/vm/vm_pageout.h
Directory Properties:
  stable/6/sys/   (props changed)
  stable/6/sys/contrib/pf/   (props changed)
  stable/6/sys/dev/cxgb/   (props changed)

Modified: stable/6/sys/vm/swap_pager.c
==============================================================================
--- stable/6/sys/vm/swap_pager.c        Fri Mar 19 21:29:30 2010        
(r205348)
+++ stable/6/sys/vm/swap_pager.c        Fri Mar 19 22:39:27 2010        
(r205349)
@@ -1680,7 +1680,7 @@ swp_pager_meta_build(vm_object_t object,
 {
        struct swblock *swap;
        struct swblock **pswap;
-       int idx;
+       int dummy, idx;
 
        VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
        /*
@@ -1720,9 +1720,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);
+                               tsleep(&dummy, PVM, "swzonex", 10);
+                       } else
+                               VM_WAIT;
                        VM_OBJECT_LOCK(object);
                        goto retry;
                }

Modified: stable/6/sys/vm/vm_pageout.c
==============================================================================
--- stable/6/sys/vm/vm_pageout.c        Fri Mar 19 21:29:30 2010        
(r205348)
+++ stable/6/sys/vm/vm_pageout.c        Fri Mar 19 22:39:27 2010        
(r205349)
@@ -711,9 +711,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, cache_cur, cache_first_failure;
        static int cache_last_free;
@@ -1246,7 +1243,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
@@ -1254,77 +1267,81 @@ 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.
-                        */
-                       mtx_lock_spin(&sched_lock);
-                       breakout = 0;
-                       FOREACH_THREAD_IN_PROC(p, td) {
-                               if (!TD_ON_RUNQ(td) &&
-                                   !TD_IS_RUNNING(td) &&
-                                   !TD_IS_SLEEPING(td)) {
-                                       breakout = 1;
-                                       break;
-                               }
-                       }
-                       if (breakout) {
-                               mtx_unlock_spin(&sched_lock);
-                               PROC_UNLOCK(p);
-                               continue;
-                       }
-                       mtx_unlock_spin(&sched_lock);
-                       /*
-                        * get the process size
-                        */
-                       if (!vm_map_trylock_read(&p->p_vmspace->vm_map)) {
-                               PROC_UNLOCK(p);
-                               continue;
+               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.
+                */
+               mtx_lock_spin(&sched_lock);
+               breakout = 0;
+               FOREACH_THREAD_IN_PROC(p, td) {
+                       if (!TD_ON_RUNQ(td) &&
+                           !TD_IS_RUNNING(td) &&
+                           !TD_IS_SLEEPING(td)) {
+                               breakout = 1;
+                               break;
                        }
-                       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);
                }
-               sx_sunlock(&allproc_lock);
-               if (bigproc != NULL) {
-                       killproc(bigproc, "out of swap space");
-                       mtx_lock_spin(&sched_lock);
-                       sched_nice(bigproc, PRIO_MIN);
+               if (breakout) {
                        mtx_unlock_spin(&sched_lock);
-                       PROC_UNLOCK(bigproc);
-                       wakeup(&cnt.v_free_count);
+                       PROC_UNLOCK(p);
+                       continue;
+               }
+               mtx_unlock_spin(&sched_lock);
+               /*
+                * 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");
+               mtx_lock_spin(&sched_lock);
+               sched_nice(bigproc, PRIO_MIN);
+               mtx_unlock_spin(&sched_lock);
+               PROC_UNLOCK(bigproc);
+               wakeup(&cnt.v_free_count);
        }
 }
 
@@ -1595,6 +1612,7 @@ vm_daemon()
        struct rlimit rsslim;
        struct proc *p;
        struct thread *td;
+       struct vmspace *vm;
        int breakout, swapout_flags;
 
        while (TRUE) {
@@ -1619,7 +1637,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;
                        }
@@ -1656,13 +1674,17 @@ vm_daemon()
                         */
                        if ((p->p_sflag & PS_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/6/sys/vm/vm_pageout.h
==============================================================================
--- stable/6/sys/vm/vm_pageout.h        Fri Mar 19 21:29:30 2010        
(r205348)
+++ stable/6/sys/vm/vm_pageout.h        Fri Mar 19 22:39:27 2010        
(r205349)
@@ -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.
  */
@@ -99,5 +102,6 @@ extern void vm_waitpfault(void);
 
 #ifdef _KERNEL
 int vm_pageout_flush(vm_page_t *, int, int);
+void vm_pageout_oom(int shortage);
 #endif
 #endif /* _VM_VM_PAGEOUT_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to