git: 4a6526d84a56 - main - fusefs: optimize NFS readdir for FUSE_NO_OPENDIR_SUPPORT
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 04 Feb 2022 23:31:42 UTC
The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=4a6526d84a56f398732bff491e63aa42f796a27d commit 4a6526d84a56f398732bff491e63aa42f796a27d Author: Alan Somers <asomers@FreeBSD.org> AuthorDate: 2022-01-02 22:29:50 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2022-02-04 23:30:58 +0000 fusefs: optimize NFS readdir for FUSE_NO_OPENDIR_SUPPORT In its lowest common denominator, FUSE does not require that a directory entry's d_off field is valid outside of the lifetime of the directory's FUSE file handle. But since NFS is stateless, it must reopen the directory on every call to VOP_READDIR. That means reading the directory all the way from the first entry. Not only does this create an O(n^2) condition for large directories, but it can also result in incorrect behavior if either: * The file system _does_ change the d_off field for the last directory entry previously seen by NFS, or * The file system deletes the last directory entry previously seen by NFS. Handily, for file systems that set FUSE_NO_OPENDIR_SUPPORT d_off is guaranteed to be valid for the lifetime of the directory entry, there is no need to read the directory from the start. MFC after: 3 weeks Reviewed by: rmacklem --- sys/fs/fuse/fuse_vnops.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 259925f54d9f..da925b5dcbb5 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1846,6 +1846,7 @@ fuse_vnop_readdir(struct vop_readdir_args *ap) struct uio *uio = ap->a_uio; struct ucred *cred = ap->a_cred; struct fuse_filehandle *fufh = NULL; + struct fuse_data *mpdata = fuse_get_mpdata(vnode_mount(vp)); struct fuse_iov cookediov; int err = 0; uint64_t *cookies; @@ -1874,13 +1875,14 @@ fuse_vnop_readdir(struct vop_readdir_args *ap) * must implicitly open the directory here */ err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred); - if (err == 0) { + if (err == 0 && !(mpdata->dataflags & FSESS_NO_OPEN_SUPPORT)) { /* - * When a directory is opened, it must be read from - * the beginning. Hopefully, the "startoff" still - * exists as an offset cookie for the directory. - * If not, it will read the entire directory without - * returning any entries and just return eof. + * FUSE does not require a directory entry's d_off + * field to be valid outside of the lifetime of the + * directory's FUSE file handle. So we must read the + * directory from the beginning. However, if the file + * system sets FUSE_NO_OPENDIR_SUPPORT, then the d_off + * field will be valid for the lifetime of the dirent. */ uio->uio_offset = 0; }