Nptr leafNode;
#ifdef DEBUG_BTREE
- StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: key %s.\n", key.name);
+ StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: key %S.\n", key.name);
OutputDebugString(B->message);
#endif
dataNode = getnode(leafNode, slot);
data = getdatavalue(dataNode);
- StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: %S found on page %d value (%d.%d.%d).\n",
key.name,
getnodenumber(B, leafNode),
data.fid.volume,
Nptr newNode;
#ifdef DEBUG_BTREE
- StringCbPrintfA(B->message, sizeof(B->message), "INSERT: key %s.\n", key.name);
+ StringCbPrintfA(B->message, sizeof(B->message), "INSERT: key %S.\n", key.name);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
#endif
Nptr newNode;
#ifdef DEBUG_BTREE
- StringCbPrintfA(B->message, sizeof(B->message), "DELETE: key %s.\n", key.name);
+ StringCbPrintfA(B->message, sizeof(B->message), "DELETE: key %S.\n", key.name);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
#endif
for (x = 1; x <= numentries(n); x++) {
StringCbPrintfA(B->message, sizeof(B->message), "| entry %6d ", x);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
- StringCbPrintfA(B->message, sizeof(B->message), "| key = %6s ", getkey(n, x).name);
+ StringCbPrintfA(B->message, sizeof(B->message), "| key = %6S ", getkey(n, x).name);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
StringCbPrintfA(B->message, sizeof(B->message), "| node = %6d |\n", getnodenumber(B, getnode(n, x)));
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
StringCbPrintfA(B->message, sizeof(B->message), "| theKey %6s |\n", getfunkey(B).name);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
- StringCbPrintfA(B->message, sizeof(B->message), "| theData %d.%d.%d |\n", getfundata(B).volume,
- getfundata(B).vnode, getfundata(B).unique);
+ StringCbPrintfA(B->message, sizeof(B->message), "| theData %s (%d.%d.%d) |\n", getfundata(B).fsname, getfundata(B).fid.volume,
+ getfundata(B).fid.vnode, getfundata(B).fid.unique);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
StringCbPrintfA(B->message, sizeof(B->message), "- -- -- -- -- -- -\n");
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
insert(op->scp->dirBplus, key, data);
- if (!cm_Is8Dot3(entry)) {
+ if (cm_shortNames && !cm_Is8Dot3(entry)) {
cm_dirFid_t dfid;
clientchar_t wshortName[13];
}
if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
- dfid.vnode = htonl(fid.vnode);
- dfid.unique = htonl(fid.unique);
- cm_Gen8Dot3NameIntW(centry, &dfid, shortName, NULL);
-
/* delete first the long name and then the short name */
delete(op->scp->dirBplus, key);
- key.name = shortName;
- delete(op->scp->dirBplus, key);
+
+ if (cm_shortNames) {
+ dfid.vnode = htonl(fid.vnode);
+ dfid.unique = htonl(fid.unique);
+ cm_Gen8Dot3NameIntW(centry, &dfid, shortName, NULL);
+
+ key.name = shortName;
+ delete(op->scp->dirBplus, key);
+ }
}
} /* !NONODE */
} else {
/* the Write lock is held in cm_BPlusDirBuildTree() */
insert(scp->dirBplus, key, data);
- if (!cm_Is8Dot3(data.cname)) {
+ if (cm_shortNames && !cm_Is8Dot3(data.cname)) {
cm_dirFid_t dfid;
wchar_t wshortName[13];
}
long
-cm_BPlusDirEnumerate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
+cm_BPlusDirEnumerate(cm_scache_t *dscp, cm_user_t *userp, cm_req_t *reqp,
afs_uint32 locked, clientchar_t * maskp,
afs_uint32 fetchStatus, cm_direnum_t **enumpp)
{
/* Read lock the bplus tree so the data can't change */
if (!locked)
- lock_ObtainRead(&scp->dirlock);
+ lock_ObtainRead(&dscp->dirlock);
/*
- * Hold a reference to the directory so that it wont' be
+ * Hold a reference to the directory so that it won't be
* recycled while the enumeration is active.
*/
- cm_HoldSCache(scp);
+ cm_HoldSCache(dscp);
cm_HoldUser(userp);
- if (scp->dirBplus == NULL) {
+ if (dscp->dirBplus == NULL) {
osi_Log0(afsd_logp, "cm_BPlusDirEnumerate No BPlus Tree");
rc = CM_ERROR_WOULDBLOCK;
goto done;
}
/* Compute the number of entries */
- for (count = 0, leafNode = getleaf(scp->dirBplus); leafNode; leafNode = nextLeafNode) {
+ for (count = 0, leafNode = getleaf(dscp->dirBplus); leafNode; leafNode = nextLeafNode) {
for ( slot = 1, numentries = numentries(leafNode); slot <= numentries; slot++) {
firstDataNode = getnode(leafNode, slot);
}
/* Copy the name and fid for each cname entry into the enumeration */
- for (count = 0, leafNode = getleaf(scp->dirBplus); leafNode; leafNode = nextLeafNode) {
+ for (count = 0, leafNode = getleaf(dscp->dirBplus); leafNode; leafNode = nextLeafNode) {
for ( slot = 1, numentries = numentries(leafNode); slot <= numentries; slot++) {
firstDataNode = getnode(leafNode, slot);
enump->entry[count].name = name;
enump->entry[count].fid = getdatavalue(dataNode).fid;
- if (!cm_Is8Dot3(name)) {
- cm_dirFid_t dfid;
+ if (cm_shortNames) {
+ if (!cm_Is8Dot3(name)) {
+ cm_dirFid_t dfid;
- dfid.vnode = htonl(getdatavalue(dataNode).fid.vnode);
- dfid.unique = htonl(getdatavalue(dataNode).fid.unique);
+ dfid.vnode = htonl(getdatavalue(dataNode).fid.vnode);
+ dfid.unique = htonl(getdatavalue(dataNode).fid.unique);
- cm_Gen8Dot3NameIntW(name, &dfid, enump->entry[count].shortName, NULL);
- } else {
- StringCbCopyW(enump->entry[count].shortName,
- sizeof(enump->entry[count].shortName),
- name);
+ cm_Gen8Dot3NameIntW(name, &dfid, enump->entry[count].shortName, NULL);
+ } else {
+ StringCbCopyW(enump->entry[count].shortName,
+ sizeof(enump->entry[count].shortName),
+ name);
+ }
}
count++;
nextLeafNode = getnextnode(leafNode);
}
- enump->dscp = scp;
+ enump->dscp = dscp;
enump->userp = userp;
enump->reqFlags = reqp->flags;
enump->fetchStatus = fetchStatus;
+ enump->dataVersion = dscp->dirDataVersion;
done:
if (!locked)
- lock_ReleaseRead(&scp->dirlock);
+ lock_ReleaseRead(&dscp->dirlock);
/* if we failed, cleanup any mess */
if (rc != 0) {
osi_Log0(afsd_logp, "cm_BPlusDirEnumerate rc != 0");
- /* release the directory because we failed to generate an enumeration object */
- cm_ReleaseSCache(scp);
+ /*
+ * release the directory because we failed to generate an enumeration object.
+ * adjust the directory position in the queue to ensure it doesn't get pushed
+ * out by the allocation of a large number of cm_scache objects.
+ */
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_AdjustScacheLRU(dscp);
+ cm_ReleaseSCacheNoLock(dscp);
+ lock_ReleaseWrite(&cm_scacheLock);
cm_ReleaseUser(userp);
if (enump) {
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
{
cm_scache_t *dscp = enump->dscp;
cm_user_t *userp = enump->userp;
- cm_bulkStat_t *bsp;
+ cm_bulkStat_t *bsp = NULL;
+ afs_uint32 ** bs_errorCodep = NULL;
+ afs_uint32 ** bs_flagsp = NULL;
+ afs_uint32 dscp_errorCode = 0;
+ afs_uint32 dscp_flags = 0;
afs_uint32 count;
afs_uint32 code = 0;
cm_req_t req;
+ int i;
+ cm_scache_t *tscp;
+ afs_int32 nobulkstat = 0;
cm_InitReq(&req);
req.flags = enump->reqFlags;
return 0;
bsp = malloc(sizeof(cm_bulkStat_t));
- if (!bsp)
- return ENOMEM;
+ if (!bsp) {
+ code = ENOMEM;
+ goto done;
+ }
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
- for ( count = 0; count < enump->count; count++ ) {
- cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
- int i;
+ bs_errorCodep = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ bs_flagsp = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_flagsp) {
+ code = ENOMEM;
+ goto done;
+ }
+ /*
+ * 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.
+ */
+ bsp->fids[0].Volume = dscp->fid.volume;
+ bsp->fids[0].Vnode = dscp->fid.vnode;
+ bsp->fids[0].Unique = dscp->fid.unique;
+ bs_errorCodep[0] = &dscp_errorCode;
+ bs_flagsp[0] = &dscp_flags;
+ bsp->counter++;
+
+ restart_stat:
+ for ( count = 0; count < enump->count; count++ ) {
+ if ( !wcscmp(L".", enump->entry[count].name) || !wcscmp(L"..", enump->entry[count].name) ) {
+ continue;
+ }
+
+ tscp = cm_FindSCache(&enump->entry[count].fid);
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)) {
+ if (!cm_EAccesFindEntry(userp, &tscp->fid) && 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[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ enump->entry[count].errorCode = 0;
+ continue;
+ }
+
+ if (nobulkstat) {
+ code = cm_SyncOp(tscp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ enump->entry[count].errorCode = code;
continue;
}
+
lock_ReleaseWrite(&tscp->rw);
} /* got lock */
cm_ReleaseSCache(tscp);
bsp->fids[i].Volume = enump->entry[count].fid.volume;
bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
bsp->fids[i].Unique = enump->entry[count].fid.unique;
+ bs_errorCodep[i] = &enump->entry[count].errorCode;
+ bs_flagsp[bsp->counter] = &enump->entry[i].flags;
enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
if (bsp->counter == AFSCBMAX) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ if (code == CM_ERROR_BULKSTAT_FAILURE) {
+ /*
+ * If bulk stat cannot be used for this directory
+ * we must perform individual fetch status calls.
+ * Restart from the beginning of the enumeration.
+ */
+ nobulkstat = 1;
+
+ for (i=0; i<bsp->counter; i++) {
+ *(bs_flagsp[i]) &= ~CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+ goto restart_stat;
+ }
+
+ if (code) {
+ /* on any other error, exit */
+ goto done;
+ }
+ for ( i=0; i<bsp->counter; i++) {
+ *(bs_errorCodep[i]) = cm_MapRPCError(bsp->stats[i].errorCode, &req);
+ }
+
+ if (dscp_errorCode) {
+ code = dscp_errorCode;
+ goto done;
+ }
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
+
+ /*
+ * 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.
+ */
+ bsp->fids[0].Volume = dscp->fid.volume;
+ bsp->fids[0].Vnode = dscp->fid.vnode;
+ bsp->fids[0].Unique = dscp->fid.unique;
+ bs_errorCodep[0] = &dscp_errorCode;
+ bsp->counter++;
}
}
- if (bsp->counter > 0)
+ if (bsp->counter > 0) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ if (code == CM_ERROR_BULKSTAT_FAILURE) {
+ /*
+ * If bulk stat cannot be used for this directory
+ * we must perform individual fetch status calls.
+ * Restart from the beginning of the enumeration.
+ */
+ nobulkstat = 1;
+
+ for (i=0; i<bsp->counter; i++) {
+ *(bs_flagsp[i]) &= ~CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+ goto restart_stat;
+ }
+
+ if (code)
+ goto done;
+
+ for ( i=0; i<bsp->counter; i++) {
+ *(bs_errorCodep[i]) = cm_MapRPCError(bsp->stats[i].errorCode, &req);
+ }
+
+ if (dscp_errorCode) {
+ code = dscp_errorCode;
+ goto done;
+ }
+ }
+
+ done:
+ if (bsp)
+ free(bsp);
+ if (bs_errorCodep)
+ free(bs_errorCodep);
+ if (bs_flagsp)
+ free(bs_flagsp);
- free(bsp);
return code;
}
-static long
-cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
+/*
+ * Similar to cm_BPlusDirEnumBulkStat() except that only
+ * one RPC is issued containing the provided scp FID and up to
+ * AFSCBMAX - 2 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 count;
+ cm_bulkStat_t *bsp = NULL;
+ afs_uint32 ** bs_errorCodep = NULL;
+ afs_uint32 ** bs_flagsp = NULL;
+ afs_uint32 dscp_errorCode = 0;
+ afs_uint32 dscp_flags = 0;
+ afs_uint32 scp_errorCode = 0;
+ afs_uint32 scp_flags = 0;
afs_uint32 code = 0;
+ afs_uint32 i;
cm_req_t req;
+ cm_scache_t *tscp;
+
+ if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
+ return 0;
cm_InitReq(&req);
req.flags = enump->reqFlags;
+ bsp = malloc(sizeof(cm_bulkStat_t));
+ if (!bsp) {
+ code = ENOMEM;
+ goto done;
+ }
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
+
+ bs_errorCodep = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ bs_flagsp = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_flagsp) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * 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.
+ */
+ bsp->fids[0].Volume = dscp->fid.volume;
+ bsp->fids[0].Vnode = dscp->fid.vnode;
+ bsp->fids[0].Unique = dscp->fid.unique;
+ bs_errorCodep[0] = &dscp_errorCode;
+ bs_flagsp[0] = &dscp_flags;
+ bsp->counter++;
+
+ /*
+ * There is an assumption that this FID is located
+ * within the directory enumeration but it could be
+ * the case that the enumeration is out of date and
+ * the FID is not listed. So we explicitly add it
+ * after the directory FID and then skip it later
+ * if we find it.
+ */
+ bsp->fids[1].Volume = scp->fid.volume;
+ bsp->fids[1].Vnode = scp->fid.vnode;
+ bsp->fids[1].Unique = scp->fid.unique;
+ bs_errorCodep[1] = &scp_errorCode;
+ bs_flagsp[1] = &scp_flags;
+ bsp->counter++;
+
+ 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++) {
+ if ( !wcscmp(L".", enump->entry[i].name) || !wcscmp(L"..", enump->entry[i].name) ) {
+ continue;
+ }
+
+ tscp = cm_FindSCache(&enump->entry[i].fid);
+ if (tscp) {
+ if (tscp == scp) {
+ cm_ReleaseSCache(tscp);
+ continue;
+ }
+
+ if (lock_TryWrite(&tscp->rw)) {
+ /* we have an entry that we can look at */
+ if (!cm_EAccesFindEntry(userp, &tscp->fid) && 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;
+ enump->entry[i].errorCode = 0;
+ continue;
+ }
+ lock_ReleaseWrite(&tscp->rw);
+ } /* got lock */
+ cm_ReleaseSCache(tscp);
+ } /* found entry */
+
+ bsp->fids[bsp->counter].Volume = enump->entry[i].fid.volume;
+ bsp->fids[bsp->counter].Vnode = enump->entry[i].fid.vnode;
+ bsp->fids[bsp->counter].Unique = enump->entry[i].fid.unique;
+ bs_errorCodep[bsp->counter] = &enump->entry[i].errorCode;
+ bs_flagsp[bsp->counter] = &enump->entry[i].flags;
+ enump->entry[i].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ bsp->counter++;
+ }
+
+ if (bsp->counter > 0) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ /* Now process any errors that might have occurred */
+ if (code == CM_ERROR_BULKSTAT_FAILURE) {
+ for (i=2; i<bsp->counter; i++) {
+ *(bs_flagsp[i]) &= ~CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+
+ lock_ObtainWrite(&scp->rw);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&scp->rw);
+ goto done;
+ }
+
+ if (code)
+ goto done;
+
+ for ( i=0; i<bsp->counter; i++) {
+ *(bs_errorCodep[i]) = cm_MapRPCError(bsp->stats[i].errorCode, &req);
+ }
+
+ /* Check if there was an error on the requested FID, if so return it */
+ if ( scp_errorCode ) {
+ code = scp_errorCode;
+ goto done;
+ }
+ }
+
+ done:
+ if (bsp)
+ free(bsp);
+ if (bs_errorCodep)
+ free(bs_errorCodep);
+ if (bs_flagsp)
+ free(bs_flagsp);
+
+ return code;
+}
+
+static long
+cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
+{
+ cm_scache_t *dscp = enump->dscp;
+ cm_user_t *userp = enump->userp;
+ cm_bulkStat_t *bsp = NULL;
+ afs_uint32 ** bs_errorCodep = NULL;
+ afs_uint32 ** bs_flagsp = NULL;
+ afs_uint32 dscp_errorCode = 0;
+ afs_uint32 dscp_flags = 0;
+ afs_uint32 count;
+ afs_uint32 code = 0;
+ cm_req_t req;
+ cm_scache_t *tscp;
+ afs_int32 next = -1;
+ int i;
+
if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
return 0;
+ cm_InitReq(&req);
+ req.flags = enump->reqFlags;
+
bsp = malloc(sizeof(cm_bulkStat_t));
- if (!bsp)
- return ENOMEM;
+ if (!bsp) {
+ code = ENOMEM;
+ goto done;
+ }
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
+
+ bs_errorCodep = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ bs_flagsp = malloc(sizeof(afs_uint32 *) * AFSCBMAX);
+ if (!bs_flagsp) {
+ code = ENOMEM;
+ goto done;
+ }
- for ( count = enump->next; count < enump->count; count++ ) {
- cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
- int i;
+ /*
+ * 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.
+ */
+ bsp->fids[0].Volume = dscp->fid.volume;
+ bsp->fids[0].Vnode = dscp->fid.vnode;
+ bsp->fids[0].Unique = dscp->fid.unique;
+ bs_errorCodep[0] = &dscp_errorCode;
+ bs_flagsp[0] = &dscp_flags;
+ bsp->counter++;
+
+ for ( count = enump->next; count < enump->count && bsp->counter < AFSCBMAX; count++ ) {
+ if ( !wcscmp(L".", enump->entry[count].name) || !wcscmp(L"..", enump->entry[count].name) ) {
+ continue;
+ }
+ tscp = cm_FindSCache(&enump->entry[count].fid);
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)) {
+ if (!cm_EAccesFindEntry(userp, &tscp->fid) && 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[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ enump->entry[count].errorCode = 0;
continue;
}
lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
} /* found entry */
- i = bsp->counter++;
- bsp->fids[i].Volume = enump->entry[count].fid.volume;
- bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
- bsp->fids[i].Unique = enump->entry[count].fid.unique;
+ /* 'next' is the enump entry that is stored in the [bsp->counter == 1] element */
+ if (next == -1)
+ next = count;
+
+ bsp->fids[bsp->counter].Volume = enump->entry[count].fid.volume;
+ bsp->fids[bsp->counter].Vnode = enump->entry[count].fid.vnode;
+ bsp->fids[bsp->counter].Unique = enump->entry[count].fid.unique;
+ bs_errorCodep[bsp->counter] = &enump->entry[count].errorCode;
+ bs_flagsp[bsp->counter] = &enump->entry[count].flags;
enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ bsp->counter++;
+ }
- if (bsp->counter == AFSCBMAX) {
- code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
- break;
+ if (bsp->counter > 0) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ /* Now process any errors that might have occurred */
+ if (code == CM_ERROR_BULKSTAT_FAILURE) {
+ for (i=0; i<bsp->counter; i++) {
+ *(bs_flagsp[i]) &= ~CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+
+ /* if next == -1, there is no entry to update the status of */
+ if (next != -1) {
+ code = cm_GetSCache(&enump->entry[next].fid, NULL, &tscp, userp, &req);
+ if (code == 0) {
+ if (lock_TryWrite(&tscp->rw)) {
+ code = cm_SyncOp(tscp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&tscp->rw);
+ *(bs_errorCodep[1]) = code;
+ *(bs_flagsp[1]) |= CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+ cm_ReleaseSCache(tscp);
+ } else {
+ *(bs_errorCodep[1]) = code;
+ *(bs_flagsp[1]) |= CM_DIRENUM_FLAG_GOT_STATUS;
+ }
+ }
+ goto done;
+ }
+
+ if (code)
+ goto done;
+
+ for ( i=0; i<bsp->counter; i++) {
+ *(bs_errorCodep[i]) = cm_MapRPCError(bsp->stats[i].errorCode, &req);
+ }
+
+ if (dscp_errorCode) {
+ code = dscp_errorCode;
+ goto done;
}
}
- if (bsp->counter > 0 && bsp->counter < AFSCBMAX)
- code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ done:
+ if (bsp)
+ free(bsp);
+ if (bs_errorCodep)
+ free(bs_errorCodep);
+ if (bs_flagsp)
+ free(bs_flagsp);
- free(bsp);
return code;
}
long
cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
{
+ long code = 0;
+
if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
if (entrypp)
*entrypp = NULL;
}
if (enump->fetchStatus &&
- !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
- cm_BPlusDirEnumBulkStatNext(enump);
+ !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS)) {
+ code = cm_BPlusDirEnumBulkStatNext(enump);
+ }
*entrypp = &enump->entry[enump->next++];
if ( enump->next == enump->count ) {
return CM_ERROR_STOPNOW;
}
else {
- osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry SUCCESS");
+ if (code) {
+ (*entrypp)->errorCode = code;
+ osi_Log1(afsd_logp, "cm_BPlusDirNextEnumEntry ERROR 0x%x", code);
+ } else {
+ osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry SUCCESS");
+ }
return 0;
}
}
long
cm_BPlusDirPeekNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
{
+ long code;
+
if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
if (entrypp)
*entrypp = NULL;
}
if (enump->fetchStatus &&
- !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
- cm_BPlusDirEnumBulkStatNext(enump);
+ !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS)) {
+ code = cm_BPlusDirEnumBulkStatNext(enump);
+ if (code)
+ return code;
+ }
*entrypp = &enump->entry[enump->next];
if ( enump->next == enump->count ) {
osi_Log0(afsd_logp, "cm_BPlusDirFreeEnumeration");
if (enump) {
- /* Release the directory object */
- cm_ReleaseSCache(enump->dscp);
+ /*
+ * Release the directory object but first adjust its position
+ * in the LRU queue to ensure that it does not get stuck at the
+ * end due to the allocation of a large number of cm_scache
+ * entries in the directory.
+ */
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_AdjustScacheLRU(enump->dscp);
+ cm_ReleaseSCacheNoLock(enump->dscp);
+ lock_ReleaseWrite(&cm_scacheLock);
cm_ReleaseUser(enump->userp);
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {