The branch main has been updated by asomers:

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

commit d088dc76e1a62ecb6c05bd2b14ee48a9f9a7e2bd
Author:     Alan Somers <[email protected]>
AuthorDate: 2022-01-02 17:18:47 +0000
Commit:     Alan Somers <[email protected]>
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;

Reply via email to