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/84749f9257e1
branches: trunk
changeset: 942647:84749f9257e1
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 6ca876a2f6e8 -r 84749f9257e1 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 6ca876a2f6e8 -r 84749f9257e1 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