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;
 }
 
 /*

Reply via email to