Windows: add cm_BPlusDirEnumBulkStatOne

cm_BPlusDirEnumBulkStatOne() is similar to cm_BPlusDirEnumBulkStat()
except that it is used to obtain the status info for one FID in
particular via RXAFS_InlineBulkStat, the parent directory FID, and
up to 48 other FIDs in the same directory which do not currently
have a registered callback.

The parent directory is included to prevent the directory FID
callback from expiring when a directory such as /afs/andrew.cmu.edu/usr/
that requires more status objects then exist in the cache are continuously
recycled.

Up to 48 other FIDs are requested since in most cases on Windows
every entry in a directory is required for an enumeration.

Change-Id: Ic53134498ac0e776232a6f9c97cdb26367959546
Reviewed-on: http://gerrit.openafs.org/5345
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>
This commit is contained in:
Jeffrey Altman 2011-02-28 01:27:33 +00:00 committed by Jeffrey Altman
parent 1a0dd342cc
commit 0954e0ef9a
2 changed files with 109 additions and 0 deletions

View File

@ -2397,6 +2397,114 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
return code;
}
/*
* Similar to cm_BPlusDirEnumBulkStat() except that only
* one RPC is issued containing the provided scp FID and up to
* AFSCBMAX - 1 other FIDs for which the status info has yet
* to be obtained.
*/
long
cm_BPlusDirEnumBulkStatOne(cm_direnum_t *enump, cm_scache_t *scp)
{
cm_scache_t *dscp = enump->dscp;
cm_user_t *userp = enump->userp;
cm_bulkStat_t *bsp;
afs_uint32 code = 0;
afs_uint32 i;
cm_req_t req;
cm_InitReq(&req);
req.flags = enump->reqFlags;
if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
return 0;
bsp = malloc(sizeof(cm_bulkStat_t));
if (!bsp)
return ENOMEM;
memset(bsp, 0, sizeof(cm_bulkStat_t));
/*
* In order to prevent the directory callback from expiring
* on really large directories with many symlinks to mount
* points such as /afs/andrew.cmu.edu/usr/, always include
* the directory fid in the search.
*/
if (lock_TryWrite(&dscp->rw)) {
bsp->fids[bsp->counter].Volume = dscp->fid.volume;
bsp->fids[bsp->counter].Vnode = dscp->fid.vnode;
bsp->fids[bsp->counter].Unique = dscp->fid.unique;
bsp->counter++;
lock_ReleaseWrite(&dscp->rw);
}
/* First process the requested scp if we can */
if (lock_TryWrite(&scp->rw)) {
bsp->fids[bsp->counter].Volume = scp->fid.volume;
bsp->fids[bsp->counter].Vnode = scp->fid.vnode;
bsp->fids[bsp->counter].Unique = scp->fid.unique;
bsp->counter++;
lock_ReleaseWrite(&scp->rw);
}
if (enump->count <= AFSCBMAX - 1) {
i = 0;
} else {
/*
* Find the requested FID in the enumeration
* and start from there.
*/
for (i=0; i < enump->count && cm_FidCmp(&scp->fid, &enump->entry[i].fid); i++);
}
for ( ; bsp->counter < AFSCBMAX && i < enump->count; i++) {
cm_scache_t *tscp;
int count = bsp->counter;
if ( !wcscmp(L".", enump->entry[i].name) || !wcscmp(L"..", enump->entry[i].name) ) {
continue;
} else {
tscp = cm_FindSCache(&enump->entry[i].fid);
if (scp == tscp) {
enump->entry[i].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
cm_ReleaseSCache(tscp);
continue;
}
}
if (tscp) {
if (lock_TryWrite(&tscp->rw)) {
/* we have an entry that we can look at */
if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
/* we have a callback on it. Don't bother
* fetching this stat entry, since we're happy
* with the info we have.
*/
lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
enump->entry[i].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
continue;
}
lock_ReleaseWrite(&tscp->rw);
} /* got lock */
if (scp != tscp)
cm_ReleaseSCache(tscp);
} /* found entry */
bsp->fids[count].Volume = enump->entry[i].fid.volume;
bsp->fids[count].Vnode = enump->entry[i].fid.vnode;
bsp->fids[count].Unique = enump->entry[i].fid.unique;
bsp->counter++;
enump->entry[i].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
}
if (bsp->counter > 0)
code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
free(bsp);
return code;
}
static long
cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
{

View File

@ -179,6 +179,7 @@ long cm_BPlusDirPeekNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entr
long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
long cm_BPlusDirEnumTest(cm_scache_t * dscp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked);
long cm_BPlusDirEnumBulkStat(cm_direnum_t *enump);
long cm_BPlusDirEnumBulkStatOne(cm_direnum_t *enump, cm_scache_t *scp);
long cm_InitBPlusDir(void);