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;
}