git: 353ba3bf08fd - main - vm_object_coalesce(): do not account holes twice

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 30 Dec 2025 03:25:51 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=353ba3bf08fdef69b77e3e565435e50784a51412

commit 353ba3bf08fdef69b77e3e565435e50784a51412
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-11-27 21:53:24 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-12-30 03:25:36 +0000

    vm_object_coalesce(): do not account holes twice
    
    alc wrote:
    Suppose that the object is OBJ_ONEMAPPING and that we, in fact,
    have a single mapping to it. Then, we punch a hole in that mapping.
    vm_map_entry_delete() only subtracts from the object's charge when
    we shrink the size of the object. Now, suppose that we perform
    mmap(MAP_ANON) to reallocate some of the hole. Aren't we going to add to
    the charge here, even though vm_map_entry_delete() never subtracted from
    the charge for the hole that was created?
    
    Only account the change in the charged object size that was added to it.
    
    Noted by:       alc
    Reviewed by:    alc, markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54263
---
 sys/vm/vm_object.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 36edb279bbce..c216fdc01af1 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -2202,7 +2202,8 @@ vm_object_coalesce(vm_object_t prev_object, vm_ooffset_t prev_offset,
 	/*
 	 * Account for the charge.
 	 */
-	if (prev_object->cred != NULL) {
+	if (prev_object->cred != NULL &&
+	    next_pindex + next_size > prev_object->size) {
 		/*
 		 * If prev_object was charged, then this mapping,
 		 * although not charged now, may become writable
@@ -2213,12 +2214,14 @@ vm_object_coalesce(vm_object_t prev_object, vm_ooffset_t prev_offset,
 		 * entry, and swap reservation for this entry is
 		 * managed in appropriate time.
 		 */
-		if (!reserved && !swap_reserve_by_cred(ptoa(next_size),
-		    prev_object->cred)) {
+		vm_size_t charge = ptoa(next_pindex + next_size -
+		    prev_object->size);
+		if (!reserved &&
+		    !swap_reserve_by_cred(charge, prev_object->cred)) {
 			VM_OBJECT_WUNLOCK(prev_object);
 			return (FALSE);
 		}
-		prev_object->charge += ptoa(next_size);
+		prev_object->charge += charge;
 	}
 
 	/*