summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2018-08-04 20:45:43 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2018-08-04 20:45:43 +0000
commita70e9a1388d4aa928158fc9204553a89ee9c6332 (patch)
tree7f797a596632ea89f1a5a6c7646eda8f28f56731 /sys
parent9f21643182a8c77df8949e8a3a425d6e5dc24baa (diff)
downloadsrc-test2-a70e9a1388d4aa928158fc9204553a89ee9c6332.tar.gz
src-test2-a70e9a1388d4aa928158fc9204553a89ee9c6332.zip
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_sig.c19
-rw-r--r--sys/kern/sys_process.c2
-rw-r--r--sys/sys/proc.h1
-rw-r--r--sys/vm/vm_swapout.c127
4 files changed, 101 insertions, 48 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index a2b07974bdb5..0817bb618c1c 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -3064,6 +3064,23 @@ postsig(int sig)
return (1);
}
+void
+proc_wkilled(struct proc *p)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ if ((p->p_flag & P_WKILLED) == 0) {
+ p->p_flag |= P_WKILLED;
+ /*
+ * Notify swapper that there is a process to swap in.
+ * The notification is racy, at worst it would take 10
+ * seconds for the swapper process to notice.
+ */
+ if ((p->p_flag & (P_INMEM | P_SWAPPINGIN)) == 0)
+ wakeup(&proc0);
+ }
+}
+
/*
* Kill the current process for stated reason.
*/
@@ -3076,7 +3093,7 @@ killproc(struct proc *p, char *why)
p->p_comm);
log(LOG_ERR, "pid %d (%s), uid %d, was killed: %s\n", p->p_pid,
p->p_comm, p->p_ucred ? p->p_ucred->cr_uid : -1, why);
- p->p_flag |= P_WKILLED;
+ proc_wkilled(p);
kern_psignal(p, SIGKILL);
}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index af3199468bc2..886df3113737 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1170,7 +1170,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
* queue cannot accommodate any new signals.
*/
if (data == SIGKILL)
- p->p_flag |= P_WKILLED;
+ proc_wkilled(p);
/*
* Unsuspend all threads. To leave a thread
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 2d393435b35d..d5351dd043c1 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1050,6 +1050,7 @@ struct proc *proc_realparent(struct proc *child);
void proc_reap(struct thread *td, struct proc *p, int *status, int options);
void proc_reparent(struct proc *child, struct proc *newparent);
void proc_set_traced(struct proc *p, bool stop);
+void proc_wkilled(struct proc *p);
struct pstats *pstats_alloc(void);
void pstats_fork(struct pstats *src, struct pstats *dst);
void pstats_free(struct pstats *ps);
diff --git a/sys/vm/vm_swapout.c b/sys/vm/vm_swapout.c
index d4e6e3a86770..343ff830f0c6 100644
--- a/sys/vm/vm_swapout.c
+++ b/sys/vm/vm_swapout.c
@@ -158,13 +158,14 @@ static struct mtx vm_daemon_mtx;
/* Allow for use by vm_pageout before vm_daemon is initialized. */
MTX_SYSINIT(vm_daemon, &vm_daemon_mtx, "vm daemon", MTX_DEF);
+static int swapped_cnt;
+
static void swapclear(struct proc *);
static int swapout(struct proc *);
static void vm_swapout_map_deactivate_pages(vm_map_t, long);
static void vm_swapout_object_deactivate_pages(pmap_t, vm_object_t, long);
static void swapout_procs(int action);
static void vm_req_vmdaemon(int req);
-static void vm_thread_swapin(struct thread *td);
static void vm_thread_swapout(struct thread *td);
/*
@@ -563,7 +564,7 @@ vm_thread_swapout(struct thread *td)
* Bring the kernel stack for a specified thread back in.
*/
static void
-vm_thread_swapin(struct thread *td)
+vm_thread_swapin(struct thread *td, int oom_alloc)
{
vm_object_t ksobj;
vm_page_t ma[KSTACK_MAX_PAGES];
@@ -572,7 +573,7 @@ vm_thread_swapin(struct thread *td)
pages = td->td_kstack_pages;
ksobj = td->td_kstack_obj;
VM_OBJECT_WLOCK(ksobj);
- (void)vm_page_grab_pages(ksobj, 0, VM_ALLOC_NORMAL | VM_ALLOC_WIRED, ma,
+ (void)vm_page_grab_pages(ksobj, 0, oom_alloc | VM_ALLOC_WIRED, ma,
pages);
for (i = 0; i < pages;) {
vm_page_assert_xbusied(ma[i]);
@@ -605,8 +606,10 @@ void
faultin(struct proc *p)
{
struct thread *td;
+ int oom_alloc;
PROC_LOCK_ASSERT(p, MA_OWNED);
+
/*
* If another process is swapping in this process,
* just wait until it finishes.
@@ -616,7 +619,11 @@ faultin(struct proc *p)
msleep(&p->p_flag, &p->p_mtx, PVM, "faultin", 0);
return;
}
+
if ((p->p_flag & P_INMEM) == 0) {
+ oom_alloc = (p->p_flag & P_WKILLED) != 0 ? VM_ALLOC_SYSTEM :
+ VM_ALLOC_NORMAL;
+
/*
* Don't let another thread swap process p out while we are
* busy swapping it in.
@@ -624,6 +631,10 @@ faultin(struct proc *p)
++p->p_lock;
p->p_flag |= P_SWAPPINGIN;
PROC_UNLOCK(p);
+ sx_xlock(&allproc_lock);
+ MPASS(swapped_cnt > 0);
+ swapped_cnt--;
+ sx_xunlock(&allproc_lock);
/*
* We hold no lock here because the list of threads
@@ -631,14 +642,14 @@ faultin(struct proc *p)
* swapped out.
*/
FOREACH_THREAD_IN_PROC(p, td)
- vm_thread_swapin(td);
+ vm_thread_swapin(td, oom_alloc);
+
PROC_LOCK(p);
swapclear(p);
p->p_swtick = ticks;
- wakeup(&p->p_flag);
-
/* Allow other threads to swap p out now. */
+ wakeup(&p->p_flag);
--p->p_lock;
}
}
@@ -648,26 +659,38 @@ faultin(struct proc *p)
* is enough space for them. Of course, if a process waits for a long
* time, it will be swapped in anyway.
*/
-void
-swapper(void)
+
+static struct proc *
+swapper_selector(void)
{
- struct proc *p, *pp;
+ struct proc *p, *res;
struct thread *td;
- int ppri, pri, slptime, swtime;
-
-loop:
- if (vm_page_count_min()) {
- vm_wait_min();
- goto loop;
- }
+ int min_flag, ppri, pri, slptime, swtime;
- pp = NULL;
+ sx_assert(&allproc_lock, SA_SLOCKED);
+ if (swapped_cnt == 0)
+ return (NULL);
+ res = NULL;
ppri = INT_MIN;
- sx_slock(&allproc_lock);
+ min_flag = vm_page_count_min();
FOREACH_PROC_IN_SYSTEM(p) {
PROC_LOCK(p);
- if (p->p_state == PRS_NEW ||
- p->p_flag & (P_SWAPPINGOUT | P_SWAPPINGIN | P_INMEM)) {
+ if (p->p_state == PRS_NEW || (p->p_flag & (P_SWAPPINGOUT |
+ P_SWAPPINGIN | P_INMEM)) != 0) {
+ PROC_UNLOCK(p);
+ continue;
+ }
+ if (p->p_state == PRS_NORMAL && (p->p_flag & P_WKILLED) != 0) {
+ /*
+ * A swapped-out process might have mapped a
+ * large portion of the system's pages as
+ * anonymous memory. There is no other way to
+ * release the memory other than to kill the
+ * process, for which we need to swap it in.
+ */
+ return (p);
+ }
+ if (min_flag) {
PROC_UNLOCK(p);
continue;
}
@@ -690,7 +713,7 @@ loop:
* selection.
*/
if (pri > ppri) {
- pp = p;
+ res = p;
ppri = pri;
}
}
@@ -698,33 +721,40 @@ loop:
}
PROC_UNLOCK(p);
}
- sx_sunlock(&allproc_lock);
+ if (res != NULL)
+ PROC_LOCK(res);
+ return (res);
+}
- /*
- * Nothing to do, back to sleep.
- */
- if ((p = pp) == NULL) {
- tsleep(&proc0, PVM, "swapin", MAXSLP * hz / 2);
- goto loop;
- }
- PROC_LOCK(p);
+void
+swapper(void)
+{
+ struct proc *p;
- /*
- * Another process may be bringing or may have already
- * brought this process in while we traverse all threads.
- * Or, this process may even be being swapped out again.
- */
- if (p->p_flag & (P_INMEM | P_SWAPPINGOUT | P_SWAPPINGIN)) {
- PROC_UNLOCK(p);
- goto loop;
- }
+ for (;;) {
+ sx_slock(&allproc_lock);
+ p = swapper_selector();
+ sx_sunlock(&allproc_lock);
- /*
- * We would like to bring someone in.
- */
- faultin(p);
- PROC_UNLOCK(p);
- goto loop;
+ if (p == NULL) {
+ tsleep(&proc0, PVM, "swapin", MAXSLP * hz / 2);
+ } else {
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ /*
+ * Another process may be bringing or may have
+ * already brought this process in while we
+ * traverse all threads. Or, this process may
+ * have exited or even being swapped out
+ * again.
+ */
+ if (p->p_state == PRS_NORMAL && (p->p_flag & (P_INMEM |
+ P_SWAPPINGOUT | P_SWAPPINGIN)) == 0) {
+ faultin(p);
+ }
+ PROC_UNLOCK(p);
+ }
+ }
}
/*
@@ -803,7 +833,12 @@ swapout_procs(int action)
didswap = true;
PROC_UNLOCK(p);
- sx_slock(&allproc_lock);
+ if (didswap) {
+ sx_xlock(&allproc_lock);
+ swapped_cnt++;
+ sx_downgrade(&allproc_lock);
+ } else
+ sx_slock(&allproc_lock);
PRELE(p);
}
sx_sunlock(&allproc_lock);