Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/coda Rewrite coda_readdir() to directly process the cont...



details:   https://anonhg.NetBSD.org/src/rev/990d5f75db74
branches:  trunk
changeset: 946018:990d5f75db74
user:      hannken <hannken%NetBSD.org@localhost>
date:      Sat Nov 14 11:42:56 2020 +0000

description:
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 ...

diffstat:

 sys/coda/coda.h       |    8 +-
 sys/coda/coda_vnops.c |  168 ++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 127 insertions(+), 49 deletions(-)

diffs (244 lines):

diff -r d791e07d537a -r 990d5f75db74 sys/coda/coda.h
--- a/sys/coda/coda.h   Sat Nov 14 11:42:05 2020 +0000
+++ b/sys/coda/coda.h   Sat Nov 14 11:42:56 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: coda.h,v 1.20 2018/04/19 21:50:07 christos Exp $ */
+/* $NetBSD: coda.h,v 1.21 2020/11/14 11:42:56 hannken Exp $ */
 
 /*
 
@@ -61,6 +61,10 @@
 #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 @@
 #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 */
diff -r d791e07d537a -r 990d5f75db74 sys/coda/coda_vnops.c
--- a/sys/coda/coda_vnops.c     Sat Nov 14 11:42:05 2020 +0000
+++ b/sys/coda/coda_vnops.c     Sat Nov 14 11:42:56 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: coda_vnops.c,v 1.113 2020/11/14 11:42:05 hannken Exp $ */
+/*     $NetBSD: coda_vnops.c,v 1.114 2020/11/14 11:42:56 hannken Exp $ */
 
 /*
  *
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.113 2020/11/14 11:42:05 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.114 2020/11/14 11:42:56 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -62,6 +62,7 @@
 #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>
@@ -1528,70 +1529,143 @@
 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;
+       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)); )
+       MARK_ENTRY(CODA_READDIR_STATS);
 
-    /* Check for readdir of control object. */
-    if (IS_CTL_VP(vp)) {
-       MARK_INT_FAIL(CODA_READDIR_STATS);
-       return(ENOENT);
-    }
+       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;
+
+       CODADEBUG(CODA_READDIR, myprintf(("%s: fid = %s, refcnt = %d\n",
+           __func__, coda_f2s(&cp->c_fid), vrefcnt(cvp))); )
+
+       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;
 
-       /* Have UFS handle the call. */
-       CODADEBUG(CODA_READDIR, myprintf(("%s: fid = %s, refcnt = %d\n",
-           __func__, coda_f2s(&cp->c_fid), vrefcnt(vp))); )
-       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);
+                       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;
 }
 
 /*



Home | Main Index | Thread Index | Old Index