Part I: Update extended attribute API and ABI:

o Modify the system call syntax for extattr_{get,set}_{fd,file}() so
  as not to use the scatter gather API (which appeared not to be used
  by any consumers, and be less portable), rather, accepts 'data'
  and 'nbytes' in the style of other simple read/write interfaces.
  This changes the API and ABI.

o Modify system call semantics so that extattr_get_{fd,file}() return
  a size_t.  When performing a read, the number of bytes read will
  be returned, unless the data pointer is NULL, in which case the
  number of bytes of data are returned.  This changes the API only.

o Modify the VOP_GETEXTATTR() vnode operation to accept a *size_t
  argument so as to return the size, if desirable.  If set to NULL,
  the size will not be returned.

o Update various filesystems (pseodofs, ufs) to DTRT.

These changes should make extended attributes more useful and more
portable.  More commits to rebuild the system call files, as well
as update userland utilities to follow.

Obtained from:	TrustedBSD Project
Sponsored by:	DARPA, NAI Labs
This commit is contained in:
Robert Watson 2002-02-10 04:43:22 +00:00
parent e751b85f6f
commit 74237f55b0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=90448
10 changed files with 171 additions and 200 deletions

View File

@ -138,7 +138,7 @@ typedef int (*pfs_ioctl_t)(PFS_IOCTL_ARGS);
#define PFS_GETEXTATTR_ARGS \
struct thread *td, struct proc *p, struct pfs_node *pn, \
int attrnamespace, const char *name, struct uio *uio, \
struct ucred *cred
size_t *size, struct ucred *cred
#define PFS_GETEXTATTR_PROTO(name) \
int name(PFS_GETEXTATTR_ARGS);
struct ucred;

View File

@ -283,7 +283,7 @@ pfs_getextattr(struct vop_getextattr_args *va)
}
error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
va->a_name, va->a_uio, va->a_cred);
va->a_name, va->a_uio, va->a_size, va->a_cred);
if (proc != NULL)
PRELE(proc);

View File

@ -513,10 +513,10 @@
const char *attrname); }
356 STD BSD { int extattr_set_file(const char *path, \
int attrnamespace, const char *attrname, \
struct iovec *iovp, unsigned iovcnt); }
357 STD BSD { int extattr_get_file(const char *path, \
void *data, size_t nbytes); }
357 STD BSD { ssize_t extattr_get_file(const char *path, \
int attrnamespace, const char *attrname, \
struct iovec *iovp, unsigned iovcnt); }
void *data, size_t nbytes); }
358 STD BSD { int extattr_delete_file(const char *path, \
int attrnamespace, const char *attrname); }
359 NOSTD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
@ -535,11 +535,10 @@
369 STD BSD { int __cap_set_file(const char *path_p, struct cap *cap_p); }
370 NODEF NOHIDE lkmressys lkmressys nosys_args int
371 STD BSD { int extattr_set_fd(int fd, int attrnamespace, \
const char *attrname, struct iovec *iovp, \
int iovcnt); }
372 STD BSD { int extattr_get_fd(int fd, int attrnamespace, \
const char *attrname, struct iovec *iovp, \
int iovcnt); }
const char *attrname, void *data, \
size_t nbytes); }
372 STD BSD { ssize_t extattr_get_fd(int fd, int attrnamespace, \
const char *attrname, void *data, size_t nbytes); }
373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \
const char *attrname); }
374 MSTD BSD { int __setugid(int flag); }

View File

@ -3993,67 +3993,52 @@ extattrctl(td, uap)
return (error);
}
/*
* extattr_set_vp(): Set a named extended attribute on a file or directory
/*-
* 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"
* kernelspace string pointer "attrname", userspace buffer
* pointer "data", buffer length "nbytes", thread "td".
* 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_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct thread *td)
const void *data, size_t nbytes, struct thread *td)
{
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
struct iovec aiov;
ssize_t cnt;
int error;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
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
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
aiov.iov_base = data;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
if (nbytes > INT_MAX) {
error = EINVAL;
goto done;
}
auio.uio_resid = nbytes;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
cnt = nbytes;
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return (error);
@ -4079,7 +4064,7 @@ extattr_set_file(td, uap)
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), td);
SCARG(uap, data), SCARG(uap, nbytes), td);
vrele(nd.ni_vp);
return (error);
@ -4103,71 +4088,65 @@ extattr_set_fd(td, uap)
return (error);
error = extattr_set_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), td);
SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
SCARG(uap, nbytes), td);
fdrop(fp, td);
return (error);
}
/*
* extattr_get_vp(): Get a named extended attribute on a file or directory
/*-
* 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"
* kernelspace string pointer "attrname", userspace buffer
* pointer "data", buffer length "nbytes", thread "td".
* 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 thread *td)
void *data, size_t nbytes, struct thread *td)
{
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
struct iovec aiov;
ssize_t cnt;
size_t size;
int error;
VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
iovlen = iovcnt * sizeof (struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
/*
* Slightly unusual semantics: if the user provides a NULL data
* pointer, they don't want to receive the data, just the
* maximum read length.
*/
if (data != NULL) {
aiov.iov_base = data;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_offset = 0;
if (nbytes > INT_MAX) {
error = EINVAL;
goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
auio.uio_resid = nbytes;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
cnt = nbytes;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
NULL, td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
} else {
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
&size, td->td_proc->p_ucred, td);
td->td_retval[0] = size;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, td);
return (error);
}
@ -4192,7 +4171,7 @@ extattr_get_file(td, uap)
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), td);
SCARG(uap, data), SCARG(uap, nbytes), td);
vrele(nd.ni_vp);
return (error);
@ -4216,8 +4195,8 @@ extattr_get_fd(td, uap)
return (error);
error = extattr_get_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), td);
SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
SCARG(uap, nbytes), td);
fdrop(fp, td);
return (error);

View File

@ -3993,67 +3993,52 @@ extattrctl(td, uap)
return (error);
}
/*
* extattr_set_vp(): Set a named extended attribute on a file or directory
/*-
* 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"
* kernelspace string pointer "attrname", userspace buffer
* pointer "data", buffer length "nbytes", thread "td".
* 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_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct thread *td)
const void *data, size_t nbytes, struct thread *td)
{
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
struct iovec aiov;
ssize_t cnt;
int error;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
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
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
aiov.iov_base = data;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
if (nbytes > INT_MAX) {
error = EINVAL;
goto done;
}
auio.uio_resid = nbytes;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
cnt = nbytes;
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return (error);
@ -4079,7 +4064,7 @@ extattr_set_file(td, uap)
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), td);
SCARG(uap, data), SCARG(uap, nbytes), td);
vrele(nd.ni_vp);
return (error);
@ -4103,71 +4088,65 @@ extattr_set_fd(td, uap)
return (error);
error = extattr_set_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), td);
SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
SCARG(uap, nbytes), td);
fdrop(fp, td);
return (error);
}
/*
* extattr_get_vp(): Get a named extended attribute on a file or directory
/*-
* 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"
* kernelspace string pointer "attrname", userspace buffer
* pointer "data", buffer length "nbytes", thread "td".
* 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 thread *td)
void *data, size_t nbytes, struct thread *td)
{
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
struct iovec aiov;
ssize_t cnt;
size_t size;
int error;
VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
iovlen = iovcnt * sizeof (struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
/*
* Slightly unusual semantics: if the user provides a NULL data
* pointer, they don't want to receive the data, just the
* maximum read length.
*/
if (data != NULL) {
aiov.iov_base = data;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_offset = 0;
if (nbytes > INT_MAX) {
error = EINVAL;
goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
auio.uio_resid = nbytes;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_td = td;
cnt = nbytes;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
NULL, td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
} else {
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
&size, td->td_proc->p_ucred, td);
td->td_retval[0] = size;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_proc->p_ucred, td);
cnt -= auio.uio_resid;
td->td_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, td);
return (error);
}
@ -4192,7 +4171,7 @@ extattr_get_file(td, uap)
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), td);
SCARG(uap, data), SCARG(uap, nbytes), td);
vrele(nd.ni_vp);
return (error);
@ -4216,8 +4195,8 @@ extattr_get_fd(td, uap)
return (error);
error = extattr_get_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), td);
SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
SCARG(uap, nbytes), td);
fdrop(fp, td);
return (error);

View File

@ -905,7 +905,8 @@ vn_extattr_get(struct vnode *vp, int ioflg, int attrnamespace,
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
/* authorize attribute retrieval as kernel */
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, NULL, td);
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, NULL, NULL,
td);
if ((ioflg & IO_NODELOCKED) == 0)
VOP_UNLOCK(vp, 0, td);

View File

@ -512,6 +512,7 @@ vop_getextattr {
IN int attrnamespace;
IN const char *name;
INOUT struct uio *uio;
OUT size_t *size;
IN struct ucred *cred;
IN struct thread *td;
};

View File

@ -1053,6 +1053,7 @@ lomacfs_getextattr(
int a_attrnamespace;
const char *a_name;
struct uio *a_uio;
size_t *a_size;
struct ucred *a_cred;
struct thread *a_td;
} */ *ap
@ -1065,7 +1066,7 @@ lomacfs_getextattr(
return (EPERM);
else
return (VOP_GETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace,
ap->a_name, ap->a_uio, ap->a_cred, ap->a_td));
ap->a_name, ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
}
static int

View File

@ -55,14 +55,14 @@ int extattrctl(const char *_path, int _cmd, const char *_filename,
int extattr_delete_fd(int _fd, int _attrnamespace, const char *_attrname);
int extattr_delete_file(const char *_path, int _attrnamespace,
const char *_attrname);
int extattr_get_fd(int _fd, int _attrnamespace, const char *_attrname,
struct iovec *_iovp, unsigned _iovcnt);
int extattr_get_file(const char *_path, int _attrnamespace,
const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
ssize_t extattr_get_fd(int _fd, int _attrnamespace, const char *_attrname,
void *_data, size_t _nbytes);
ssize_t extattr_get_file(const char *_path, int _attrnamespace,
const char *_attrname, void *_data, size_t _nbytes);
int extattr_set_fd(int _fd, int _attrnamespace, const char *_attrname,
struct iovec *_iovp, unsigned _iovcnt);
const void *_data, size_t _nbytes);
int extattr_set_file(const char *_path, int _attrnamespace,
const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
const char *_attrname, const void *_data, size_t _nbytes);
__END_DECLS
#endif /* !_KERNEL */

View File

@ -80,7 +80,8 @@ static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
const char *attrname, struct thread *td);
static int ufs_extattr_get(struct vnode *vp, int attrnamespace,
const char *name, struct uio *uio, struct ucred *cred, struct thread *td);
const char *name, struct uio *uio, size_t *size, struct ucred *cred,
struct thread *td);
static int ufs_extattr_set(struct vnode *vp, int attrnamespace,
const char *name, struct uio *uio, struct ucred *cred, struct thread *td);
static int ufs_extattr_rm(struct vnode *vp, int attrnamespace,
@ -825,6 +826,7 @@ vop_getextattr {
IN int a_attrnamespace;
IN const char *a_name;
INOUT struct uio *a_uio;
OUT struct size_t *a_size;
IN struct ucred *a_cred;
IN struct thread *a_td;
};
@ -837,7 +839,7 @@ vop_getextattr {
ufs_extattr_uepm_lock(ump, ap->a_td);
error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
ap->a_uio, ap->a_cred, ap->a_td);
ap->a_uio, ap->a_size, ap->a_cred, ap->a_td);
ufs_extattr_uepm_unlock(ump, ap->a_td);
@ -850,7 +852,7 @@ vop_getextattr {
*/
static int
ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
struct uio *uio, struct ucred *cred, struct thread *td)
struct uio *uio, size_t *size, struct ucred *cred, struct thread *td)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
@ -860,7 +862,7 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
struct ufsmount *ump = VFSTOUFS(mp);
struct inode *ip = VTOI(vp);
off_t base_offset;
size_t size, old_size;
size_t len, old_len;
int error = 0;
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
@ -885,7 +887,7 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
* extended attribute semantic. Otherwise we can't guarantee
* atomicity, as we don't provide locks for extended attributes.
*/
if (uio->uio_offset != 0)
if (uio != NULL && uio->uio_offset != 0)
return (ENXIO);
/*
@ -956,27 +958,36 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
goto vopunlock_exit;
}
/* Allow for offset into the attribute data. */
uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
/* Return full data size if caller requested it. */
if (size != NULL)
*size = ueh.ueh_len;
/*
* Figure out maximum to transfer -- use buffer size and local data
* limit.
*/
size = MIN(uio->uio_resid, ueh.ueh_len);
old_size = uio->uio_resid;
uio->uio_resid = size;
/* Return data if the caller requested it. */
if (uio != NULL) {
/* Allow for offset into the attribute data. */
uio->uio_offset = base_offset + sizeof(struct
ufs_extattr_header);
error = VOP_READ(attribute->uele_backing_vnode, uio,
IO_NODELOCKED, ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
/*
* Figure out maximum to transfer -- use buffer size and
* local data limit.
*/
len = MIN(uio->uio_resid, ueh.ueh_len);
old_len = uio->uio_resid;
uio->uio_resid = len;
uio->uio_resid = old_size - (size - uio->uio_resid);
error = VOP_READ(attribute->uele_backing_vnode, uio,
IO_NODELOCKED, ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
uio->uio_resid = old_len - (len - uio->uio_resid);
}
vopunlock_exit:
uio->uio_offset = 0;
if (uio != NULL)
uio->uio_offset = 0;
if (attribute->uele_backing_vnode != vp)
VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);