git: 1107834090be - main - swap_pager: swapoff detecting object death

From: Doug Moore <dougm_at_FreeBSD.org>
Date: Fri, 11 Oct 2024 17:48:19 UTC
The branch main has been updated by dougm:

URL: https://cgit.FreeBSD.org/src/commit/?id=1107834090be4df01070028f6a8cdb37ff1f51f1

commit 1107834090be4df01070028f6a8cdb37ff1f51f1
Author:     Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2024-10-11 17:45:54 +0000
Commit:     Doug Moore <dougm@FreeBSD.org>
CommitDate: 2024-10-11 17:45:54 +0000

    swap_pager: swapoff detecting object death
    
    In swap_pager_swapoff_object, the object is initially not dead, and
    can only become dead while the object lock is not held. Move the test
    for object-death so that it is right after the early loop-break that
    happens after lock re-acquisition, and before the iterator is
    re-initialized, which fails an assertion when the object is dead,
    and not swap.
    
    Addresses a problem produced in testing by @pho and diagnosed by @kib.
    
    Reported by:    pho
    Reviewed by:    alc, kib
    Differential Revision:  https://reviews.freebsd.org/D47064
---
 sys/vm/swap_pager.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index f4db46a32dee..23b5e1c34b07 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -1910,6 +1910,8 @@ swap_pager_swapoff_object(struct swdevt *sp, vm_object_t object)
 	VM_OBJECT_ASSERT_WLOCKED(object);
 	KASSERT((object->flags & OBJ_SWAP) != 0,
 	    ("%s: Object not swappable", __func__));
+	KASSERT((object->flags & OBJ_DEAD) == 0,
+	    ("%s: Object already dead", __func__));
 	KASSERT((sp->sw_flags & SW_CLOSING) != 0,
 	    ("%s: Device not blocking further allocations", __func__));
 
@@ -1917,15 +1919,6 @@ swap_pager_swapoff_object(struct swdevt *sp, vm_object_t object)
 	swp_pager_init_freerange(&range);
 	sb = swblk_iter_init(&blks, object, 0);
 	while (sb != NULL) {
-		if ((object->flags & OBJ_DEAD) != 0) {
-			/*
-			 * Make sure that pending writes finish before
-			 * returning.
-			 */
-			vm_object_pip_wait(object, "swpoff");
-			swp_pager_meta_free_all(object);
-			break;
-		}
 		sb_empty = true;
 		for (i = 0; i < SWAP_META_PAGES; i++) {
 			/* Skip an invalid block. */
@@ -1983,8 +1976,21 @@ swap_pager_swapoff_object(struct swdevt *sp, vm_object_t object)
 		}
 		if (i < SWAP_META_PAGES) {
 			/*
-			 * With the object lock released and regained, the
-			 * swapblk could have been freed, so reset the pages
+			 * The object lock has been released and regained.
+			 * Perhaps the object is now dead.
+			 */
+			if ((object->flags & OBJ_DEAD) != 0) {
+				/*
+				 * Make sure that pending writes finish before
+				 * returning.
+				 */
+				vm_object_pip_wait(object, "swpoff");
+				swp_pager_meta_free_all(object);
+				break;
+			}
+
+			/*
+			 * The swapblk could have been freed, so reset the pages
 			 * iterator and search again for the first swblk at or
 			 * after blks.index.
 			 */