git: 2b4a45992a04 - stable/13 - fusefs: FUSE_NOTIFY_INVAL_* must busy the mountpoint

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Mon, 20 Jan 2025 22:33:10 UTC
The branch stable/13 has been updated by asomers:

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

commit 2b4a45992a043459ab0d63410059822a2efb6045
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2024-12-13 14:00:20 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2025-01-20 22:31:29 +0000

    fusefs: FUSE_NOTIFY_INVAL_* must busy the mountpoint
    
    Unusually, the FUSE_NOTIFY_INVAL_INODE and FUSE_NOTIFY_INVAL_ENTRY
    messages are fully asynchronous.  The server sends them to the kernel
    unsolicited.  That means that unlike every other fuse message coming
    from the server, these two arrive to a potentially unbusied mountpoint.
    So they must explicitly busy it.  Otherwise a page fault could result if
    the mountpoint were being unmounted.
    
    Reported by:    JSML4ThWwBID69YC@protonmail.com
    
    (cherry picked from commit 989998529387b4d98dfaa6c499ad88b006f78de8)
---
 sys/fs/fuse/fuse_device.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c
index 88ebe702ec0a..7b163bc04bc2 100644
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -440,7 +440,6 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
 	err = devfs_get_cdevpriv((void **)&data);
 	if (err != 0)
 		return (err);
-	mp = data->mp;
 
 	if (uio->uio_resid < sizeof(struct fuse_out_header)) {
 		SDT_PROBE2(fusefs, , device, trace, 1,
@@ -543,6 +542,13 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
 	} else if (ohead.unique == 0){
 		/* unique == 0 means asynchronous notification */
 		SDT_PROBE1(fusefs, , device, fuse_device_write_notify, &ohead);
+		mp = data->mp;
+		vfs_ref(mp);
+		err = vfs_busy(mp, 0);
+		vfs_rel(mp);
+		if (err)
+			return (err);
+
 		switch (ohead.error) {
 		case FUSE_NOTIFY_INVAL_ENTRY:
 			err = fuse_internal_invalidate_entry(mp, uio);
@@ -567,6 +573,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
 			/* Not implemented */
 			err = ENOSYS;
 		}
+		vfs_unbusy(mp);
 	} else {
 		/* no callback at all! */
 		SDT_PROBE1(fusefs, , device, fuse_device_write_missing_ticket,