git: c3dc958cacd8 - stable/13 - vfs cache: plug a hypothetical corner case when freeing
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 13 Oct 2023 23:53:49 UTC
The branch stable/13 has been updated by mjg:
URL: https://cgit.FreeBSD.org/src/commit/?id=c3dc958cacd819c9fe989477371f01c187873cc0
commit c3dc958cacd819c9fe989477371f01c187873cc0
Author: Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2023-09-23 02:04:06 +0000
Commit: Mateusz Guzik <mjg@FreeBSD.org>
CommitDate: 2023-10-13 23:48:12 +0000
vfs cache: plug a hypothetical corner case when freeing
cache_zap_unlocked_bucket is called with a bunch of addresses and
without any locks held, forcing it to revalidate everything from
scratch.
It did not account for a case where the entry is reallocated with
everything the same except for the target vnode.
Should the target use a different lock than the one expected, freeing
would proceed without being properly synchronized.
Note this is almost impossible to happen in practice.
(cherry picked from commit 0f15054f7990f9c772bea34778a8838aa05ebed8)
---
sys/kern/vfs_cache.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 1d52b2e63169..49e66803a1d1 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -1649,6 +1649,7 @@ cache_zap_unlocked_bucket(struct namecache *ncp, struct componentname *cnp,
struct mtx *blp)
{
struct namecache *rncp;
+ struct mtx *rvlp;
cache_assert_bucket_unlocked(ncp);
@@ -1661,14 +1662,24 @@ cache_zap_unlocked_bucket(struct namecache *ncp, struct componentname *cnp,
!bcmp(rncp->nc_name, cnp->cn_nameptr, rncp->nc_nlen))
break;
}
- if (rncp != NULL) {
- cache_zap_locked(rncp);
- mtx_unlock(blp);
- cache_unlock_vnodes(dvlp, vlp);
- atomic_add_long(&zap_bucket_relock_success, 1);
- return (0);
- }
+ if (rncp == NULL)
+ goto out_mismatch;
+
+ if (!(ncp->nc_flag & NCF_NEGATIVE))
+ rvlp = VP2VNODELOCK(rncp->nc_vp);
+ else
+ rvlp = NULL;
+ if (rvlp != vlp)
+ goto out_mismatch;
+
+ cache_zap_locked(rncp);
+ mtx_unlock(blp);
+ cache_unlock_vnodes(dvlp, vlp);
+ atomic_add_long(&zap_bucket_relock_success, 1);
+ return (0);
+
+out_mismatch:
mtx_unlock(blp);
cache_unlock_vnodes(dvlp, vlp);
return (EAGAIN);