git: 75734c4360fc - main - tmpfs: check residence in data_locked

From: Doug Moore <dougm_at_FreeBSD.org>
Date: Fri, 04 Oct 2024 07:45:43 UTC
The branch main has been updated by dougm:

URL: https://cgit.FreeBSD.org/src/commit/?id=75734c4360fcd5c70ab9650683ae47ca11aea15f

commit 75734c4360fcd5c70ab9650683ae47ca11aea15f
Author:     Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2024-10-04 07:44:19 +0000
Commit:     Doug Moore <dougm@FreeBSD.org>
CommitDate: 2024-10-04 07:44:19 +0000

    tmpfs: check residence in data_locked
    
    tmpfs_seek_data_locked should return the offset of the first page
    either resident in memory or in swap, but may return an offset to a
    nonresident page. Check for residence to fix that.
    
    Reviewed by:    alc, kib
    Differential Revision:  https://reviews.freebsd.org/D46879
---
 sys/fs/tmpfs/tmpfs_vnops.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index b278c3153863..fa9945a9074a 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -2099,7 +2099,7 @@ static off_t
 tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
 {
 	vm_page_t m;
-	vm_pindex_t p, p_m, p_swp;
+	vm_pindex_t p, p_swp;
 
 	p = OFF_TO_IDX(noff);
 	m = vm_page_find_least(obj, p);
@@ -2108,15 +2108,24 @@ tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
 	 * Microoptimize the most common case for SEEK_DATA, where
 	 * there is no hole and the page is resident.
 	 */
-	if (m != NULL && vm_page_any_valid(m) && m->pindex == p)
+	if (m != NULL && m->pindex == p && vm_page_any_valid(m))
 		return (noff);
 
 	p_swp = swap_pager_find_least(obj, p);
 	if (p_swp == p)
 		return (noff);
 
-	p_m = m == NULL ? obj->size : m->pindex;
-	return (IDX_TO_OFF(MIN(p_m, p_swp)));
+	/*
+	 * Find the first resident page after p, before p_swp.
+	 */
+	while (m != NULL && m->pindex < p_swp) {
+		if (vm_page_any_valid(m))
+			return (IDX_TO_OFF(m->pindex));
+		m = TAILQ_NEXT(m, listq);
+	}
+	if (p_swp == OBJ_MAX_SIZE)
+		p_swp = obj->size;
+	return (IDX_TO_OFF(p_swp));
 }
 
 static off_t