From cb3ee63add04c3a8de3c9e9efbbe3a498ee80f1d Mon Sep 17 00:00:00 2001 From: mpi Date: Fri, 27 Oct 2023 19:18:53 +0000 Subject: [PATCH] Make out-of-swap checks more robust. Consider that the swap space is full when 99% of it is filled with pages that are no longer present in memory. This prevents deadlocks when out-of-swap if some swap ranges had I/O errors and have been marked as 'bad', or if some pages are unreachable by the pagedaemon and still holding some slots. Also introduce uvm_swapisfilled() to check if there are some free slots in the swap. Note that we consider the swap space completly filled if it is not possible to write a full cluster. This prevents deadlocks if a few slots are never allocated. ok miod@ --- sys/uvm/uvm_pdaemon.c | 11 +++-------- sys/uvm/uvm_swap.c | 30 ++++++++++++++++++++++++++---- sys/uvm/uvm_swap.h | 3 ++- sys/uvm/uvmexp.h | 4 ++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/sys/uvm/uvm_pdaemon.c b/sys/uvm/uvm_pdaemon.c index 445102eed80..1b99b190c92 100644 --- a/sys/uvm/uvm_pdaemon.c +++ b/sys/uvm/uvm_pdaemon.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pdaemon.c,v 1.108 2023/10/24 10:00:22 mpi Exp $ */ +/* $OpenBSD: uvm_pdaemon.c,v 1.109 2023/10/27 19:18:53 mpi Exp $ */ /* $NetBSD: uvm_pdaemon.c,v 1.23 2000/08/20 10:24:14 bjh21 Exp $ */ /* @@ -595,11 +595,8 @@ uvmpd_scan_inactive(struct uvm_pmalloc *pma, * is full, free any swap allocated to the page * so that other pages can be paged out. */ - KASSERT(uvmexp.swpginuse <= uvmexp.swpages); - if ((p->pg_flags & PQ_SWAPBACKED) && - uvmexp.swpginuse == uvmexp.swpages) { + if ((p->pg_flags & PQ_SWAPBACKED) && uvm_swapisfilled()) uvmpd_dropswap(p); - } /* * the page we are looking at is dirty. we must @@ -917,9 +914,7 @@ uvmpd_scan(struct uvm_pmalloc *pma, struct uvm_constraint_range *constraint) */ free = uvmexp.free - BUFPAGES_DEFICIT; swap_shortage = 0; - if (free < uvmexp.freetarg && - uvmexp.swpginuse == uvmexp.swpages && - !uvm_swapisfull() && + if (free < uvmexp.freetarg && uvm_swapisfilled() && !uvm_swapisfull() && pages_freed == 0) { swap_shortage = uvmexp.freetarg - free; } diff --git a/sys/uvm/uvm_swap.c b/sys/uvm/uvm_swap.c index 27963259eba..1818cc06384 100644 --- a/sys/uvm/uvm_swap.c +++ b/sys/uvm/uvm_swap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_swap.c,v 1.166 2023/01/10 11:18:47 kettenis Exp $ */ +/* $OpenBSD: uvm_swap.c,v 1.167 2023/10/27 19:18:53 mpi Exp $ */ /* $NetBSD: uvm_swap.c,v 1.40 2000/11/17 11:39:39 mrg Exp $ */ /* @@ -1516,8 +1516,30 @@ ReTry: /* XXXMRG */ } /* - * uvm_swapisfull: return true if all of available swap is allocated - * and in use. + * uvm_swapisfilled: return true if the amount of free space in swap is + * smaller than the size of a cluster. + * + * As long as some swap slots are being used by pages currently in memory, + * it is possible to reuse them. Even if the swap space has been completly + * filled we do not consider it full. + */ +int +uvm_swapisfilled(void) +{ + int result; + + mtx_enter(&uvm_swap_data_lock); + KASSERT(uvmexp.swpginuse <= uvmexp.swpages); + result = (uvmexp.swpginuse + SWCLUSTPAGES) >= uvmexp.swpages; + mtx_leave(&uvm_swap_data_lock); + + return result; +} + +/* + * uvm_swapisfull: return true if the amount of pages only in swap + * accounts for more than 99% of the total swap space. + * */ int uvm_swapisfull(void) @@ -1526,7 +1548,7 @@ uvm_swapisfull(void) mtx_enter(&uvm_swap_data_lock); KASSERT(uvmexp.swpgonly <= uvmexp.swpages); - result = (uvmexp.swpgonly == uvmexp.swpages); + result = (uvmexp.swpgonly >= (uvmexp.swpages * 99 / 100)); mtx_leave(&uvm_swap_data_lock); return result; diff --git a/sys/uvm/uvm_swap.h b/sys/uvm/uvm_swap.h index 9904fe58cd7..58b0bfc9a61 100644 --- a/sys/uvm/uvm_swap.h +++ b/sys/uvm/uvm_swap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_swap.h,v 1.19 2022/06/28 19:19:34 mpi Exp $ */ +/* $OpenBSD: uvm_swap.h,v 1.20 2023/10/27 19:18:53 mpi Exp $ */ /* $NetBSD: uvm_swap.h,v 1.5 2000/01/11 06:57:51 chs Exp $ */ /* @@ -42,6 +42,7 @@ int uvm_swap_put(int, struct vm_page **, int, int); int uvm_swap_alloc(int *, boolean_t); void uvm_swap_free(int, int); void uvm_swap_markbad(int, int); +int uvm_swapisfilled(void); int uvm_swapisfull(void); void uvm_swap_freepages(struct vm_page **, int); #ifdef HIBERNATE diff --git a/sys/uvm/uvmexp.h b/sys/uvm/uvmexp.h index de5f5fa367c..7d0225786fd 100644 --- a/sys/uvm/uvmexp.h +++ b/sys/uvm/uvmexp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvmexp.h,v 1.10 2022/08/29 11:09:31 mpi Exp $ */ +/* $OpenBSD: uvmexp.h,v 1.11 2023/10/27 19:18:53 mpi Exp $ */ #ifndef _UVM_UVMEXP_ #define _UVM_UVMEXP_ @@ -83,7 +83,7 @@ struct uvmexp { /* swap */ int nswapdev; /* [S] number of configured swap devices in system */ int swpages; /* [S] number of PAGE_SIZE'ed swap pages */ - int swpginuse; /* [K] number of swap pages in use */ + int swpginuse; /* [S] number of swap pages in use */ int swpgonly; /* [a] number of swap pages in use, not also in RAM */ int nswget; /* [a] number of swap pages moved from disk to RAM */ int nanon; /* XXX number total of anon's in system */ -- 2.20.1