/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
+#include <afsconfig.h>
#include <afs/param.h>
+#include <roken.h>
+
#include <afs/stds.h>
#include <windows.h>
cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags);
static long
-cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked);
+cm_DirCheckStatus(cm_dirOp_t * op, int locked);
static long
cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified);
static long
cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs);
+static long
+cm_DirPrefetchBuffers(cm_dirOp_t * op);
/* compute how many 32 byte entries an AFS 3 dir requires for storing
* the specified name.
*/
-long
-cm_NameEntries(char *namep, long *lenp)
+long
+cm_NameEntries(char *namep, size_t *lenp)
{
long i;
-
+
i = (long)strlen(namep);
if (lenp) *lenp = i;
return 1 + ((i+16) >> 5);
entry is a string name.
On entry:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
On exit:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
/* Return the length of a directory in pages
On entry:
- op->scp->mx is locked
+ op->scp->rw is locked
On exit:
- op->scp->mx is locked
+ op->scp->rw is locked
The first directory page for op->scp should not be locked by the
calling thread.
/* Delete a directory entry.
On entry:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
On exit:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
/* Find a bunch of contiguous entries; at least nblobs in a row.
- Called with op->scp->mx */
+ Called with op->scp->rw */
static long
cm_DirFindBlobs(cm_dirOp_t * op, int nblobs)
{
dhpModified = TRUE;
}
+ /* the create flag is not set for the GetPage call below
+ since the page should have been added if necessary
+ above. */
code = cm_DirGetPage(op, i, &pagebuf, &pp);
if (code) {
cm_DirReleasePage(op, &dhpbuf, dhpModified);
return -1;
}
-/* Add a page to a directory.
+/* Add a page to a directory.
- Called with op->scp->mx
+ Called with op->scp->rw
*/
static long
cm_DirAddPage(cm_dirOp_t * op, int pageno)
/* Free a whole bunch of directory entries.
- Called with op->scp->mx
+ Called with op->scp->rw
*/
static long
cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs)
* directory header page are allocated, 1 to the page header, 4 to the
* allocation map and 8 to the hash table.
*
- * Called with op->scp->mx unlocked
+ * Called with op->scp->rw unlocked
*/
int
cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent)
return rc;
}
+
/* Look up a file name in directory.
On entry:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
On exit:
- op->scp->mx is unlocked
+ op->scp->rw is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
LARGE_INTEGER start;
LARGE_INTEGER end;
+ lock_AssertNone(&op->scp->rw);
+
QueryPerformanceCounter(&start);
osi_Log2(afsd_logp, "cm_DirLookup for op 0x%p, entry[%s]",
code = cm_DirFindItem(op, entry,
&itembuf, &firstitem,
&pibuf, &previtem);
+
+ if (code == CM_ERROR_NOTINCACHE) {
+ code = cm_DirPrefetchBuffers(op);
+ if (code == 0)
+ code = cm_DirFindItem(op, entry, &itembuf, &firstitem,
+ &pibuf, &previtem);
+ }
+
if (code != 0) {
dir_lookup_misses++;
code = ENOENT;
/* Look up a file name in directory.
On entry:
- op->scp->mx is locked
+ op->scp->rw is locked
On exit:
- op->scp->mx is locked
+ op->scp->rw is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
/* Apply a function to every directory entry in a directory.
On entry:
- op->scp->mx is locked
+ op->scp->rw is locked
On exit:
- op->scp->mx is locked
+ op->scp->rw is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
/* Check if a directory is empty
On entry:
- op->scp->mx is locked
+ op->scp->rw is locked
On exit:
- op->scp->mx is locked
+ op->scp->rw is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
/* Return a pointer to an entry, given its number.
On entry:
- scp->mx locked
+ scp->rw locked
if *bufferpp != NULL, then *bufferpp->mx is locked
During:
- scp->mx may be unlocked
+ scp->rw may be unlocked
*bufferpp may be released
On exit:
- scp->mx locked
+ scp->rw locked
if *bufferpp != NULL, then *bufferpp->mx is locked
*bufferpp should be released via cm_DirReleasePage() or any other
*blobpp = (cm_dirEntry_t *) (ep + 32 * (blobno & (CM_DIR_EPP - 1)));
return code;
-}
+}
int
cm_DirHash(char *string)
{
/* Hash a string to a number between 0 and NHASHENT. */
- register unsigned char tc;
- register int hval;
- register int tval;
+ unsigned char tc;
+ int hval;
+ int tval;
hval = 0;
while ((tc = (*string++))) {
hval *= 173;
* pointer is returned instead.
*
* On entry:
- * scp->mx locked
+ * scp->rw locked
*
* On exit:
- * scp->mx locked
+ * scp->rw locked
*/
static long
cm_DirFindItem(cm_dirOp_t * op,
}
}
-/* Begin a sequence of directory operations.
- * Called with scp->mx unlocked.
+/* Begin a sequence of directory operations.
+ * Called with scp->rw unlocked.
*/
long
cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
- afs_uint32 lockType, cm_dirOp_t * op)
+ afs_uint32 lockType, afs_uint32 flags, cm_dirOp_t * op)
{
long code;
int i, mxheld = 0, haveWrite = 0;
- osi_Log3(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p]",
- op, scp, userp);
+ osi_Log4(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p] lockType[0x%x]",
+ op, scp, userp, lockType);
memset(op, 0, sizeof(*op));
op->scp = scp;
cm_HoldUser(userp);
op->userp = userp;
- cm_InitReq(&op->req);
+ op->req = *reqp; /* copy the values from the input */
op->dirtyBufCount = 0;
op->nBuffers = 0;
if (lockType == CM_DIRLOCK_WRITE) {
lock_ObtainWrite(&scp->dirlock);
haveWrite = 1;
- } else {
+ } else {
lock_ObtainRead(&scp->dirlock);
haveWrite = 0;
}
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
mxheld = 1;
code = cm_DirCheckStatus(op, 1);
if (code == 0) {
#ifdef USE_BPLUS
if (!cm_BPlusTrees ||
(scp->dirBplus &&
- scp->dirDataVersion == scp->dataVersion))
+ scp->dirDataVersion == scp->dataVersion))
{
/* we know that haveWrite matches lockType at this point */
switch (lockType) {
default:
osi_assert(haveWrite);
}
+ op->lockType = lockType;
} else {
- if (!(scp->dirBplus &&
- scp->dirDataVersion == scp->dataVersion))
+ if (!(scp->dirBplus &&
+ scp->dirDataVersion == scp->dataVersion))
{
repeat:
if (!haveWrite) {
if (mxheld) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
mxheld = 0;
}
- lock_ReleaseRead(&scp->dirlock);
- lock_ObtainWrite(&scp->dirlock);
+ lock_ConvertRToW(&scp->dirlock);
haveWrite = 1;
}
if (!mxheld) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
mxheld = 1;
}
- if (scp->dirBplus &&
+ if (scp->dirBplus &&
scp->dirDataVersion != scp->dataVersion)
{
bplus_dv_error++;
bplus_free_tree++;
freeBtree(scp->dirBplus);
scp->dirBplus = NULL;
- scp->dirDataVersion = -1;
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
}
- if (!scp->dirBplus) {
+ if ((!scp->dirBplus) &&
+ (!(flags & CM_DIROP_FLAG_NOBUILDTREE))) {
if (mxheld) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
mxheld = 0;
}
- cm_BPlusDirBuildTree(scp, userp, reqp);
+ code = cm_BPlusDirBuildTree(scp, userp, reqp);
+ osi_Log1(afsd_logp, "cm_BeginDirOp cm_BPlusDirBuildTree code 0x%x", code);
if (!mxheld) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
mxheld = 1;
}
- if (op->dataVersion != scp->dataVersion) {
- /* We lost the race, therefore we must update the
- * dirop state and retry to build the tree.
- */
- op->length = scp->length;
- op->newLength = op->length;
- op->dataVersion = scp->dataVersion;
- op->newDataVersion = op->dataVersion;
- goto repeat;
+ if (code) {
+ bplus_free_tree++;
+ freeBtree(scp->dirBplus);
+ scp->dirBplus = NULL;
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
+ } else {
+ if (op->dataVersion != scp->dataVersion) {
+ /* We lost the race, therefore we must update the
+ * dirop state and retry to build the tree.
+ */
+ op->length = scp->length;
+ op->newLength = op->length;
+ op->dataVersion = scp->dataVersion;
+ op->newDataVersion = op->dataVersion;
+ goto repeat;
+ }
+
+ if (scp->dirBplus)
+ scp->dirDataVersion = scp->dataVersion;
}
-
- if (scp->dirBplus)
- scp->dirDataVersion = scp->dataVersion;
- }
+ } /* build btree */
}
- switch (lockType) {
- case CM_DIRLOCK_NONE:
- lock_ReleaseWrite(&scp->dirlock);
- break;
- case CM_DIRLOCK_READ:
- lock_ConvertWToR(&scp->dirlock);
- break;
- case CM_DIRLOCK_WRITE:
- default:
- /* got it already */;
+ if (code == 0) {
+ switch (lockType) {
+ case CM_DIRLOCK_NONE:
+ lock_ReleaseWrite(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_READ:
+ lock_ConvertWToR(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_WRITE:
+ default:
+ /* got it already */;
+ }
+ op->lockType = lockType;
}
- haveWrite = 0;
}
#else
/* we know that haveWrite matches lockType at this point */
default:
osi_assert(haveWrite);
}
-#endif
op->lockType = lockType;
- if (mxheld)
- lock_ReleaseMutex(&scp->mx);
- } else {
+#endif
+ }
+
+ if (mxheld)
+ lock_ReleaseWrite(&scp->rw);
+
+ if (code) {
if (haveWrite)
lock_ReleaseWrite(&scp->dirlock);
else
lock_ReleaseRead(&scp->dirlock);
- if (mxheld)
- lock_ReleaseMutex(&scp->mx);
cm_EndDirOp(op);
+
+ osi_Log1(afsd_logp, "cm_BeginDirOp return code 0x%x", code);
}
return code;
}
/* Check if it is safe for us to perform local directory updates.
- Called with scp->mx unlocked. */
+ Called with op->scp->rw write-locked. */
int
cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
{
if (op->scp == NULL)
return 0;
- lock_ObtainMutex(&op->scp->mx);
+ lock_AssertWrite(&op->scp->rw);
+
code = cm_DirCheckStatus(op, 1);
if (code == 0 &&
- op->dataVersion == op->scp->dataVersion - 1) {
- /* only one set of changes happened between cm_BeginDirOp()
- and this function. It is safe for us to perform local
- changes. */
+ op->dataVersion == op->scp->dataVersion - 1)
+ {
+ /*
+ * only one set of changes happened between cm_BeginDirOp()
+ * and this function. It is safe for us to perform local
+ * changes. */
op->newDataVersion = op->scp->dataVersion;
op->newLength = op->scp->serverLength;
rc = 1;
+ } else {
+ /*
+ * The directory buffers are no longer up to date.
+ */
+ op->scp->bufDataVersionLow = op->scp->dataVersion;
+
+ rc = 0;
}
- lock_ReleaseMutex(&op->scp->mx);
-
+
if (rc)
osi_Log0(afsd_logp, "cm_CheckDirOpForSingleChange succeeded");
else
osi_Log3(afsd_logp,
- "cm_CheckDirOpForSingleChange failed. code=0x%x, old dv=%I64d, new dv=%I64d",
+ "cm_CheckDirOpForSingleChange failed. code=0x%x, old dv=%d, new dv=%d",
code, op->dataVersion, op->scp->dataVersion);
return rc;
}
-/* End a sequence of directory operations.
- * Called with op->scp->mx unlocked.*/
+/* End a sequence of directory operations.
+ * Called with op->scp->rw unlocked.*/
long
cm_EndDirOp(cm_dirOp_t * op)
{
long code = 0;
+ osi_Log4(afsd_logp, "Ending dirOp[0x%p] scp[0x%p] lockType[0x%x] with %d dirty buffer releases",
+ op, op->scp, op->lockType, op->dirtyBufCount);
+
if (op->scp == NULL)
return 0;
- osi_Log2(afsd_logp, "Ending dirOp 0x%p with %d dirty buffer releases",
- op, op->dirtyBufCount);
-
if (op->dirtyBufCount > 0) {
#ifdef USE_BPLUS
/* update the data version on the B+ tree */
- if (op->scp->dirBplus &&
+ if (op->scp->dirBplus &&
op->scp->dirDataVersion == op->dataVersion) {
switch (op->lockType) {
case CM_DIRLOCK_READ:
- lock_ReleaseRead(&op->scp->dirlock);
- /* fall through ... */
+ lock_ConvertRToW(&op->scp->dirlock);
+ op->lockType = CM_DIRLOCK_WRITE;
+ break;
case CM_DIRLOCK_NONE:
lock_ObtainWrite(&op->scp->dirlock);
op->lockType = CM_DIRLOCK_WRITE;
/* we made changes. We should go through the list of buffers
* and update the dataVersion for each. */
- lock_ObtainMutex(&op->scp->mx);
+ lock_ObtainWrite(&op->scp->rw);
code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion);
- lock_ReleaseMutex(&op->scp->mx);
+ op->scp->flags |= CM_SCACHEFLAG_LOCAL;
+ lock_ReleaseWrite(&op->scp->rw);
}
switch (op->lockType) {
osi_assertx(op->nBuffers == 0, "Buffer leak after dirOp termination");
+ if (code)
+ osi_Log1(afsd_logp, "cm_EndDirOp return code 0x%x", code);
+
return code;
}
-/* NOTE: Called without scp->mx and without bufferp->mx */
+/* NOTE: Called without scp->rw and without bufferp->mx */
static long
cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp)
{
osi_assert(i < CM_DIROP_MAXBUFFERS);
lock_ObtainMutex(&bufferp->mx);
- lock_ObtainMutex(&op->scp->mx);
+ lock_ObtainWrite(&op->scp->rw);
/* Make sure we are synchronized. */
osi_assert(op->lockType != CM_DIRLOCK_NONE);
CM_SCACHESYNC_BUFLOCKED);
if (code == 0 && bufferp->dataVersion != op->dataVersion) {
- osi_Log2(afsd_logp, "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %I64d. needs %I64d",
- bufferp->dataVersion, op->dataVersion);
-
- cm_SyncOpDone(op->scp, bufferp,
- CM_SCACHESYNC_NEEDCALLBACK |
- (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
- CM_SCACHESYNC_BUFLOCKED);
-
- code = CM_ERROR_INVAL;
+ osi_Log2(afsd_logp,
+ "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %d. needs %d",
+ bufferp->dataVersion, op->dataVersion);
+
+ cm_SyncOpDone(op->scp, bufferp,
+ CM_SCACHESYNC_NEEDCALLBACK |
+ (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
+ CM_SCACHESYNC_BUFLOCKED);
+ code = CM_ERROR_NOTINCACHE;
}
- lock_ReleaseMutex(&op->scp->mx);
+ lock_ReleaseWrite(&op->scp->rw);
lock_ReleaseMutex(&bufferp->mx);
if (code) {
}
}
-/* Note: Called without op->scp->mx */
+/* Note: Called without op->scp->rw */
static int
cm_DirOpFindBuffer(cm_dirOp_t * op, osi_hyper_t offset, cm_buf_t ** bufferpp)
{
}
-/* NOTE: called with scp->mx held or not depending on the flags */
+/* NOTE: called with scp->rw held or not depending on the flags */
static int
cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags)
{
version of the buffer with the data version of the
scp. */
if (!(flags & DIROP_SCPLOCKED)) {
- lock_ObtainMutex(&op->scp->mx);
+ lock_ObtainWrite(&op->scp->rw);
}
/* first make sure that the buffer is idle. It should
osi_assert(bufferp->dataVersion == op->dataVersion);
#endif
- lock_ReleaseMutex(&op->scp->mx);
+ lock_ReleaseWrite(&op->scp->rw);
lock_ObtainMutex(&bufferp->mx);
if (flags & DIROP_SCPLOCKED) {
- lock_ObtainMutex(&op->scp->mx);
+ lock_ObtainWrite(&op->scp->rw);
}
if (flags & DIROP_MODIFIED) {
This should be called before cm_DirGetPage() is called per scp.
On entry:
- scp->mx locked state indicated by parameter
+ scp->rw locked state indicated by parameter
On exit:
- scp->mx same state as upon entry
+ scp->rw same state as upon entry
During:
- scp->mx may be released
+ scp->rw may be released
*/
static long
-cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked)
+cm_DirCheckStatus(cm_dirOp_t * op, int scp_locked)
{
long code;
- if (!locked)
- lock_ObtainMutex(&op->scp->mx);
+ if (!scp_locked)
+ lock_ObtainWrite(&op->scp->rw);
code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (!locked)
- lock_ReleaseMutex(&op->scp->mx);
+ if (!scp_locked)
+ lock_ReleaseWrite(&op->scp->rw);
osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x",
op, code);
return code;
}
+/* Attempt to prefetch all the buffers for this operation.
+
+ Called with scp->rw unlocked
+ */
+static long
+cm_DirPrefetchBuffers(cm_dirOp_t * op)
+{
+ long code = 0;
+ osi_hyper_t offset;
+ cm_buf_t *bufferp = NULL;
+
+ osi_Log1(afsd_logp, "cm_DirPrefetchBuffers for op 0x%p", op);
+
+ /* prefetching is only done on read operations where we don't
+ expect the data version to change. */
+ if (op->dataVersion != op->newDataVersion) {
+ osi_Log0(afsd_logp, "Skipping prefetch for write operation.");
+ return CM_ERROR_INVAL;
+ }
+
+ lock_ObtainWrite(&op->scp->rw);
+
+ /* When we are prefetching a file, we first flush out any of its
+ contents just to make sure that we don't end up with buffers
+ that was locally modified. */
+
+ if (op->scp->flags & CM_SCACHEFLAG_LOCAL)
+ op->scp->bufDataVersionLow = op->scp->dataVersion;
+
+ offset = ConvertLongToLargeInteger(0);
+ while (LargeIntegerLessThan(offset, op->scp->length)) {
+ osi_Log2(afsd_logp, "Trying prefetch for offset %08x:%08x",
+ offset.HighPart, offset.LowPart);
+ lock_ReleaseWrite(&op->scp->rw);
+
+ code = buf_Get(op->scp, &offset, &op->req, &bufferp);
+
+ lock_ObtainWrite(&op->scp->rw);
+
+ if (code)
+ break;
+
+ while (1) {
+
+ code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
+ CM_SCACHESYNC_NEEDCALLBACK |
+ (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+
+ if (code)
+ break;
+
+ cm_SyncOpDone(op->scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK |
+ (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+
+ if (cm_HaveBuffer(op->scp, bufferp, 0))
+ break;
+
+ code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
+ if (code)
+ break;
+ }
+
+ if (code)
+ break;
+
+ if (bufferp) {
+ buf_Release(bufferp);
+ bufferp = NULL;
+ }
+
+ offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(cm_data.buf_blockSize));
+ }
+
+ lock_ReleaseWrite(&op->scp->rw);
+
+ osi_Log1(afsd_logp, "cm_DirPrefetchBuffers returning code 0x%x", code);
+
+ return code;
+}
+
/* Release a directory buffer that was obtained via a call to
cm_DirGetPage() or any other function that returns a locked, held,
directory page buffer.
- Called with scp->mx unlocked
+ Called with scp->rw unlocked
*/
static long
cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified)
released and a new buffer returned that contains the requested
page.
+ If the specified page exists beyond the EOF for the scp, a new
+ buffer will be allocated only if create is set to TRUE.
+
Note: If a buffer is specified on entry via bufferpp, it is assumed
that the buffer is unmodified. If the buffer is modified, it
should be released via cm_DirReleasePage().
On entry:
- scp->mx unlocked.
+ scp->rw unlocked.
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
On exit:
- scp->mx unlocked
+ scp->rw unlocked
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
During:
- scp->mx will be obtained and released
+ scp->rw will be obtained and released
*/
static long
goto _has_buffer;
}
- code = buf_Get(op->scp, &bufferOffset, &bufferp);
+ code = buf_Get(op->scp, &bufferOffset, &op->req, &bufferp);
if (code) {
osi_Log1(afsd_logp, " buf_Get returned code 0x%x", code);
bufferp = NULL;
bufferp = NULL;
goto _exit;
}
-
-#if 0
- /* The code below is for making sure the buffer contains
- current data. This is a bad idea, since the whole point of
- doing directory updates locally is to avoid fetching all
- the data from the server. */
- while (1) {
- lock_ObtainMutex(&op->scp->mx);
- code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
- CM_SCACHESYNC_NEEDCALLBACK |
- CM_SCACHESYNC_READ |
- CM_SCACHESYNC_BUFLOCKED);
-
- if (code) {
- lock_ReleaseMutex(&op->scp->mx);
- break;
- }
-
- cm_SyncOpDone(op->scp, bufferp,
- CM_SCACHESYNC_NEEDCALLBACK |
- CM_SCACHESYNC_READ |
- CM_SCACHESYNC_BUFLOCKED);
-
- if (cm_HaveBuffer(op->scp, bufferp, 1)) {
- lock_ReleaseMutex(&op->scp->mx);
- break;
- }
-
- lock_ReleaseMutex(&bufferp->mx);
- code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
- lock_ReleaseMutex(&op->scp->mx);
- lock_ObtainMutex(&bufferp->mx);
-
- if (code)
- break;
- }
-
- if (code) {
- cm_DirOpDelBuffer(op, bufferp, 0);
- buf_Release(bufferp);
- bufferp = NULL;
- goto _exit;
- }
-#endif
}
_has_buffer: