PERFORCE change 100167 for review
John Baldwin
jhb at FreeBSD.org
Tue Jun 27 20:56:50 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=100167
Change 100167 by jhb at 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 *);
More information about the p4-projects
mailing list