summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_extattr.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2001-03-31 16:20:05 +0000
committerrwatson <rwatson@FreeBSD.org>2001-03-31 16:20:05 +0000
commitcb4f33ea3159d458714cc82ae47bdeca7b9d636f (patch)
tree6c91438e0bae4ef89921aa2478673f15ddd9b7e3 /sys/kern/vfs_extattr.c
parent1d52622861ade01fba488110e63ed8ba868cfcdf (diff)
downloadFreeBSD-src-cb4f33ea3159d458714cc82ae47bdeca7b9d636f.zip
FreeBSD-src-cb4f33ea3159d458714cc82ae47bdeca7b9d636f.tar.gz
o Introduce extattr_{delete,get,set}_fd() to allow extended attribute
operations on file descriptors, which complement the existing set of calls, extattr_{delete,get,set}_file() which act on paths. In doing so, restructure the system call implementation such that the two sets of functions share most of the relevant code, rather than duplicating it. This pushes the vnode locking into the shared code, but keeps the copying in of some arguments in the system call code. Allowing access via file descriptors reduces the opportunity for race conditions when managing extended attributes. Obtained from: TrustedBSD Project
Diffstat (limited to 'sys/kern/vfs_extattr.c')
-rw-r--r--sys/kern/vfs_extattr.c287
1 files changed, 213 insertions, 74 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 407d685..6b73258 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -3745,38 +3745,34 @@ extattrctl(p, uap)
}
/*
- * Syscall to set a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to the data to set.
- * The uio is consumed in the style of writev(). The real work happens
- * in VOP_SETEXTATTR().
+ * extattr_set_vp(): Set a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt
+ * proc "p"
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
*/
-int
-extattr_set_file(p, uap)
- struct proc *p;
- struct extattr_set_file_args *uap;
+static int
+extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
- struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
- char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
- if (error)
- return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
- if ((error = namei(&nd)) != 0)
- return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
- }
- iovlen = uap->iovcnt * sizeof(struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof(struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
@@ -3785,15 +3781,15 @@ extattr_set_file(p, uap)
} else
iov = aiov;
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3802,65 +3798,111 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
+ VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
-/*
- * Syscall to get a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to a buffer for the
- * data. The uio is consumed in the style of readv(). The real work
- * happens in VOP_GETEXTATTR();
- */
int
-extattr_get_file(p, uap)
+extattr_set_file(p, uap)
struct proc *p;
- struct extattr_get_file_args *uap;
+ struct extattr_set_file_args *uap;
{
struct nameidata nd;
- struct uio auio;
- struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
- u_int iovlen, cnt;
- int error, i;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
- iovlen = uap->iovcnt * sizeof (struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
- NDFREE(&nd, 0);
- return (EINVAL);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_set_fd(p, uap)
+ struct proc *p;
+ struct extattr_set_fd_args *uap;
+{
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ error = extattr_set_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
+}
+
+/*
+ * extattr_get_vp(): Get a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt,
+ * proc "p"
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
+ */
+static int
+extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
+{
+ struct uio auio;
+ struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
+ u_int iovlen, cnt;
+ int error, i;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof (struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
+ error = EINVAL;
+ goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
- } else {
+ } else
iov = aiov;
- needfree = NULL;
- }
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3869,45 +3911,142 @@ extattr_get_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
- return(error);
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+extattr_get_file(p, uap)
+ struct proc *p;
+ struct extattr_get_file_args *uap;
+{
+ struct nameidata nd;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_get_fd(p, uap)
+ struct proc *p;
+ struct extattr_get_fd_args *uap;
+{
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ error = extattr_get_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
}
/*
- * Syscall to delete a named extended attribute from a file or directory.
- * Accepts attribute name. The real work happens in VOP_SETEXTATTR().
+ * extattr_delete_vp(): Delete a named extended attribute on a file or
+ * directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname", proc "p"
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
*/
+static int
+extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct proc *p)
+{
+ struct mount *mp;
+ int error;
+
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
+ return (error);
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
+ p->p_cred->pc_ucred, p);
+
+ VOP_UNLOCK(vp, 0, p);
+ vn_finished_write(mp);
+ return (error);
+}
+
int
extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
- struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
- int error;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return(error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
- return (error);
- }
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- NULL, p->p_cred->pc_ucred, p);
- NDFREE(&nd, 0);
- vn_finished_write(mp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
+ attrname, p);
+
+ vrele(nd.ni_vp);
return(error);
}
+
+int
+extattr_delete_fd(p, uap)
+ struct proc *p;
+ struct extattr_delete_fd_args *uap;
+{
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ error = extattr_delete_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, p);
+
+ return (error);
+}
OpenPOWER on IntegriCloud