afs: Prioritize removal of unlinked vcaches

On some platforms (such as LINUX), unlinked vcaches are not destroyed
until the next execution of afs_ShakeLooseVCaches(). Since the hash for
a given vcache is computed from its volume id and vnode number, keeping
unlinked vcaches around can be a problem if files are repeatedly deleted
and recreated in the same volume. In this scenario, the same vnode
number will be reused several times, resulting in many vcaches with the
same volume id and vnode number (but different unique ids) in the same
bucket. Consequently, finding a given vcache in the bucket in question
can be time consuming (and cause extra cpu processing), as we would have
to traverse a long linked list.

To mitigate this problem, move vcaches associated with unlinked files to
the least recently used position in our VLRU, prioritizing their removal
the next time afs_ShakeLooseVCaches() is executed.

Introduce the QAddEnd() macro to make it easier to add a vcache to the
end of the VLRU.

Change-Id: Idc74da0c3c0b27bfdf2cd491b003bdd42c889a95
Reviewed-on: https://gerrit.openafs.org/14961
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Reviewed-by: Mark Vitale <mvitale@sinenomine.net>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
This commit is contained in:
Marcio Barbosa 2022-06-27 19:06:54 +00:00 committed by Andrew Deason
parent 1ccc87bbdc
commit 3f393cea96
2 changed files with 40 additions and 1 deletions

View File

@ -48,6 +48,31 @@ FetchWholeEnchilada(struct vcache *avc, struct vrequest *areq)
}
}
/**
* Move vcache to the tail of our VLRU.
*
* Move this vcache to the 'least recently used position' in our VLRU so it can
* be flushed the next time afs_ShakeLooseVCaches() is executed.
*
* @param[in] avc vcache to be moved
*
* @pre afs_xvcache is NOT held
*/
static void
DemoteSmushedVCache(struct vcache *avc)
{
/*
* Don't block on afs_xvcache. If we can't get it, let the regular flushing
* mechanism deal with this entry later (best-effort).
*/
if (NBObtainWriteLock(&afs_xvcache, 1210) == 0) {
QRemove(&avc->vlruq);
QAddEnd(&VLRU, &avc->vlruq);
ReleaseWriteLock(&afs_xvcache);
}
}
int
afsremove(struct vcache *adp, struct dcache *tdc,
struct vcache *tvc, char *aname, afs_ucred_t *acred,
@ -116,6 +141,7 @@ afsremove(struct vcache *adp, struct dcache *tdc,
* call FindVCache instead of GetVCache since if the file's really
* gone, we won't be able to fetch the status info anyway. */
if (tvc) {
int smushed = 0;
if (afs_mariner)
afs_MarinerLog("store$Removing", tvc);
ObtainWriteLock(&tvc->lock, 141);
@ -124,10 +150,20 @@ afsremove(struct vcache *adp, struct dcache *tdc,
tvc->f.m.LinkCount--;
tvc->f.states &= ~CUnique; /* For the dfs xlator */
if (tvc->f.m.LinkCount == 0 && !osi_Active(tvc)) {
if (!AFS_NFSXLATORREQ(acred))
if (!AFS_NFSXLATORREQ(acred)) {
afs_TryToSmush(tvc, acred, 0);
smushed = 1;
}
}
ReleaseWriteLock(&tvc->lock);
if (smushed) {
/*
* On many platforms, the VFS holds an additional reference on the
* vcache, so we cannot flush it here. Mark it to be flushed later.
*/
DemoteSmushedVCache(tvc);
}
afs_PutVCache(tvc);
}
return (0);

View File

@ -239,6 +239,9 @@ struct afs_q {
#define QInit(q) ((q)->prev = (q)->next = (q))
#define QAdd(q,e) ((e)->next = (q)->next, (e)->prev = (q), \
(q)->next->prev = (e), (q)->next = (e))
/* QAddEnd adds 'e' to the end of queue 'q' */
#define QAddEnd(q,e) ((e)->prev = (q)->prev, (e)->next = (q), \
(q)->prev->next = (e), (q)->prev = (e))
#define QRemove(e) ((e)->next->prev = (e)->prev, (e)->prev->next = (e)->next, (e)->prev = NULL, (e)->next = NULL)
#define QNext(e) ((e)->next)
#define QPrev(e) ((e)->prev)