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)
This commit is contained in:
Alan Somers 2024-12-13 07:00:20 -07:00
parent 980eedb0ca
commit b797d07560

View file

@ -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,