*/
slot = getSlot(op->scp->dirBplus, leafNode);
if (slot <= BTERROR) {
- op->scp->dirDataVersion = 0;
+ op->scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
rc = (slot == BTERROR ? EINVAL : ENOENT);
goto done;
}
}
long
-cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
- clientchar_t * maskp, cm_direnum_t **enumpp)
+cm_BPlusDirEnumerate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
+ afs_uint32 locked, clientchar_t * maskp, cm_direnum_t **enumpp)
{
afs_uint32 count = 0, slot, numentries;
Nptr leafNode = NONODE, nextLeafNode;
* recycled while the enumeration is active.
*/
cm_HoldSCache(scp);
+ cm_HoldUser(userp);
if (scp->dirBplus == NULL) {
osi_Log0(afsd_logp, "cm_BPlusDirEnumerate No BPlus Tree");
}
enump->dscp = scp;
+ enump->userp = userp;
+ enump->reqFlags = reqp->flags;
done:
if (!locked)
/* release the directory because we failed to generate an enumeration object */
cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
if (enump) {
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
free(enump->entry[count].name);
}
long
-cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
+cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
{
cm_scache_t *dscp = enump->dscp;
+ cm_user_t *userp = enump->userp;
cm_bulkStat_t *bsp;
afs_uint32 count;
- afs_uint32 code;
+ afs_uint32 code = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+ req.flags = enump->reqFlags;
if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
return 0;
*/
lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
continue;
}
lock_ReleaseWrite(&tscp->rw);
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;
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
if (bsp->counter == AFSCBMAX) {
- code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
memset(bsp, 0, sizeof(cm_bulkStat_t));
}
}
if (bsp->counter > 0)
- code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
free(bsp);
- return 0;
+ return code;
}
-long
+static long
+cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
+{
+ cm_scache_t *dscp = enump->dscp;
+ cm_user_t *userp = enump->userp;
+ cm_bulkStat_t *bsp;
+ afs_uint32 count;
+ afs_uint32 code = 0;
+ 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));
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+ for ( count = enump->next; count < enump->count; count++ ) {
+ cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
+ int i;
+
+ 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[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ continue;
+ }
+ lock_ReleaseWrite(&tscp->rw);
+ } /* got lock */
+ 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;
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+
+ if (bsp->counter == AFSCBMAX) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ break;
+ }
+ }
+
+ if (bsp->counter > 0 && bsp->counter < AFSCBMAX)
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+
+ free(bsp);
+ return code;
+}
+
+long
cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
{
if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
return CM_ERROR_INVAL;
}
+ if (!(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
+ cm_BPlusDirEnumBulkStatNext(enump);
+
*entrypp = &enump->entry[enump->next++];
if ( enump->next == enump->count ) {
osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry STOPNOW");
if (enump) {
/* Release the directory object */
cm_ReleaseSCache(enump->dscp);
+ cm_ReleaseUser(enump->userp);
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
free(enump->entry[count].name);
}
long
-cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked)
+cm_BPlusDirEnumTest(cm_scache_t * dscp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked)
{
cm_direnum_t * enump = NULL;
cm_direnum_entry_t * entryp;
long code;
+
osi_Log0(afsd_logp, "cm_BPlusDirEnumTest start");
- for (code = cm_BPlusDirEnumerate(dscp, locked, NULL, &enump); code == 0; ) {
+ for (code = cm_BPlusDirEnumerate(dscp, userp, reqp, locked, NULL, &enump); code == 0; ) {
code = cm_BPlusDirNextEnumEntry(enump, &entryp);
if (code == 0 || code == CM_ERROR_STOPNOW) {
char buffer[1024];
clientchar_t *name;
cm_fid_t fid;
normchar_t shortName[13];
+ afs_uint32 flags;
} cm_direnum_entry_t;
+#define CM_DIRENUM_FLAG_GOT_STATUS 1
+
typedef struct cm_direnum {
cm_scache_t *dscp;
+ cm_user_t *userp;
+ afs_uint32 reqFlags;
afs_uint32 count;
afs_uint32 next;
cm_direnum_entry_t entry[1];
} cm_direnum_t;
-long cm_BPlusDirEnumerate(cm_scache_t *dscp, afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
+long cm_BPlusDirEnumerate(cm_scache_t *dscp, cm_user_t *userp, cm_req_t *reqp,
+ afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
long cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp);
long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
-long cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked);
-long cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp);
+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_InitBPlusDir(void);