Skip to content

Commit

Permalink
Use both va_gen and va_filerev to validate cache entries.
Browse files Browse the repository at this point in the history
Various filesystems implement one or another of these with varying
semantics so check both otherwise the cache does not operate corectly.
  • Loading branch information
Robin Geuze authored and DanielO committed Oct 12, 2022
1 parent 7e65358 commit aa7f151
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
2 changes: 2 additions & 0 deletions sys/fs/pefs/pefs_dircache.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ pefs_dircache_purge(struct pefs_dircache *pd)
// ASSERT_VOP_ELOCKED
mtx_lock(&pd->pd_mtx);
atomic_store_rel_long(&pd->pd_gen, 0);
atomic_store_rel_64(&pd->pd_filerev, 0);
LIST_FOREACH_SAFE(pde, &pd->pd_activehead, pde_dir_entry, tmp) {
dircache_entry_expire_locked(pde);
}
Expand All @@ -337,6 +338,7 @@ pefs_dircache_expire(struct pefs_dircache_entry *pde, u_int dflags)
return;
mtx_lock(&pd->pd_mtx);
atomic_store_rel_long(&pd->pd_gen, 0);
atomic_store_rel_64(&pd->pd_filerev, 0);
dircache_retry_clear(pd);
if (pde->pde_dircache != NULL) {
dircache_entry_expire_locked(pde);
Expand Down
15 changes: 10 additions & 5 deletions sys/fs/pefs/pefs_dircache.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ struct pefs_dircache {
struct mtx pd_mtx;
struct pefs_dircache_listhead pd_activehead;
struct pefs_dircache_listhead pd_stalehead;
volatile u_long pd_gen;
volatile u_long pd_gen;
volatile u_quad_t pd_filerev;
struct pefs_dircache_pool *pd_pool;
struct pefs_dircache_entry *pd_retry[PEFS_DIRCACHE_RETRY_COUNT];
};
Expand Down Expand Up @@ -89,14 +90,17 @@ void pefs_dircache_expire_encname(struct pefs_dircache *pd,
void pefs_dircache_gc(struct pefs_dircache *pd);

static __inline int
pefs_dircache_valid(struct pefs_dircache *pd, u_long gen)
pefs_dircache_valid(struct pefs_dircache *pd, u_long gen, u_quad_t filerev)
{
u_long pd_gen;
u_quad_t pd_filerev;

if (gen == 0)
if (filerev == 0 && gen == 0)
return 0;

pd_gen = atomic_load_acq_long(&pd->pd_gen);
return (gen == pd_gen);
pd_filerev = atomic_load_acq_64(&pd->pd_filerev);
return ((filerev == pd_filerev || filerev == 0) && (gen == pd_gen || gen == 0));
}

static __inline void
Expand All @@ -105,9 +109,10 @@ pefs_dircache_beginupdate(struct pefs_dircache *pd)
}

static __inline void
pefs_dircache_endupdate(struct pefs_dircache *pd, u_long gen)
pefs_dircache_endupdate(struct pefs_dircache *pd, u_long gen, u_quad_t filerev)
{
atomic_store_rel_long(&pd->pd_gen, gen);
atomic_store_rel_64(&pd->pd_filerev, filerev);
}

static __inline void
Expand Down
47 changes: 29 additions & 18 deletions sys/fs/pefs/pefs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,28 @@ static int pefs_read_int(struct vnode *vp, struct uio *uio, int ioflag,
static int pefs_write_int(struct vnode *vp, struct uio *uio, int ioflag,
struct ucred *cred, u_quad_t nsize);

static __inline u_long
pefs_getgen(struct vnode *vp, struct ucred *cred)
static __inline void
pefs_getgen_and_filerev(struct vnode *vp, struct ucred *cred, u_long *gen, u_quad_t *filerev)
{
struct vattr va;
int error;

if (!pefs_dircache_enable ||
((VFS_TO_PEFS(vp->v_mount)->pm_flags & PM_DIRCACHE) == 0))
return (0);
((VFS_TO_PEFS(vp->v_mount)->pm_flags & PM_DIRCACHE) == 0)) {
*gen = 0;
*filerev = 0;
return;
}

error = VOP_GETATTR(PEFS_LOWERVP(vp), &va, cred);
if (error != 0)
return (0);
if (error != 0) {
*gen = 0;
*filerev = 0;
return;
}

return (va.va_gen);
*gen = va.va_gen;
*filerev = va.va_filerev;
}

static __inline int
Expand Down Expand Up @@ -439,7 +446,7 @@ pefs_lookup_parsedir(struct pefs_dircache *pd, struct pefs_ctx *ctx,
}

static int
pefs_lookup_readdir(struct pefs_enccn *pec, u_long gen, struct vnode *dvp,
pefs_lookup_readdir(struct pefs_enccn *pec, u_long gen, u_quad_t filerev, struct vnode *dvp,
struct componentname *cnp)
{
struct uio *uio;
Expand Down Expand Up @@ -485,7 +492,7 @@ pefs_lookup_readdir(struct pefs_enccn *pec, u_long gen, struct vnode *dvp,
pefs_chunk_restore(&pc);
}
if (eofflag != 0 && error == 0)
pefs_dircache_endupdate(dpn->pn_dircache, gen);
pefs_dircache_endupdate(dpn->pn_dircache, gen, filerev);
else
pefs_dircache_abortupdate(dpn->pn_dircache);

Expand Down Expand Up @@ -534,7 +541,7 @@ pefs_lookup_lower(struct vnode *dvp, struct vnode **lvpp,
}

static int
pefs_lookup_dircache(struct pefs_enccn *enccn, u_long gen, struct vnode *dvp,
pefs_lookup_dircache(struct pefs_enccn *enccn, u_long gen, u_quad_t filerev , struct vnode *dvp,
struct vnode **lvpp, struct componentname *cnp)
{
struct pefs_dircache *pd;
Expand All @@ -546,7 +553,7 @@ pefs_lookup_dircache(struct pefs_enccn *enccn, u_long gen, struct vnode *dvp,
cache = pefs_dircache_lookup(pd, cnp->cn_nameptr,
cnp->cn_namelen);
if (cache == NULL) {
if (pefs_dircache_valid(pd, gen))
if (pefs_dircache_valid(pd, gen, filerev))
return (ENOENT);
return (EINVAL);
}
Expand Down Expand Up @@ -578,6 +585,7 @@ pefs_lookup(struct vop_cachedlookup_args *ap)
struct mount *mp;
uint64_t flags;
u_long gen;
u_quad_t filerev;
int nokey_lookup, skip_lookup;
int error;

Expand Down Expand Up @@ -613,10 +621,10 @@ pefs_lookup(struct vop_cachedlookup_args *ap)

if (!nokey_lookup) {
lvp = NULL;
gen = pefs_getgen(dvp, cnp->cn_cred);
error = pefs_lookup_dircache(&enccn, gen, dvp, &lvp, cnp);
pefs_getgen_and_filerev(dvp, cnp->cn_cred, &gen, &filerev);
error = pefs_lookup_dircache(&enccn, gen, filerev, dvp, &lvp, cnp);
if (error != 0 && error != ENOENT)
error = pefs_lookup_readdir(&enccn, gen, dvp, cnp);
error = pefs_lookup_readdir(&enccn, gen, filerev, dvp, cnp);
if (error == ENOENT && (cnp->cn_flags & ISLASTCN) &&
(cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME ||
(cnp->cn_nameiop == DELETE &&
Expand Down Expand Up @@ -1680,6 +1688,7 @@ pefs_readdir(struct vop_readdir_args *ap)
struct pefs_ctx *ctx;
size_t mem_size;
u_long gen;
u_quad_t filerev;
int error;
int r_ncookies = 0, r_ncookies_max = 0, ncookies = 0;
u_long *r_cookies = NULL, *cookies = NULL;
Expand All @@ -1703,13 +1712,15 @@ pefs_readdir(struct vop_readdir_args *ap)
a_cookies = &cookies;
}

gen = pefs_getgen(vp, cred);
pefs_getgen_and_filerev(vp, cred, &gen, &filerev);
ctx = pefs_ctx_get();
pefs_chunk_create(&pc, pn, qmin(uio->uio_resid, DFLTPHYS));
pn_key = pefs_node_key(pn);
pefs_dircache_beginupdate(pn->pn_dircache);
if (!pefs_dircache_valid(pn->pn_dircache, gen) || uio->uio_offset != 0)
if (!pefs_dircache_valid(pn->pn_dircache, gen, filerev) || uio->uio_offset != 0) {
gen = 0;
filerev = 0;
}
while (1) {
if (uio->uio_resid < pc.pc_size)
pefs_chunk_setsize(&pc, uio->uio_resid);
Expand Down Expand Up @@ -1766,8 +1777,8 @@ pefs_readdir(struct vop_readdir_args *ap)

pefs_chunk_restore(&pc);
}
if (*eofflag != 0 && error == 0 && gen != 0)
pefs_dircache_endupdate(pn->pn_dircache, gen);
if (*eofflag != 0 && error == 0 && gen != 0 && filerev != 0)
pefs_dircache_endupdate(pn->pn_dircache, gen, filerev);
else
pefs_dircache_abortupdate(pn->pn_dircache);

Expand Down

0 comments on commit aa7f151

Please sign in to comment.