Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_vnops.c
Show First 20 Lines • Show All 1,340 Lines • ▼ Show 20 Lines | ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td) | ||||
error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC); | error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC); | ||||
if (error) { | if (error) { | ||||
free(eae, M_TEMP); | free(eae, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Validate disk xattrfile contents. */ | /* Validate disk xattrfile contents. */ | ||||
for (eap = (void *)eae, eaend = (void *)(eae + easize); eap < eaend; | for (eap = (void *)eae, eaend = (void *)(eae + easize); eap < eaend; | ||||
eap = eapnext) { | eap = eapnext) { | ||||
/* Detect zeroed out tail */ | |||||
if (eap->ea_length < sizeof(*eap) || eap->ea_length == 0) { | |||||
easize = (const u_char *)eap - eae; | |||||
break; | |||||
} | |||||
eapnext = EXTATTR_NEXT(eap); | eapnext = EXTATTR_NEXT(eap); | ||||
/* Bogusly short entry or bogusly long entry. */ | /* Bogusly long entry. */ | ||||
if (eap->ea_length < sizeof(*eap) || eapnext > eaend) { | if (eapnext > eaend) { | ||||
free(eae, M_TEMP); | free(eae, M_TEMP); | ||||
return (EINTEGRITY); | return (EINTEGRITY); | ||||
} | } | ||||
} | } | ||||
ip->i_ea_len = easize; | |||||
*p = eae; | *p = eae; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
ffs_lock_ea(struct vnode *vp) | ffs_lock_ea(struct vnode *vp) | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
Show All 38 Lines | if (ip->i_ea_area != NULL) { | ||||
return (0); | return (0); | ||||
} | } | ||||
dp = ip->i_din2; | dp = ip->i_din2; | ||||
error = ffs_rdextattr(&ip->i_ea_area, vp, td); | error = ffs_rdextattr(&ip->i_ea_area, vp, td); | ||||
if (error) { | if (error) { | ||||
ffs_unlock_ea(vp); | ffs_unlock_ea(vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
ip->i_ea_len = dp->di_extsize; | |||||
ip->i_ea_error = 0; | ip->i_ea_error = 0; | ||||
ip->i_ea_refs++; | ip->i_ea_refs++; | ||||
ffs_unlock_ea(vp); | ffs_unlock_ea(vp); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Vnode extattr transaction commit/abort | * Vnode extattr transaction commit/abort | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td) | ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td) | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
struct uio luio; | struct uio luio; | ||||
struct iovec *liovec; | struct iovec *liovec; | ||||
struct ufs2_dinode *dp; | struct ufs2_dinode *dp; | ||||
size_t ea_len, tlen; | size_t ea_len, tlen; | ||||
int error, i, lcnt; | int error, i, lcnt; | ||||
bool truncate; | |||||
ip = VTOI(vp); | ip = VTOI(vp); | ||||
ffs_lock_ea(vp); | ffs_lock_ea(vp); | ||||
if (ip->i_ea_area == NULL) { | if (ip->i_ea_area == NULL) { | ||||
ffs_unlock_ea(vp); | ffs_unlock_ea(vp); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
dp = ip->i_din2; | dp = ip->i_din2; | ||||
error = ip->i_ea_error; | error = ip->i_ea_error; | ||||
truncate = false; | |||||
if (commit && error == 0) { | if (commit && error == 0) { | ||||
ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit"); | ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit"); | ||||
if (cred == NOCRED) | if (cred == NOCRED) | ||||
cred = vp->v_mount->mnt_cred; | cred = vp->v_mount->mnt_cred; | ||||
ea_len = MAX(ip->i_ea_len, dp->di_extsize); | ea_len = MAX(ip->i_ea_len, dp->di_extsize); | ||||
for (lcnt = 1, tlen = ea_len - ip->i_ea_len; tlen > 0;) { | for (lcnt = 1, tlen = ea_len - ip->i_ea_len; tlen > 0;) { | ||||
tlen -= MIN(ZERO_REGION_SIZE, tlen); | tlen -= MIN(ZERO_REGION_SIZE, tlen); | ||||
lcnt++; | lcnt++; | ||||
} | } | ||||
liovec = __builtin_alloca(lcnt * sizeof(struct iovec)); | liovec = __builtin_alloca(lcnt * sizeof(struct iovec)); | ||||
luio.uio_iovcnt = lcnt; | luio.uio_iovcnt = lcnt; | ||||
liovec[0].iov_base = ip->i_ea_area; | liovec[0].iov_base = ip->i_ea_area; | ||||
liovec[0].iov_len = ip->i_ea_len; | liovec[0].iov_len = ip->i_ea_len; | ||||
for (i = 1, tlen = ea_len; i < lcnt; i++) { | for (i = 1, tlen = ea_len - ip->i_ea_len; i < lcnt; i++) { | ||||
liovec[i].iov_base = __DECONST(void *, zero_region); | liovec[i].iov_base = __DECONST(void *, zero_region); | ||||
liovec[i].iov_len = MIN(ZERO_REGION_SIZE, tlen); | liovec[i].iov_len = MIN(ZERO_REGION_SIZE, tlen); | ||||
tlen -= liovec[i].iov_len; | tlen -= liovec[i].iov_len; | ||||
} | } | ||||
MPASS(tlen == ip->i_ea_len); | MPASS(tlen == 0); | ||||
luio.uio_iov = liovec; | luio.uio_iov = liovec; | ||||
luio.uio_offset = 0; | luio.uio_offset = 0; | ||||
luio.uio_resid = ea_len; | luio.uio_resid = ea_len; | ||||
luio.uio_segflg = UIO_SYSSPACE; | luio.uio_segflg = UIO_SYSSPACE; | ||||
luio.uio_rw = UIO_WRITE; | luio.uio_rw = UIO_WRITE; | ||||
luio.uio_td = td; | luio.uio_td = td; | ||||
error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred); | error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred); | ||||
if (error == 0 && ip->i_ea_len == 0) | |||||
truncate = true; | |||||
} | } | ||||
if (--ip->i_ea_refs == 0) { | if (--ip->i_ea_refs == 0) { | ||||
free(ip->i_ea_area, M_TEMP); | free(ip->i_ea_area, M_TEMP); | ||||
ip->i_ea_area = NULL; | ip->i_ea_area = NULL; | ||||
ip->i_ea_len = 0; | ip->i_ea_len = 0; | ||||
ip->i_ea_error = 0; | ip->i_ea_error = 0; | ||||
} | } | ||||
ffs_unlock_ea(vp); | ffs_unlock_ea(vp); | ||||
if (commit && error == 0 && ip->i_ea_len == 0) | if (truncate) | ||||
ffs_truncate(vp, 0, IO_EXT, cred); | ffs_truncate(vp, 0, IO_EXT, cred); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode extattr strategy routine for fifos. | * Vnode extattr strategy routine for fifos. | ||||
* | * | ||||
* We need to check for a read or write of the external attributes. | * We need to check for a read or write of the external attributes. | ||||
▲ Show 20 Lines • Show All 599 Lines • Show Last 20 Lines |