Date: Sun, 14 Jun 2026 02:05:14 +0000 From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 36b155a2b3ba - main - vfs: work around the race between vget() and vnlru Message-ID: <6a2e0c5a.27eb4.27ede61b@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=36b155a2b3baa747c1968a9094df9fa7fb0d02b3 commit 36b155a2b3baa747c1968a9094df9fa7fb0d02b3 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2026-05-28 09:42:38 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2026-06-14 02:02:38 +0000 vfs: work around the race between vget() and vnlru Specifically, do not let vtryrecycle() to recycle a used vnode. It is possible for a vnode to be vref-ed or vuse-ed lockless after it is held by vhold_recycle_free(). Then, since vtryrecycle() does not recheck the hold count, we might end up freeing vused vnode. Since vget_finish() increments v_usecount after obtaining the vnode lock, we would observe the hold reference anyway when the parallel vget() is blocked waiting on the vnode lock. PR: 281749 Reported and tested by: Steve Peurifoy <ssw01@mathistry.net>, Vladimir Grebenshchikov <vova@zote.me> Reviewed by: olce Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D57305 --- sys/kern/vfs_subr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 65529bc195bb..7b2718269a1f 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1936,9 +1936,14 @@ vtryrecycle(struct vnode *vp, bool isvnlru) * anyone picked up this vnode from another list. If not, we will * mark it with DOOMED via vgonel() so that anyone who does find it * will skip over it. + * + * We cannot check only for v_usecount > 0 there, since + * v_usecount increment is lockless. Instead check for + * v_holdcnt > 1, with the side effect that a parallel vhold() + * also aborts freeing this vnode. */ VI_LOCK(vp); - if (vp->v_usecount) { + if (vp->v_holdcnt > 1) { VOP_UNLOCK(vp); vdropl_recycle(vp); vn_finished_write(vnmp);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a2e0c5a.27eb4.27ede61b>
