git: a4ebad0c202f - stable/14 - fusefs: better handling for low-memory conditions

Alan Somers <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a729d50.3ace4.75ad93e2__37372.0244782575$1785896293$gmane$org@gitrepo.freebsd.org>
The branch stable/14 has been updated by asomers:

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

commit a4ebad0c202f5c2d08381d2ac732729cd386388f
Author:     Alan Somers <[email protected]>
AuthorDate: 2026-03-30 14:22:07 +0000
Commit:     Alan Somers <[email protected]>
CommitDate: 2026-08-05 01:55:00 +0000

    fusefs: better handling for low-memory conditions
    
    Under conditions of low memory, getblk can fail.  fusefs was not
    handling those failures very systematically.  It was always using
    PCATCH, which appears to have been originally copy/pasted from the NFS
    client code, but isn't always appropriate:
    
    * During fuse_vnode_setsize_immediate, which can be called from many
      different VOPs and from the vn_delayed_setsize mechanism, remove
      PCATCH.  Some of these callers cannot tolerate allocate failure.
    
    * In fuse_inval_buf_range, don't assume that getblk will always succeed.
    
    * When calling fuse_inval_buf_range from VOP_ALLOCATE,
      VOP_COPY_FILE_RANGE, or VOP_WRITE (with IO_DIRECT), return EINTR if
      the allocation fails.
    
    * When calling fuse_inval_buf_range from VOP_DEALLOCATE, remove PCATCH.
      This VOP must not fail with EINTR.
    
    No new tests, because I can't force any particular getblk call to fail.
    
    PR:             293957
    Sponsored by:   ConnectWise
    Reported by:    [email protected]
    
    (cherry picked from commit 374548e930bd9452351059c14e697036d903b1c4)
---
 sys/fs/fuse/fuse_node.c  |  6 +-----
 sys/fs/fuse/fuse_vnops.c | 24 +++++++++++++++++-------
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/sys/fs/fuse/fuse_node.c b/sys/fs/fuse/fuse_node.c
index c0ec6b202c6e..3119e0096179 100644
--- a/sys/fs/fuse/fuse_node.c
+++ b/sys/fs/fuse/fuse_node.c
@@ -465,11 +465,7 @@ fuse_vnode_setsize(struct vnode *vp, off_t newsize, bool from_server)
 		 */
 
 		lbn = newsize / iosize;
-		bp = getblk(vp, lbn, iosize, PCATCH, 0, 0);
-		if (!bp) {
-			err = EINTR;
-			goto out;
-		}
+		bp = getblk(vp, lbn, iosize, 0, 0, 0);
 		if (!(bp->b_flags & B_CACHE))
 			goto out;	/* Nothing to do */
 		MPASS(bp->b_flags & B_VMIO);
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index ba72a21c8efe..ad246049949d 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -319,7 +319,8 @@ fuse_fifo_close(struct vop_close_args *ap)
 
 /* Invalidate a range of cached data, whether dirty of not */
 static int
-fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
+fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end,
+	int slpflag)
 {
 	struct buf *bp;
 	daddr_t left_lbn, end_lbn, right_lbn;
@@ -331,7 +332,9 @@ fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
 	end_lbn = howmany(end, iosize);
 	left_on = start & (iosize - 1);
 	if (left_on != 0) {
-		bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
+		bp = getblk(vp, left_lbn, iosize, slpflag, 0, 0);
+		if (!bp)
+			return (EINTR);
 		if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
 			/*
 			 * Flush the dirty buffer, because we don't have a
@@ -350,7 +353,9 @@ fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
 		right_lbn = end / iosize;
 		new_filesize = MAX(filesize, end);
 		right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
-		bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
+		bp = getblk(vp, right_lbn, right_blksize, slpflag, 0, 0);
+		if (!bp)
+			return (EINTR);
 		if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
 			/*
 			 * Flush the dirty buffer, because we don't have a
@@ -635,7 +640,10 @@ fuse_vnop_allocate(struct vop_allocate_args *ap)
 	err = fuse_vnode_size(vp, &filesize, cred, curthread);
 	if (err)
 		return (err);
-	fuse_inval_buf_range(vp, filesize, *offset, *offset + *len);
+	err = fuse_inval_buf_range(vp, filesize, *offset, *offset + *len,
+	    PCATCH);
+	if (err)
+		return (err);
 
 	fdisp_init(&fdi, sizeof(*ffi));
 	fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
@@ -919,7 +927,7 @@ fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
 
 	vnode_pager_clean_sync(invp);
 	err = fuse_inval_buf_range(outvp, outfilesize, *ap->a_outoffp,
-		*ap->a_outoffp + io.uio_resid);
+		*ap->a_outoffp + io.uio_resid, PCATCH);
 	if (err)
 		goto unlock;
 
@@ -2514,7 +2522,7 @@ fuse_vnop_write(struct vop_write_args *ap)
 		end = start + uio->uio_resid;
 		if (!pages) {
 			err = fuse_inval_buf_range(vp, filesize, start,
-			    end);
+			    end, PCATCH);
 			if (err)
 				goto out;
 		}
@@ -3031,7 +3039,9 @@ fuse_vnop_deallocate(struct vop_deallocate_args *ap)
 	err = fuse_vnode_size(vp, &filesize, cred, curthread);
 	if (err)
 		goto out;
-	fuse_inval_buf_range(vp, filesize, *offset, *offset + *len);
+	err = fuse_inval_buf_range(vp, filesize, *offset, *offset + *len, 0);
+	if (err)
+		goto out;
 
 	fdisp_init(&fdi, sizeof(*ffi));
 	fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.