git: ca1ce50b2b5e - main - vfs: add more safety against concurrent forced unmount to vn_write

Mateusz Guzik mjg at FreeBSD.org
Fri May 14 14:23:56 UTC 2021


The branch main has been updated by mjg:

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

commit ca1ce50b2b5ef11d85841f3aead98b2a9ad18819
Author:     Mateusz Guzik <mjg at FreeBSD.org>
AuthorDate: 2021-05-14 11:26:56 +0000
Commit:     Mateusz Guzik <mjg at FreeBSD.org>
CommitDate: 2021-05-14 14:22:22 +0000

    vfs: add more safety against concurrent forced unmount to vn_write
    
    1. stop re-reading ->v_mount (can become NULL)
    2. stop re-reading ->v_type (can change to VBAD)
---
 sys/kern/vfs_vnops.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 8f583329f067..6bf798cd73c5 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -1107,6 +1107,7 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags,
 	off_t orig_offset;
 	int error, ioflag, lock_flags;
 	int advice;
+	bool need_finished_write;
 
 	KASSERT(uio->uio_td == td, ("uio_td %p is not td %p",
 	    uio->uio_td, td));
@@ -1121,9 +1122,11 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags,
 		ioflag |= IO_NDELAY;
 	if (fp->f_flag & O_DIRECT)
 		ioflag |= IO_DIRECT;
-	if ((fp->f_flag & O_FSYNC) ||
-	    (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
-		ioflag |= IO_SYNC;
+	if (fp->f_flag & O_FSYNC) {
+		mp = atomic_load_ptr(&vp->v_mount);
+		if (mp != NULL && mp->mnt_flag & MNT_SYNCHRONOUS)
+			ioflag |= IO_SYNC;
+	}
 	/*
 	 * For O_DSYNC we set both IO_SYNC and IO_DATASYNC, so that VOP_WRITE()
 	 * implementations that don't understand IO_DATASYNC fall back to full
@@ -1132,9 +1135,13 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags,
 	if (fp->f_flag & O_DSYNC)
 		ioflag |= IO_SYNC | IO_DATASYNC;
 	mp = NULL;
-	if (vp->v_type != VCHR &&
-	    (error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
-		goto unlock;
+	need_finished_write = false;
+	if (vp->v_type != VCHR) {
+		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
+		if (error != 0)
+			goto unlock;
+		need_finished_write = true;
+	}
 
 	advice = get_advice(fp, uio);
 
@@ -1165,7 +1172,7 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags,
 		error = VOP_WRITE(vp, uio, ioflag, fp->f_cred);
 	fp->f_nextoff[UIO_WRITE] = uio->uio_offset;
 	VOP_UNLOCK(vp);
-	if (vp->v_type != VCHR)
+	if (need_finished_write)
 		vn_finished_write(mp);
 	if (error == 0 && advice == POSIX_FADV_NOREUSE &&
 	    orig_offset != uio->uio_offset)


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