git: 989998529387 - main - fusefs: FUSE_NOTIFY_INVAL_* must busy the mountpoint

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Fri, 13 Dec 2024 14:08:35 UTC
The branch main has been updated by asomers:

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

commit 989998529387b4d98dfaa6c499ad88b006f78de8
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2024-12-13 14:00:20 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2024-12-13 14:08:30 +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
    MFC after:      2 weeks
---
 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 087316e86e90..0a5da63c1f54 100644
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -439,7 +439,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,
@@ -542,6 +541,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);
@@ -566,6 +572,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,