Skip to content

Commit

Permalink
vfs cache: plug a hypothetical corner case when freeing
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mjguzik committed Oct 5, 2023
1 parent 2749c22 commit 0f15054
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions sys/kern/vfs_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,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);

Expand All @@ -1732,14 +1733,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);
Expand Down

0 comments on commit 0f15054

Please sign in to comment.