From 0954e0ef9a34ca74886900a938f091e5bf9befd9 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 28 Feb 2011 01:27:33 +0000 Subject: [PATCH] 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 Tested-by: Jeffrey Altman --- src/WINNT/afsd/cm_btree.c | 108 ++++++++++++++++++++++++++++++++++++++ src/WINNT/afsd/cm_btree.h | 1 + 2 files changed, 109 insertions(+) diff --git a/src/WINNT/afsd/cm_btree.c b/src/WINNT/afsd/cm_btree.c index 212ef41859..97a33235ae 100644 --- a/src/WINNT/afsd/cm_btree.c +++ b/src/WINNT/afsd/cm_btree.c @@ -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) { diff --git a/src/WINNT/afsd/cm_btree.h b/src/WINNT/afsd/cm_btree.h index 62917c0d0c..32eade8057 100644 --- a/src/WINNT/afsd/cm_btree.h +++ b/src/WINNT/afsd/cm_btree.h @@ -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);