git: 5e198e7646a2 - main - ffs_close_ea: do not relock vnode under lock_ea

Konstantin Belousov kib at FreeBSD.org
Wed Feb 24 07:57:06 UTC 2021


The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=5e198e7646a27412c0541719f7bf1bbc0bd89223

commit 5e198e7646a27412c0541719f7bf1bbc0bd89223
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-02-21 10:10:06 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-02-24 07:55:04 +0000

    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
---
 sys/ufs/ffs/ffs_vnops.c | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 4e574f85c9e4..9be46951c04e 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);
 }
 


More information about the dev-commits-src-main mailing list