aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-02-21 10:10:06 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-02-25 20:50:52 +0000
commitb287d46c385be71440693d3c0d8f4e098dee1207 (patch)
tree0141475ed410dadadb27aed18fea0f0a8a1d5668
parent16961e5e3fa47563743b7e4dd8892d017000477a (diff)
downloadsrc-b287d46c385be71440693d3c0d8f4e098dee1207.tar.gz
src-b287d46c385be71440693d3c0d8f4e098dee1207.zip
ffs_close_ea: do not relock vnode under lock_ea
Approved by: re (delphij, gjb) (cherry picked from commit 5e198e7646a27412c0541719f7bf1bbc0bd89223)
-rw-r--r--sys/ufs/ffs/ffs_vnops.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index f9a6a36d178a..64c72f3d3cc4 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -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);
}