git: d088dc76e1a6 - main - Fix NFS exports of FUSE file systems for big directories
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 04 Feb 2022 23:31:41 UTC
The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=d088dc76e1a62ecb6c05bd2b14ee48a9f9a7e2bd commit d088dc76e1a62ecb6c05bd2b14ee48a9f9a7e2bd Author: Alan Somers <asomers@FreeBSD.org> AuthorDate: 2022-01-02 17:18:47 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2022-02-04 23:30:49 +0000 Fix NFS exports of FUSE file systems for big directories The FUSE protocol does not require that a directory entry's d_off field outlive the lifetime of its directory's file handle. Since the NFS server must reopen the directory on every VOP_READDIR call, that means it can't pass uio->uio_offset down to the FUSE server. Instead, it must read the directory from 0 each time. It may need to issue multiple FUSE_READDIR operations until it finds the d_off field that it's looking for. That was the intention behind SVN r348209 and r297887, but a logic bug prevented subsequent FUSE_READDIR operations from ever being issued, rendering large directories incompletely browseable. MFC after: 3 weeks Reviewed by: rmacklem --- sys/fs/fuse/fuse_internal.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index 273b4f5b8522..eb8f1f87d90f 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -586,11 +586,7 @@ fuse_internal_readdir(struct vnode *vp, fnd_start = 1; while (uio_resid(uio) > 0) { fdi.iosize = sizeof(*fri); - if (fri == NULL) - fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); - else - fdisp_refresh_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); - + fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); fri = fdi.indata; fri->fh = fufh->fh_id; fri->offset = uio_offset(uio); @@ -628,6 +624,8 @@ fuse_internal_readdir_processdata(struct uio *uio, int err = 0; int oreclen; size_t freclen; + int ents_copied = 0; + int ents_seen = 0; struct dirent *de; struct fuse_dirent *fudge; @@ -638,7 +636,7 @@ fuse_internal_readdir_processdata(struct uio *uio, return -1; for (;;) { if (bufsize < FUSE_NAME_OFFSET) { - err = -1; + err = (ents_seen == 0 || ents_copied > 0) ? -1 : 0; break; } fudge = (struct fuse_dirent *)buf; @@ -649,7 +647,7 @@ fuse_internal_readdir_processdata(struct uio *uio, * This indicates a partial directory entry at the * end of the directory data. */ - err = -1; + err = (ents_seen == 0 || ents_copied > 0) ? -1 : 0; break; } #ifdef ZERO_PAD_INCOMPLETE_BUFS @@ -671,6 +669,7 @@ fuse_internal_readdir_processdata(struct uio *uio, err = -1; break; } + ents_seen++; /* * Don't start to copy the directory entries out until * the requested offset in the directory is found. @@ -702,6 +701,7 @@ fuse_internal_readdir_processdata(struct uio *uio, cookies++; (*ncookies)--; } + ents_copied++; } else if (startoff == fudge->off) *fnd_start = 1; buf = (char *)buf + freclen;