return code;
thyper.HighPart = 0; thyper.LowPart = 0;
- code = buf_Get(scp, &thyper, reqp, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, 0, &bufferp);
if (code)
return code;
if (code)
goto done;
- if (cm_HaveBuffer(scp, bufferp, 1))
+ if (cm_HaveBuffer(scp, bufferp, 1)) {
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
break;
+ }
/* otherwise, load the buffer and try again */
lock_ReleaseMutex(&bufferp->mx);
bufferp = NULL;
}
- code = buf_Get(scp, &thyper, reqp, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, 0, &bufferp);
if (code) {
/* if buf_Get() fails we do not have a buffer object to lock */
bufferp = NULL;
{
char temp[MOUNTPOINTLEN];
osi_hyper_t offset;
+ afs_uint32 bytesRead = 0;
/* otherwise, we have to read it in */
offset.LowPart = offset.HighPart = 0;
- code = cm_GetData(scp, &offset, temp, MOUNTPOINTLEN, userp, reqp);
+ code = cm_GetData(scp, &offset, temp, MOUNTPOINTLEN, &bytesRead, userp, reqp);
if (code)
goto done;
if (targetType == BACKVOL
&& (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
== CM_SCACHEFLAG_RO) {
- code = CM_ERROR_NOSUCHVOLUME;
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
goto done;
}
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (--scp->linkCount == 0) {
- scp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&scp->flags, CM_SCACHEFLAG_DELETED);
lock_ObtainWrite(&cm_scacheLock);
cm_AdjustScacheLRU(scp);
- cm_RemoveSCacheFromHashTable(scp);
lock_ReleaseWrite(&cm_scacheLock);
}
cm_DiscardSCache(scp);
{
char temp[MOUNTPOINTLEN];
osi_hyper_t offset;
+ afs_uint32 bytesRead = 0;
/* read the link data from the file server */
offset.LowPart = offset.HighPart = 0;
- code = cm_GetData(linkScp, &offset, temp, MOUNTPOINTLEN, userp, reqp);
+ code = cm_GetData(linkScp, &offset, temp, MOUNTPOINTLEN, &bytesRead, userp, reqp);
if (code)
return code;
continue;
rxconnp = cm_GetRxConn(connp);
- if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
+ if (SERVERHASINLINEBULK(connp)) {
code = RXAFS_InlineBulkStatus(rxconnp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
if (code == RXGEN_OPCODE) {
- cm_SetServerNoInlineBulk(connp->serverp, 1);
+ SET_SERVERHASNOINLINEBULK(connp);
} else {
inlinebulk = 1;
}
}
if (!inlinebulk) {
+ /*
+ * It is important to note that RXAFS_BulkStatus is quite braindead.
+ * The AFS 3.6 file server implementation returns arrays that are
+ * sized to hold responses for all of the requested FIDs but it only
+ * populates their contents up to the point where it detects an error.
+ * Unfortunately, it does inform the caller which entries were filled
+ * and which were not. The caller has no ability to determine which
+ * FID the RPC return code applies to or which of the FIDs valid status
+ * info and callbacks have been issued for. As a result, when an
+ * error is returned, none of the data received can be trusted.
+ */
code = RXAFS_BulkStatus(rxconnp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
}
if (code) {
osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x",
inlinebulk ? "Inline" : "", code);
+ if (!inlinebulk) {
+ /*
+ * Since an error occurred and it is impossible to determine
+ * the context in which the returned error code should be
+ * interpreted, we return the CM_ERROR_BULKSTAT_FAILURE error
+ * which indicates that Bulk Stat cannot be used for the
+ * current request. The caller should fallback to using
+ * individual RXAFS_FetchStatus calls.
+ */
+ code = CM_ERROR_BULKSTAT_FAILURE;
+ }
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
break;
}
&bbp->callbacks[j],
&volSync,
CM_CALLBACK_MAINTAINCOUNT|CM_CALLBACK_BULKSTAT);
- InterlockedIncrement(&scp->activeRPCs);
- if (!lostRace)
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
code = cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, CM_MERGEFLAG_BULKSTAT);
+ }
lock_ReleaseWrite(&scp->rw);
} else {
lock_ReleaseRead(&scp->rw);
goto _done;
}
- volp = cm_GetVolumeByFID(fidp);
+ volp = cm_FindVolumeByFID(fidp, userp, reqp);
if (!volp) {
spaceAvail = 0;
goto _done;
{
long code;
int shrinking;
+ int available;
/* start by locking out buffer creation */
lock_ObtainWrite(&scp->bufCreateLock);
* than where we're truncating the file, set truncPos to this
* new value.
*/
- if (!shrinking)
+ if (!shrinking) {
+ cm_SyncOpDone(scp, NULL,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
goto startover;
+ }
if (!(scp->mask & CM_SCACHEMASK_TRUNCPOS)
|| LargeIntegerLessThan(*sizep, scp->length)) {
/* set trunc pos */
scp->mask |= CM_SCACHEMASK_LENGTH;
}
else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
- /* really extending the file */
- /* Check to see if we have sufficient quota */
- if (cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp)) {
+ /*
+ * Really extending the file so must check to see if we
+ * have sufficient quota. cm_IsSpaceAvailable() obtains
+ * the cm_scache.rw lock on the volume root directory.
+ * vnode 1 < scp->fid.vnode therefore calling cm_IsSpaceAvailable
+ * while holding scp->rw is a lock order violation.
+ * Dropping it is ok because we are holding scp->bufCreateLock
+ * which prevents the size of the file from changing.
+ */
+ afs_uint64 nextChunk = scp->length.QuadPart;
+
+ nextChunk -= (nextChunk & 0xFFFFF);
+ nextChunk += 0x100000;
+
+ if (sizep->QuadPart > nextChunk) {
+ lock_ReleaseWrite(&scp->rw);
+ available = cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp);
+ lock_ObtainWrite(&scp->rw);
+ } else {
+ /*
+ * The file server permits 1MB quota overruns so only check
+ * when the file size increases by at least that much.
+ */
+ available = 1;
+ }
+ if (available) {
scp->length = *sizep;
scp->mask |= CM_SCACHEMASK_LENGTH;
} else {
if (!cm_HaveCallback(scp)) {
lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
&newFileCallback, &volSync, 0);
- InterlockedIncrement(&scp->activeRPCs);
- if (!lostRace)
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
code = cm_MergeStatus( dscp, scp, &newFileStatus, &volSync,
userp, reqp, 0);
+ }
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
&newDirCallback, &volSync, 0);
- InterlockedIncrement(&scp->activeRPCs);
- if (!lostRace)
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
code = cm_MergeStatus( dscp, scp, &newDirStatus, &volSync,
userp, reqp, 0);
+ }
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
if (scp) {
if (code == 0) {
lock_ObtainWrite(&scp->rw);
- scp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&scp->flags, CM_SCACHEFLAG_DELETED);
lock_ObtainWrite(&cm_scacheLock);
cm_AdjustScacheLRU(scp);
- cm_RemoveSCacheFromHashTable(scp);
lock_ReleaseWrite(&cm_scacheLock);
lock_ReleaseWrite(&scp->rw);
if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR))
goto post_syncopdone;
code = cm_SyncOp(scp, NULL, fileLock->userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK
- | CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_LOCK);
+ CM_SCACHESYNC_LOCK);
if (code) {
osi_Log1(afsd_logp,
cm_user_t * userp;
code = cm_SyncOp(scp, NULL, oldFileLock->userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK
- | CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_LOCK);
+ CM_SCACHESYNC_LOCK);
if (code) {
osi_Log1(afsd_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
lock_ReleaseWrite(&cm_scacheLock);