ffs_close_ea: do not relock vnode under lock_ea

ffs_lock_ea is after the vnode lock, so vnode must not be relocked under
lock_ea. Move ffs_truncate() call in ffs_close_ea() after the lock_ea is
dropped, and only truncate to length zero, since this is the only mode
supported by ffs_truncate() for EAs. Previously code did truncation and
then write.

Zero the part of the ext area that is unused, if truncation is due but not
done because ea area is not zero-length.

Reviewed by:	mckusick
Tested by:	pho
MFC after:      1 week
Sponsored by:   The FreeBSD Foundation
This commit is contained in:
Konstantin Belousov 2021-02-21 12:10:06 +02:00
parent c6d68ca842
commit 5e198e7646

View file

@ -1422,9 +1422,10 @@ ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td
{
struct inode *ip;
struct uio luio;
struct iovec liovec;
struct iovec *liovec;
struct ufs2_dinode *dp;
int error;
size_t ea_len, tlen;
int error, i, lcnt;
ip = VTOI(vp);
@ -1439,18 +1440,31 @@ ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td
ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit");
if (cred == NOCRED)
cred = vp->v_mount->mnt_cred;
liovec.iov_base = ip->i_ea_area;
liovec.iov_len = ip->i_ea_len;
luio.uio_iov = &liovec;
luio.uio_iovcnt = 1;
ea_len = MAX(ip->i_ea_len, dp->di_extsize);
for (lcnt = 1, tlen = ea_len - ip->i_ea_len; tlen > 0;) {
tlen -= MIN(ZERO_REGION_SIZE, tlen);
lcnt++;
}
liovec = __builtin_alloca(lcnt * sizeof(struct iovec));
luio.uio_iovcnt = lcnt;
liovec[0].iov_base = ip->i_ea_area;
liovec[0].iov_len = ip->i_ea_len;
for (i = 1, tlen = ea_len; i < lcnt; i++) {
liovec[i].iov_base = __DECONST(void *, zero_region);
liovec[i].iov_len = MIN(ZERO_REGION_SIZE, tlen);
tlen -= liovec[i].iov_len;
}
MPASS(tlen == ip->i_ea_len);
luio.uio_iov = liovec;
luio.uio_offset = 0;
luio.uio_resid = ip->i_ea_len;
luio.uio_resid = ea_len;
luio.uio_segflg = UIO_SYSSPACE;
luio.uio_rw = UIO_WRITE;
luio.uio_td = td;
/* XXX: I'm not happy about truncating to zero size */
if (ip->i_ea_len < dp->di_extsize)
error = ffs_truncate(vp, 0, IO_EXT, cred);
error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred);
}
if (--ip->i_ea_refs == 0) {
@ -1460,6 +1474,9 @@ ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td
ip->i_ea_error = 0;
}
ffs_unlock_ea(vp);
if (commit && error == 0 && ip->i_ea_len == 0)
ffs_truncate(vp, 0, IO_EXT, cred);
return (error);
}