Date: Tue, 27 Jun 2006 19:51:32 GMT From: John Baldwin <jhb@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 100167 for review Message-ID: <200606271951.k5RJpWPr092469@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=100167 Change 100167 by jhb@jhb_mutex on 2006/06/27 19:50:52 Add a kern_getdirentries() and convert getdirentries(), getdents(), and ogetdirentries() to use it. ogetdirentries() is crufty and involved some mild pain. Affected files ... .. //depot/projects/smpng/sys/kern/vfs_syscalls.c#107 edit .. //depot/projects/smpng/sys/sys/syscallsubr.h#31 edit Differences ... ==== //depot/projects/smpng/sys/kern/vfs_syscalls.c#107 (text+ko) ==== @@ -3563,144 +3563,67 @@ long *basep; } */ *uap; { - struct vnode *vp; - struct file *fp; - struct uio auio, kuio; - struct iovec aiov, kiov; struct dirent *dp, *edp; - caddr_t dirbuf; - int error, eofflag, readcnt, vfslocked; - long loff; + char *dirbuf; + int error, readcnt, ufs_43; + long base; /* XXX arbitrary sanity limit on `count'. */ if (uap->count > 64 * 1024) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) - return (error); - if ((fp->f_flag & FREAD) == 0) { - fdrop(fp, td); - return (EBADF); - } - vp = fp->f_vnode; -unionread: - vfslocked = VFS_LOCK_GIANT(vp->v_mount); - if (vp->v_type != VDIR) { - VFS_UNLOCK_GIANT(vfslocked); - fdrop(fp, td); - return (EINVAL); - } - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; - auio.uio_resid = uap->count; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - loff = auio.uio_offset = fp->f_offset; -#ifdef MAC - error = mac_check_vnode_readdir(td->td_ucred, vp); + + dirbuf = malloc(uap->count, M_TEMP, M_WAITOK); + error = kern_getdirentries(td, uap->fd, dirbuf, uap->count, &base, + UIO_SYSSPACE, &ufs_43); if (error) { - VOP_UNLOCK(vp, 0, td); - VFS_UNLOCK_GIANT(vfslocked); - fdrop(fp, td); + free(dirbuf, M_TEMP); return (error); } -#endif + + readcnt = td->td_retval[0]; # if (BYTE_ORDER != LITTLE_ENDIAN) - if (vp->v_mount->mnt_maxsymlinklen <= 0) { - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, - NULL, NULL); - fp->f_offset = auio.uio_offset; - } else + /* + * On big endian systems, we can return the contents from a 4.3 + * UFS without performing a fixup. + */ + if (!ufs_43) { +# else + { # endif - { - kuio = auio; - kuio.uio_iov = &kiov; - kuio.uio_segflg = UIO_SYSSPACE; - kiov.iov_len = uap->count; - MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); - kiov.iov_base = dirbuf; - error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, - NULL, NULL); - fp->f_offset = kuio.uio_offset; - if (error == 0) { - readcnt = uap->count - kuio.uio_resid; - edp = (struct dirent *)&dirbuf[readcnt]; - for (dp = (struct dirent *)dirbuf; dp < edp; ) { -# if (BYTE_ORDER == LITTLE_ENDIAN) - /* - * The expected low byte of - * dp->d_namlen is our dp->d_type. - * The high MBZ byte of dp->d_namlen - * is our dp->d_namlen. - */ - dp->d_type = dp->d_namlen; - dp->d_namlen = 0; -# else - /* - * The dp->d_type is the high byte - * of the expected dp->d_namlen, - * so must be zero'ed. - */ - dp->d_type = 0; -# endif - if (dp->d_reclen > 0) { - dp = (struct dirent *) - ((char *)dp + dp->d_reclen); - } else { - error = EIO; - break; - } + edp = (struct dirent *)&dirbuf[readcnt]; + for (dp = (struct dirent *)dirbuf; dp < edp; ) { +# if (BYTE_ORDER == LITTLE_ENDIAN) + /* + * The expected low byte of + * dp->d_namlen is our dp->d_type. + * The high MBZ byte of dp->d_namlen + * is our dp->d_namlen. + */ + dp->d_type = dp->d_namlen; + dp->d_namlen = 0; +# else + /* + * The dp->d_type is the high byte + * of the expected dp->d_namlen, + * so must be zero'ed. + */ + dp->d_type = 0; +# endif + if (dp->d_reclen > 0) { + dp = (struct dirent *) + ((char *)dp + dp->d_reclen); + } else { + error = EIO; + break; } - if (dp >= edp) - error = uiomove(dirbuf, readcnt, &auio); } - FREE(dirbuf, M_TEMP); } - VOP_UNLOCK(vp, 0, td); - if (error) { - VFS_UNLOCK_GIANT(vfslocked); - fdrop(fp, td); - return (error); - } - if (uap->count == auio.uio_resid) { - if (union_dircheckp) { - error = union_dircheckp(td, &vp, fp); - if (error == -1) { - VFS_UNLOCK_GIANT(vfslocked); - goto unionread; - } - if (error) { - VFS_UNLOCK_GIANT(vfslocked); - fdrop(fp, td); - return (error); - } - } - /* - * XXX We could delay dropping the lock above but - * union_dircheckp complicates things. - */ - vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, td); - if ((vp->v_vflag & VV_ROOT) && - (vp->v_mount->mnt_flag & MNT_UNION)) { - struct vnode *tvp = vp; - vp = vp->v_mount->mnt_vnodecovered; - VREF(vp); - fp->f_vnode = vp; - fp->f_data = vp; - fp->f_offset = 0; - vput(tvp); - VFS_UNLOCK_GIANT(vfslocked); - goto unionread; - } - VOP_UNLOCK(vp, 0, td); - } - VFS_UNLOCK_GIANT(vfslocked); - error = copyout(&loff, uap->basep, sizeof(long)); - fdrop(fp, td); - td->td_retval[0] = uap->count - auio.uio_resid; + + if (error == 0) + error = copyout(dirbuf, uap->buf, readcnt); + free(dirbuf, M_TEMP); + if (error == 0) + error = copyout(&base, uap->basep, sizeof(long)); return (error); } #endif /* COMPAT_43 */ @@ -3726,6 +3649,20 @@ long *basep; } */ *uap; { + long base; + int error; + + error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, + UIO_USERSPACE, NULL); + if (error == 0 && uap->basep != NULL) + error = copyout(&base, uap->basep, sizeof(long)); + return (error); +} + +int +kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, + long *basep, enum uio_seg bufseg, int *ufs_43) +{ struct vnode *vp; struct file *fp; struct uio auio; @@ -3734,28 +3671,38 @@ long loff; int error, eofflag; - AUDIT_ARG(fd, uap->fd); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + AUDIT_ARG(fd, fd); + if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); return (EBADF); } vp = fp->f_vnode; +#ifdef COMPAT_43 + /* + * This is for ogetdirentries() as it returns the contents of a + * 4.3 UFS directly but has to massage the entries of a 4.4 UFS + * to 4.3 binaries. Can one even run any 4.3 binaries on any + * version of FreeBSD? + */ + if (ufs_43 != NULL) + *ufs_43 = vp->v_mount->mnt_maxsymlinklen <= 0; +#endif unionread: vfslocked = VFS_LOCK_GIANT(vp->v_mount); if (vp->v_type != VDIR) { error = EINVAL; goto fail; } - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = buf; + aiov.iov_len = count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; + auio.uio_segflg = bufseg; auio.uio_td = td; - auio.uio_resid = uap->count; + auio.uio_resid = count; /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); AUDIT_ARG(vnode, vp, ARG_VNODE1); @@ -3770,7 +3717,7 @@ VOP_UNLOCK(vp, 0, td); if (error) goto fail; - if (uap->count == auio.uio_resid) { + if (count == auio.uio_resid) { if (union_dircheckp) { error = union_dircheckp(td, &vp, fp); if (error == -1) { @@ -3799,10 +3746,9 @@ } VOP_UNLOCK(vp, 0, td); } - if (uap->basep != NULL) { - error = copyout(&loff, uap->basep, sizeof(long)); - } - td->td_retval[0] = uap->count - auio.uio_resid; + if (basep != NULL) + *basep = loff; + td->td_retval[0] = count - auio.uio_resid; fail: VFS_UNLOCK_GIANT(vfslocked); fdrop(fp, td); @@ -3824,12 +3770,9 @@ u_int count; } */ *uap; { - struct getdirentries_args ap; - ap.fd = uap->fd; - ap.buf = uap->buf; - ap.count = uap->count; - ap.basep = NULL; - return (getdirentries(td, &ap)); + + return (kern_getdirentries(td, uap->fd, uap->buf, uap->count, NULL, + UIO_USERSPACE, NULL)); } /* ==== //depot/projects/smpng/sys/sys/syscallsubr.h#31 (text+ko) ==== @@ -79,6 +79,8 @@ int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); +int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, + long *basep, enum uio_seg bufseg, int *ufs_43); int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, enum uio_seg bufseg, int flags); int kern_getitimer(struct thread *, u_int, struct itimerval *);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200606271951.k5RJpWPr092469>