Module Name: src Committed By: martin Date: Sat Nov 14 13:01:55 UTC 2020
Modified Files: src/sys/coda [netbsd-9]: coda.h coda_vnops.c Log Message: Pull up following revision(s) (requested by hannken in ticket #1131): sys/coda/coda_vnops.c: revision 1.114 (patch) sys/coda/coda.h: revision 1.21 (patch) Rewrite coda_readdir() to directly process the container file. Passing this operation down to the file system holding the container cannot work for anything but UFS and UFS doesn't allow reading directory from a plain file since ~2015. Fixes PR kern/55775 Coda client, its in-kernel part, opens wrong files ... To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.20.6.1 src/sys/coda/coda.h cvs rdiff -u -r1.107 -r1.107.4.1 src/sys/coda/coda_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/coda/coda.h diff -u src/sys/coda/coda.h:1.20 src/sys/coda/coda.h:1.20.6.1 --- src/sys/coda/coda.h:1.20 Thu Apr 19 21:50:07 2018 +++ src/sys/coda/coda.h Sat Nov 14 13:01:55 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: coda.h,v 1.20 2018/04/19 21:50:07 christos Exp $ */ +/* $NetBSD: coda.h,v 1.20.6.1 2020/11/14 13:01:55 martin Exp $ */ /* @@ -61,6 +61,10 @@ Mellon the rights to redistribute these #define CODA_MAXSYMLINKS 10 #endif +#ifndef CODA_DIRBLKSIZ +#define CODA_DIRBLKSIZ 0x1000 +#endif + #if defined(DJGPP) || defined(__CYGWIN32__) #ifdef KERNEL typedef unsigned long u_long; @@ -169,7 +173,7 @@ struct venus_dirent { #ifndef _VENUS_DIRENT_T_ #define _VENUS_DIRENT_T_ 1 struct venus_dirent { - unsigned long d_fileno; /* file number of entry */ + unsigned int d_fileno; /* file number of entry */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* file type, see below */ unsigned char d_namlen; /* length of string in d_name */ Index: src/sys/coda/coda_vnops.c diff -u src/sys/coda/coda_vnops.c:1.107 src/sys/coda/coda_vnops.c:1.107.4.1 --- src/sys/coda/coda_vnops.c:1.107 Tue Nov 20 19:05:25 2018 +++ src/sys/coda/coda_vnops.c Sat Nov 14 13:01:55 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: coda_vnops.c,v 1.107 2018/11/20 19:05:25 christos Exp $ */ +/* $NetBSD: coda_vnops.c,v 1.107.4.1 2020/11/14 13:01:55 martin Exp $ */ /* * @@ -46,7 +46,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.107 2018/11/20 19:05:25 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.107.4.1 2020/11/14 13:01:55 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -62,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: coda_vnops.c #include <sys/select.h> #include <sys/vnode.h> #include <sys/kauth.h> +#include <sys/dirent.h> #include <miscfs/genfs/genfs.h> #include <miscfs/specfs/specdev.h> @@ -1526,70 +1527,143 @@ int coda_readdir(void *v) { /* true args */ - struct vop_readdir_args *ap = v; - vnode_t *vp = ap->a_vp; - struct cnode *cp = VTOC(vp); - struct uio *uiop = ap->a_uio; - kauth_cred_t cred = ap->a_cred; - int *eofflag = ap->a_eofflag; - off_t **cookies = ap->a_cookies; - int *ncookies = ap->a_ncookies; + struct vop_readdir_args *ap = v; + vnode_t *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct uio *uiop = ap->a_uio; + kauth_cred_t cred = ap->a_cred; + int *eofflag = ap->a_eofflag; /* upcall decl */ /* locals */ - int error = 0; - enum vtype saved_type; - - MARK_ENTRY(CODA_READDIR_STATS); - - CODADEBUG(CODA_READDIR, myprintf(("%s: (%p, %lu, %lld)\n", __func__, - uiop->uio_iov->iov_base, (unsigned long) uiop->uio_resid, - (long long) uiop->uio_offset)); ) - - /* Check for readdir of control object. */ - if (IS_CTL_VP(vp)) { - MARK_INT_FAIL(CODA_READDIR_STATS); - return(ENOENT); - } + size_t initial_resid = uiop->uio_resid; + int error = 0; + int opened_internally = 0; + int ncookies; + char *buf; + struct vnode *cvp; + struct dirent *dirp; + + MARK_ENTRY(CODA_READDIR_STATS); + + CODADEBUG(CODA_READDIR, myprintf(("%s: (%p, %lu, %lld)\n", __func__, + uiop->uio_iov->iov_base, (unsigned long) uiop->uio_resid, + (long long) uiop->uio_offset)); ) - { - /* Redirect the request to UFS. */ + /* Check for readdir of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CODA_READDIR_STATS); + return ENOENT; + } /* If directory is not already open do an "internal open" on it. */ - int opened_internally = 0; if (cp->c_ovp == NULL) { - opened_internally = 1; - MARK_INT_GEN(CODA_OPEN_STATS); - error = VOP_OPEN(vp, FREAD, cred); + opened_internally = 1; + MARK_INT_GEN(CODA_OPEN_STATS); + error = VOP_OPEN(vp, FREAD, cred); #ifdef CODA_VERBOSE - printf("%s: Internally Opening %p\n", __func__, vp); + printf("%s: Internally Opening %p\n", __func__, vp); #endif - if (error) return(error); - } else - vp = cp->c_ovp; + if (error) + return error; + KASSERT(cp->c_ovp != NULL); + } + cvp = cp->c_ovp; - /* Have UFS handle the call. */ CODADEBUG(CODA_READDIR, myprintf(("%s: fid = %s, refcnt = %d\n", - __func__, coda_f2s(&cp->c_fid), vp->v_usecount)); ) - saved_type = vp->v_type; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - vp->v_type = VDIR; /* pretend the container file is a dir */ - error = VOP_READDIR(vp, uiop, cred, eofflag, cookies, ncookies); - vp->v_type = saved_type; - VOP_UNLOCK(vp); + __func__, coda_f2s(&cp->c_fid), cvp->v_usecount)); ) + + if (ap->a_ncookies) { + ncookies = ap->a_uio->uio_resid / _DIRENT_RECLEN(dirp, 1); + *ap->a_ncookies = 0; + *ap->a_cookies = malloc(ncookies * sizeof (off_t), + M_TEMP, M_WAITOK); + } + buf = kmem_alloc(CODA_DIRBLKSIZ, KM_SLEEP); + dirp = kmem_alloc(sizeof(*dirp), KM_SLEEP); + vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY); + + while (error == 0) { + size_t resid = 0; + char *dp, *ep; + + if (!ALIGNED_POINTER(uiop->uio_offset, uint32_t)) { + error = EINVAL; + break; + } + error = vn_rdwr(UIO_READ, cvp, buf, + CODA_DIRBLKSIZ, uiop->uio_offset, + UIO_SYSSPACE, IO_NODELOCKED, cred, &resid, curlwp); + if (error || resid == CODA_DIRBLKSIZ) + break; + for (dp = buf, ep = dp + CODA_DIRBLKSIZ - resid; dp < ep; ) { + off_t off; + struct venus_dirent *vd = (struct venus_dirent *)dp; + + if (!ALIGNED_POINTER(vd, uint32_t) || + !ALIGNED_POINTER(vd->d_reclen, uint32_t) || + vd->d_reclen == 0) { + error = EINVAL; + break; + } + if (dp + vd->d_reclen > ep) { + error = ENAMETOOLONG; + break; + } + if (vd->d_namlen == 0) { + uiop->uio_offset += vd->d_reclen; + dp += vd->d_reclen; + continue; + } + dirp->d_fileno = vd->d_fileno; + dirp->d_type = vd->d_type; + dirp->d_namlen = vd->d_namlen; + dirp->d_reclen = _DIRENT_SIZE(dirp); + strlcpy(dirp->d_name, vd->d_name, dirp->d_namlen + 1); + + if (uiop->uio_resid < dirp->d_reclen) { + error = ENAMETOOLONG; + break; + } + + off = uiop->uio_offset; + error = uiomove(dirp, dirp->d_reclen, uiop); + uiop->uio_offset = off; + if (error) + break; + + uiop->uio_offset += vd->d_reclen; + dp += vd->d_reclen; + if (ap->a_ncookies) + (*ap->a_cookies)[(*ap->a_ncookies)++] = + uiop->uio_offset; + } + } + + VOP_UNLOCK(cvp); + kmem_free(dirp, sizeof(*dirp)); + kmem_free(buf, CODA_DIRBLKSIZ); + if (eofflag && error == 0) + *eofflag = 1; + if (uiop->uio_resid < initial_resid && error == ENAMETOOLONG) + error = 0; + if (ap->a_ncookies && error) { + free(*ap->a_cookies, M_TEMP); + *ap->a_ncookies = 0; + *ap->a_cookies = NULL; + } if (error) - MARK_INT_FAIL(CODA_READDIR_STATS); + MARK_INT_FAIL(CODA_READDIR_STATS); else - MARK_INT_SAT(CODA_READDIR_STATS); + MARK_INT_SAT(CODA_READDIR_STATS); /* Do an "internal close" if necessary. */ if (opened_internally) { - MARK_INT_GEN(CODA_CLOSE_STATS); - (void)VOP_CLOSE(vp, FREAD, cred); + MARK_INT_GEN(CODA_CLOSE_STATS); + (void)VOP_CLOSE(vp, FREAD, cred); } - } - return(error); + return error; } /*