aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2019-09-01 14:01:09 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2019-09-01 14:01:09 +0000
commit2796c209b03972bfbe3b1a1bd8ea3309f9cfca4e (patch)
treef43bafb5b71a6c5ef9f092f3b39e26d539b978c9 /sys
parentb21097894e316eeebe2f3e1ef4a135c2eac24218 (diff)
downloadsrc-2796c209b03972bfbe3b1a1bd8ea3309f9cfca4e.tar.gz
src-2796c209b03972bfbe3b1a1bd8ea3309f9cfca4e.zip
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
Notes
Notes: svn path=/head/; revision=351656
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_default.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index 94ba43ff0645..4c7e8781d1ba 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -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);
}