The branch main has been updated by kib:

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

commit 011efaa5cd246a67bbe6e37364baa18178a9f7bd
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2025-08-01 08:22:14 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2025-08-01 16:48:53 +0000

    devfs readdir: handle short buffer same as UFS
    
    Return EINVAL if this is the first dirent encountered with the short
    buffer, or EJUSTRETURN if something was already copied out.
    
    This is needed to pass eof check in vop_readdir_post(): we are not at
    eof but resid was not advanced.
    
    Reported and tested by: pho (previous version)
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D51667
---
 sys/fs/devfs/devfs_vnops.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 1d744e6593c0..3a64c205186f 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -1450,6 +1450,7 @@ devfs_readdir(struct vop_readdir_args *ap)
        struct devfs_mount *dmp;
        off_t off;
        int *tmp_ncookies = NULL;
+       ssize_t startresid;
 
        if (ap->a_vp->v_type != VDIR)
                return (ENOTDIR);
@@ -1482,6 +1483,7 @@ devfs_readdir(struct vop_readdir_args *ap)
        error = 0;
        de = ap->a_vp->v_data;
        off = 0;
+       startresid = uio->uio_resid;
        TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
                KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, 
__LINE__));
                if (dd->de_flags & (DE_COVERED | DE_WHITEOUT))
@@ -1494,8 +1496,13 @@ devfs_readdir(struct vop_readdir_args *ap)
                        de = dd;
                dp = dd->de_dirent;
                MPASS(dp->d_reclen == GENERIC_DIRSIZ(dp));
-               if (dp->d_reclen > uio->uio_resid)
+               if (dp->d_reclen > uio->uio_resid) {
+                       /* Nothing was copied out, return EINVAL. */
+                       if (uio->uio_resid == startresid)
+                               error = EINVAL;
+                       /* Otherwise stop. */
                        break;
+               }
                dp->d_fileno = de->de_inode;
                /* NOTE: d_off is the offset for the *next* entry. */
                dp->d_off = off + dp->d_reclen;

Reply via email to