/*
- * Copyright 2007-2008 Secure Endpoints Inc.
- *
+ * Copyright 2007-2008 Secure Endpoints Inc.
+ *
* All Rights Reserved.
*
* This software has been released under the terms of the IBM Public
long cm_InitBPlusDir(void)
{
- if ((TlsKeyIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ if ((TlsKeyIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return 0;
- if ((TlsDataIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ if ((TlsDataIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return 0;
return 1;
/* access key and data values for B+tree methods */
/* pass values to getSlot(), descend...() */
static keyT getfunkey(Tree *B) {
- keyT *tlsKey;
-
- // Retrieve a data pointer for the current thread.
- tlsKey = (keyT *) TlsGetValue(TlsKeyIndex);
+ keyT *tlsKey;
+
+ // Retrieve a data pointer for the current thread.
+ tlsKey = (keyT *) TlsGetValue(TlsKeyIndex);
if (tlsKey == NULL) {
if (GetLastError() != ERROR_SUCCESS)
osi_panic("TlsGetValue failed", __FILE__, __LINE__);
}
static dataT getfundata(Tree *B) {
- dataT *tlsData;
-
- // Retrieve a data pointer for the current thread.
- tlsData = (dataT *) TlsGetValue(TlsDataIndex);
+ dataT *tlsData;
+
+ // Retrieve a data pointer for the current thread.
+ tlsData = (dataT *) TlsGetValue(TlsDataIndex);
if (tlsData == NULL) {
if (GetLastError() != ERROR_SUCCESS)
osi_panic("TlsGetValue failed", __FILE__, __LINE__);
static void setfunkey(Tree *B, keyT theKey) {
keyT *tlsKey;
- tlsKey = (keyT *) TlsGetValue(TlsKeyIndex);
+ tlsKey = (keyT *) TlsGetValue(TlsKeyIndex);
if (tlsKey == NULL) {
if (GetLastError() != ERROR_SUCCESS)
osi_panic("TlsGetValue failed", __FILE__, __LINE__);
tlsKey = malloc(sizeof(keyT));
-
- if (!TlsSetValue(TlsKeyIndex, tlsKey))
+
+ if (!TlsSetValue(TlsKeyIndex, tlsKey))
osi_panic("TlsSetValue failed", __FILE__, __LINE__);
}
static void setfundata(Tree *B, dataT theData) {
dataT *tlsData;
- tlsData = (dataT *) TlsGetValue(TlsDataIndex);
+ tlsData = (dataT *) TlsGetValue(TlsDataIndex);
if (tlsData == NULL) {
if (GetLastError() != ERROR_SUCCESS)
osi_panic("TlsGetValue failed", __FILE__, __LINE__);
tlsData = malloc(sizeof(dataT));
-
- if (!TlsSetValue(TlsDataIndex, tlsData))
+
+ if (!TlsSetValue(TlsDataIndex, tlsData))
osi_panic("TlsSetValue failed", __FILE__, __LINE__);
}
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,
+ getnodenumber(B, leafNode),
+ data.fid.volume,
data.fid.vnode,
data.fid.unique);
- } else
+ } else
StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: not found!\n");
OutputDebugString(B->message);
#endif
#ifdef DEBUG_BTREE
if (findslot == BTERROR) {
- StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n",
lo, hi, getnodenumber(B, curr), curr);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
}
findslot = findKey(B, curr, mid + 1, hi);
break;
case BTERROR:
- StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n",
lo, hi, getnodenumber(B, curr), curr);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
}
if (isleaf(curr) && findslot == 0)
{
- StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n",
lo, hi, findslot, getnodenumber(B, curr), curr);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
}
if (isleaf(curr))
findslot = BTLOWER; /* not found in the tree */
else
- findslot = 0;
- }
+ findslot = 0;
+ }
else if ((comp = comparekeys(B)(getfunkey(B), getkey(curr, slot - 1), 0)) >= 0) {
findslot = slot - 1;
} else if (comp < diff) {
}
} else { /* or check following slot */
if (slot == numentries(curr)) {
- if (isleaf(curr) && numentries(curr) == getfanout(B))
+ if (isleaf(curr) && numentries(curr) == getfanout(B))
findslot = BTUPPER;
- else
+ else
findslot = slot;
} else if ((comp = comparekeys(B)(getfunkey(B), getkey(curr, slot + 1), 0)) < 0) {
findslot = slot;
if (findslot == BTERROR || isleaf(curr) && findslot == 0)
{
- StringCbPrintfA(B->message, sizeof(B->message), "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n",
getnodenumber(B, curr), curr, slot, diff, comp, findslot);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
}
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
/***************** recurse down and split back up ******************/
-static Nptr
+static Nptr
descendSplit(Tree *B, Nptr curr)
{
Nptr downNode = NONODE, sibling = NONODE;
}
/*************** determine location of inserted key ****************/
-static void
+static void
insertEntry(Tree *B, Nptr currNode, int slot, Nptr sibling, Nptr downPtr)
{
int split, i, j, k, x, y;
k = (slot >= split ? 1 : 0);
/*
- * Move entries from the top half of the current node to
+ * Move entries from the top half of the current node to
* to the sibling node.
* The number of entries to move is dependent upon where
* the new entry is going to be added in relationship to
*
* If the node that is being split is an internal node (i != 0)
* then we move one less entry due to the extra down pointer
- * when the split slot is not equal to the insertion slot
+ * when the split slot is not equal to the insertion slot
*/
for (x = split + k + j * i, y = 1; x <= getfanout(B); x++, y++) {
xferentry(currNode, x, sibling, y); /* copy entries to sibling */
/* set key separating nodes */
if (isleaf(sibling))
- key = getkey(sibling, 1);
+ key = getkey(sibling, 1);
else {
Nptr leaf = getfirstnode(sibling);
while ( isinternal(leaf) )
}
/************ place key into appropriate node & slot ***************/
-static void
+static void
placeEntry(Tree *B, Nptr node, int slot, Nptr downPtr)
{
int x;
/***************** split full node and set flags *******************/
-static Nptr
+static Nptr
split(Tree *B, Nptr node)
{
Nptr sibling;
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
/********************** remove old root node ***********************/
-static void
+static void
collapseRoot(Tree *B, Nptr oldRoot, Nptr newRoot)
{
/**************** recurse down and balance back up *****************/
-static Nptr
+static Nptr
descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc, Nptr parent)
{
Nptr newMe=NONODE, myLeft=NONODE, myRight=NONODE, lAnchor=NONODE, rAnchor=NONODE, newNode=NONODE;
}
newMe = descendBalance(B, newNode, myLeft, myRight, lAnchor, rAnchor, curr);
}
- else if ((slot > 0) && !comparekeys(B)(getfunkey(B), getkey(curr, slot), 0))
+ else if ((slot > 0) && !comparekeys(B)(getfunkey(B), getkey(curr, slot), 0))
{
Nptr next;
int exact = 0;
next = getdatanext(newNode);
/*
- * We only delete exact matches.
+ * We only delete exact matches.
*/
if (!comparekeys(B)(getfunkey(B), getdatakey(newNode), EXACT_MATCH)) {
/* exact match, free the first entry */
if (next == NONODE) {
/* delete this key as there are no more data values */
newMe = newNode;
- } else {
+ } else {
/* otherwise, there are more and we leave the key in place */
setnode(curr, slot, next);
putFreeNode(B, newNode);
setmergepath(B, NONODE);
}
} else if (next == NONODE) {
- /*
+ /*
* we didn't find an exact match and there are no more
* choices. so we leave it alone and remove nothing.
*/
newMe = NONODE;
setmergepath(B, NONODE);
} else {
- /* The first data node doesn't match but there are other
+ /* The first data node doesn't match but there are other
* options. So we must determine if any of the next nodes
* are the one we are looking for.
*/
prev = next;
next = getdatanext(next);
}
-
+
/* do not delete the key */
newMe = NONODE;
setmergepath(B, NONODE);
}
}
- else
+ else
{
newMe = NONODE; /* no deletion possible, key not found */
setmergepath(B, NONODE);
/******* merge a node pair & set emptied node up for removal *******/
-static Nptr
+static Nptr
merge(Tree *B, Nptr left, Nptr right, Nptr anchor)
{
int x, y, z;
/****** shift entries in a node pair & adjust anchor key value *****/
-static Nptr
+static Nptr
shift(Tree *B, Nptr left, Nptr right, Nptr anchor)
{
int i, x, y, z;
#ifdef DEBUG_BTREE
- StringCbPrintfA(B->message, sizeof(B->message), "SHIFT: left %d, right %d, anchor %d.\n",
- getnodenumber(B, left),
- getnodenumber(B, right),
+ StringCbPrintfA(B->message, sizeof(B->message), "SHIFT: left %d, right %d, anchor %d.\n",
+ getnodenumber(B, left),
+ getnodenumber(B, right),
getnodenumber(B, anchor));
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
showNode(B, "pre-shift anchor", anchor);
#endif
i = isinternal(left);
-
+
if (numentries(left) < numentries(right)) { /* shift entries to left */
y = (numentries(right) - numentries(left)) >> 1;
x = numentries(left) + y;
for (z = numentries(right); z > 0; z--) /* adjust increased node */
pushentry(right, z, y);
-
+
setfunkey(B, getkey(left, x)); /* set new anchor key value */
z = getSlot(B, anchor);
if (z <= BTERROR)
xferentry(left, x, right, y); /* transfer entries over */
clrentry(left, x);
}
- }
+ }
#ifdef DEBUG_BTREE
else {
DebugBreak();
}
static void
-_pushentry(Nptr node, int entry, int offset)
+_pushentry(Nptr node, int entry, int offset)
{
if (getkey(node,entry + offset).name != NULL)
free(getkey(node,entry + offset).name);
\***********************************************************************/
/********************* Set up initial pool of free nodes ***********/
-static void
+static void
initFreeNodePool(Tree *B, int quantity)
{
int i;
}
setnextnode(p, NONODE); /* indicates end of free node list */
setallnode(p, NONODE); /* indicates end of all node list */
-
+
setpoolsize(B, quantity);
}
}
/************** take a free B+tree node from the pool **************/
-static Nptr
+static Nptr
getFreeNode(Tree *B)
{
Nptr newNode = getfirstfreenode(B);
/************* return a deleted B+tree node to the pool ************/
-static void
+static void
putFreeNode(Tree *B, Nptr node)
{
int i;
/******* fill a free data node with a key and associated data ******/
-static Nptr
+static Nptr
getDataNode(Tree *B, keyT key, dataT data)
{
Nptr newNode = getFreeNode(B);
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));
}
-void
+void
listBtreeNodes(Tree *B, const char * parent_desc, Nptr node)
{
int i;
StringCbPrintfA(B->message, sizeof(B->message), "%s - NoNode!!!\n");
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
return;
- }
-
+ }
+
if (!isnode(node))
{
data = getdatavalue(node);
- StringCbPrintfA(B->message, sizeof(B->message), "%s - data node %d (%d.%d.%d)\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "%s - data node %d (%d.%d.%d)\n",
parent_desc, getnodenumber(B, node),
data.fid.volume, data.fid.vnode, data.fid.unique);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
return;
- } else
+ } else
showNode(B, parent_desc, node);
if ( isinternal(node) || isroot(node) ) {
}
/*********************** B+tree data printer ***********************/
-void
+void
listBtreeValues(Tree *B, Nptr n, int num)
{
int slot;
}
prev = getkey(n, slot);
data = getdatavalue(getnode(n, slot));
- StringCbPrintfA(B->message, sizeof(B->message), "%8S (%d.%d.%d)\n",
+ StringCbPrintfA(B->message, sizeof(B->message), "%8S (%d.%d.%d)\n",
prev.name, data.fid.volume, data.fid.vnode, data.fid.unique);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
if (++slot > numentries(n))
}
/******************** entire B+tree data printer *******************/
-void
+void
listAllBtreeValues(Tree *B)
{
listBtreeValues(B, getleaf(B), BTERROR);
}
#endif /* DEBUG_BTREE */
-void
+void
findAllBtreeValues(Tree *B)
{
int num = -1;
if ( l != n ){
if (l == NONODE)
StringCbPrintfA(B->message, sizeof(B->message),"BOMB %8S cannot be found\n", prev.name);
- else
+ else
StringCbPrintfA(B->message, sizeof(B->message),"BOMB lookup(%8S) finds wrong node\n", prev.name);
osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
#ifdef DEBUG_BTREE
if (++slot > numentries(n))
n = getnextnode(n), slot = 1;
- }
+ }
}
-/*
+/*
* the return must be -1, 0, or 1. stricmp() in MSVC 8.0
* does not return only those values.
*
* the sorting of the tree is by case insensitive sort order
* therefore, unless the strings actually match via a case
* insensitive search do we want to perform the case sensitive
- * match. Otherwise, the search order might be considered
+ * match. Otherwise, the search order might be considered
* to be inconsistent when the EXACT_MATCH flag is set.
*/
int
fschar_t * fsname = NULL;
normchar_t * entry = NULL;
- if (op->scp->dirBplus == NULL ||
+ if (op->scp->dirBplus == NULL ||
op->dataVersion > op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
} else {
rc = CM_ERROR_AMBIGUOUS_FILENAME;
bplus_lookup_ambiguous++;
- }
+ }
} else {
rc = ENOENT;
bplus_lookup_misses++;
Nptr leafNode = NONODE;
LARGE_INTEGER start, end;
- if (op->scp->dirBplus == NULL ||
+ if (op->scp->dirBplus == NULL ||
op->dataVersion > op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
} else {
rc = CM_ERROR_AMBIGUOUS_FILENAME;
bplus_lookup_ambiguous++;
- }
+ }
} else {
rc = ENOENT;
bplus_lookup_misses++;
}
-/*
+/*
On entry:
op->scp->dirlock is write locked
LARGE_INTEGER start, end;
normchar_t * normalizedName = NULL;
- if (op->scp->dirBplus == NULL ||
+ if (op->scp->dirBplus == NULL ||
op->dataVersion != op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
return rc;
}
-/*
+/*
On entry:
op->scp->dirlock is write locked
LARGE_INTEGER start, end;
normchar_t * normalizedEntry = NULL;
- if (op->scp->dirBplus == NULL ||
+ if (op->scp->dirBplus == NULL ||
op->dataVersion != op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
} else {
clientchar_t * cname = NULL;
- /* We need to lookup the 8dot3 name to determine what the
+ /* We need to lookup the 8dot3 name to determine what the
* matching long name is
*/
leafNode = bplus_Lookup(op->scp->dirBplus, key);
rc = CM_ERROR_INEXACT_MATCH;
} else {
rc = CM_ERROR_AMBIGUOUS_FILENAME;
- }
+ }
}
if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
}
}
}
-
+
QueryPerformanceCounter(&end);
bplus_remove_time += (end.QuadPart - start.QuadPart);
free(normalizedEntry);
return rc;
-
+
}
afsi_log(" Free: %-16I64d", bplus_free_time);
}
-static cm_direnum_t *
+static cm_direnum_t *
cm_BPlusEnumAlloc(afs_uint32 entries)
{
cm_direnum_t * enump;
return enump;
}
-long
-cm_BPlusDirEnumerate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
- afs_uint32 locked, clientchar_t * maskp,
+long
+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)
{
afs_uint32 count = 0, slot, numentries;
/* 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
- * recycled while the enumeration is active.
+ /*
+ * 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);
}
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++ ) {
return rc;
}
-long
+long
cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
{
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 dscp_errorCode = 0;
afs_uint32 count;
afs_uint32 code = 0;
cm_req_t req;
+ int i;
+ cm_scache_t *tscp;
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));
- for ( count = 0; count < enump->count; count++ ) {
- cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
- int i;
+ bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ 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;
+ bsp->counter++;
+
+ 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 */
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);
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;
+ bs_errorCodep[i] = &enump->entry[count].errorCode;
if (bsp->counter == AFSCBMAX) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ 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;
+ }
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.
+ */
+ 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) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ 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);
+
+ return code;
+}
+
+/*
+ * 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 = NULL;
+ afs_uint32 ** bs_errorCodep = NULL;
+ afs_uint32 dscp_errorCode = 0;
+ afs_uint32 scp_errorCode = 0;
+ afs_uint32 code = 0;
+ afs_uint32 i;
+ cm_req_t req;
+ cm_scache_t *tscp;
+
+ 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) {
+ code = ENOMEM;
+ goto done;
+ }
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+ bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ 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;
+ 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;
+ 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 (!(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;
+ 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;
+ enump->entry[i].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ bs_errorCodep[bsp->counter] = &enump->entry[i].errorCode;
+ bsp->counter++;
}
- if (bsp->counter > 0)
+ if (bsp->counter > 0) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ /* Now process any errors that might have occurred */
+ 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);
- free(bsp);
return code;
}
-static 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;
+ cm_bulkStat_t *bsp = NULL;
+ afs_uint32 ** bs_errorCodep = NULL;
+ afs_uint32 dscp_errorCode = 0;
afs_uint32 count;
afs_uint32 code = 0;
cm_req_t req;
+ cm_scache_t *tscp;
+ int i;
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));
- for ( count = enump->next; count < enump->count; count++ ) {
- cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
- int i;
+ bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
+ if (!bs_errorCodep) {
+ 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;
+ 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 */
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;
+ 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;
enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ bs_errorCodep[bsp->counter] = &enump->entry[count].errorCode;
+ 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)
+ 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);
- free(bsp);
return code;
}
long
cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
-{
+{
+ long code;
+
if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
if (entrypp)
*entrypp = NULL;
return CM_ERROR_INVAL;
}
- if (enump->fetchStatus &&
- !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
- cm_BPlusDirEnumBulkStatNext(enump);
+ if (enump->fetchStatus &&
+ !(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 ) {
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;
return CM_ERROR_INVAL;
}
- if (enump->fetchStatus &&
- !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
- cm_BPlusDirEnumBulkStatNext(enump);
+ if (enump->fetchStatus &&
+ !(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 ) {
}
}
-long
+long
cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
{
afs_uint32 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++ ) {
entryp->name,
entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique,
entryp->shortName,
- type,
+ type,
dv);
osi_Log0(afsd_logp, osi_LogSaveString(afsd_logp, buffer));