PERFORCE change 100171 for review
John Baldwin
jhb at FreeBSD.org
Tue Jun 27 20:55:54 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=100171
Change 100171 by jhb at jhb_mutex on 2006/06/27 20:55:43
Revert last. All the other places that do getdirentries() do
things differently. It's going to be simpler to just add the
VFS Giant locking I think.
Affected files ...
.. //depot/projects/smpng/sys/kern/vfs_syscalls.c#108 edit
.. //depot/projects/smpng/sys/sys/syscallsubr.h#32 edit
Differences ...
==== //depot/projects/smpng/sys/kern/vfs_syscalls.c#108 (text+ko) ====
@@ -3563,67 +3563,144 @@
long *basep;
} */ *uap;
{
+ struct vnode *vp;
+ struct file *fp;
+ struct uio auio, kuio;
+ struct iovec aiov, kiov;
struct dirent *dp, *edp;
- char *dirbuf;
- int error, readcnt, ufs_43;
- long base;
+ caddr_t dirbuf;
+ int error, eofflag, readcnt, vfslocked;
+ long loff;
/* XXX arbitrary sanity limit on `count'. */
if (uap->count > 64 * 1024)
return (EINVAL);
-
- dirbuf = malloc(uap->count, M_TEMP, M_WAITOK);
- error = kern_getdirentries(td, uap->fd, dirbuf, uap->count, &base,
- UIO_SYSSPACE, &ufs_43);
+ 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);
if (error) {
- free(dirbuf, M_TEMP);
+ VOP_UNLOCK(vp, 0, td);
+ VFS_UNLOCK_GIANT(vfslocked);
+ fdrop(fp, td);
return (error);
}
-
- readcnt = td->td_retval[0];
+#endif
# if (BYTE_ORDER != LITTLE_ENDIAN)
- /*
- * On big endian systems, we can return the contents from a 4.3
- * UFS without performing a fixup.
- */
- if (!ufs_43) {
-# else
+ 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
+# endif
{
-# endif
- 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;
+ 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;
+ }
+ }
+ 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);
}
-
- if (error == 0)
- error = copyout(dirbuf, uap->buf, readcnt);
- free(dirbuf, M_TEMP);
- if (error == 0)
- error = copyout(&base, uap->basep, sizeof(long));
+ VFS_UNLOCK_GIANT(vfslocked);
+ error = copyout(&loff, uap->basep, sizeof(long));
+ fdrop(fp, td);
+ td->td_retval[0] = uap->count - auio.uio_resid;
return (error);
}
#endif /* COMPAT_43 */
@@ -3649,20 +3726,6 @@
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;
@@ -3671,38 +3734,28 @@
long loff;
int error, eofflag;
- AUDIT_ARG(fd, fd);
- if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
+ AUDIT_ARG(fd, uap->fd);
+ 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;
-#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 = buf;
- aiov.iov_len = count;
+ 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 = bufseg;
+ auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
- auio.uio_resid = count;
+ auio.uio_resid = uap->count;
/* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
AUDIT_ARG(vnode, vp, ARG_VNODE1);
@@ -3717,7 +3770,7 @@
VOP_UNLOCK(vp, 0, td);
if (error)
goto fail;
- if (count == auio.uio_resid) {
+ if (uap->count == auio.uio_resid) {
if (union_dircheckp) {
error = union_dircheckp(td, &vp, fp);
if (error == -1) {
@@ -3746,9 +3799,10 @@
}
VOP_UNLOCK(vp, 0, td);
}
- if (basep != NULL)
- *basep = loff;
- td->td_retval[0] = count - auio.uio_resid;
+ if (uap->basep != NULL) {
+ error = copyout(&loff, uap->basep, sizeof(long));
+ }
+ td->td_retval[0] = uap->count - auio.uio_resid;
fail:
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp, td);
@@ -3770,9 +3824,12 @@
u_int count;
} */ *uap;
{
-
- return (kern_getdirentries(td, uap->fd, uap->buf, uap->count, NULL,
- UIO_USERSPACE, NULL));
+ struct getdirentries_args ap;
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ return (getdirentries(td, &ap));
}
/*
==== //depot/projects/smpng/sys/sys/syscallsubr.h#32 (text+ko) ====
@@ -79,8 +79,6 @@
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