svn commit: r351656 - head/sys/kern
Mateusz Guzik
mjg at FreeBSD.org
Sun Sep 1 14:01:10 UTC 2019
Author: mjg
Date: Sun Sep 1 14:01:09 2019
New Revision: 351656
URL: https://svnweb.freebsd.org/changeset/base/351656
Log:
vfs: stop refing freed mount points in vop_stdgetwritemount
The code used blindly ref based on an unsafely red address and then would
backpedal if necessary. This was safe in terms of memory access since
mounts are type-stable, but made for a potential a bug where the mount
was reused and had the count reset to 0 before this code decreased it.
Reviewed by: kib
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D21411
Modified:
head/sys/kern/vfs_default.c
Modified: head/sys/kern/vfs_default.c
==============================================================================
--- head/sys/kern/vfs_default.c Sun Sep 1 10:39:16 2019 (r351655)
+++ head/sys/kern/vfs_default.c Sun Sep 1 14:01:09 2019 (r351656)
@@ -588,22 +588,28 @@ vop_stdgetwritemount(ap)
} */ *ap;
{
struct mount *mp;
+ struct vnode *vp;
/*
- * XXX Since this is called unlocked we may be recycled while
- * attempting to ref the mount. If this is the case or mountpoint
- * will be set to NULL. We only have to prevent this call from
- * returning with a ref to an incorrect mountpoint. It is not
- * harmful to return with a ref to our previous mountpoint.
+ * Note that having a reference does not prevent forced unmount from
+ * setting ->v_mount to NULL after the lock gets released. This is of
+ * no consequence for typical consumers (most notably vn_start_write)
+ * since in this case the vnode is VI_DOOMED. Unmount might have
+ * progressed far enough that its completion is only delayed by the
+ * reference obtained here. The consumer only needs to concern itself
+ * with releasing it.
*/
- mp = ap->a_vp->v_mount;
- if (mp != NULL) {
- vfs_ref(mp);
- if (mp != ap->a_vp->v_mount) {
- vfs_rel(mp);
- mp = NULL;
- }
+ vp = ap->a_vp;
+ mp = vp->v_mount;
+ MNT_ILOCK(mp);
+ if (mp != vp->v_mount) {
+ MNT_IUNLOCK(mp);
+ mp = NULL;
+ goto out;
}
+ MNT_REF(mp);
+ MNT_IUNLOCK(mp);
+out:
*(ap->a_mpp) = mp;
return (0);
}
More information about the svn-src-head
mailing list