if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
tfid = scp->mountRootFid;
lock_ReleaseWrite(&scp->rw);
- code = cm_GetSCache(&tfid, outScpp, userp, reqp);
+ code = cm_GetSCache(&tfid, NULL, outScpp, userp, reqp);
lock_ObtainWrite(&scp->rw);
return code;
}
tfid = scp->mountRootFid;
lock_ReleaseWrite(&scp->rw);
- code = cm_GetSCache(&tfid, outScpp, userp, reqp);
+ code = cm_GetSCache(&tfid, NULL, outScpp, userp, reqp);
lock_ObtainWrite(&scp->rw);
}
if ( !tscp ) /* we did not find it in the dnlc */
{
dnlcHit = 0;
- code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
+ code = cm_GetSCache(&rock.fid, &dscp->fid, &tscp, userp, reqp);
if (code)
goto done;
}
cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
- code = cm_GetSCache(&fid, outScpp, userp, reqp);
+ code = cm_GetSCache(&fid, NULL, outScpp, userp, reqp);
_exit_cleanup:
if (fnamep)
&newDirStatus, &volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, reqp, &dscp->fid, 1, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
if (code == 0) {
cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
invalidate = 1;
+ if (cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirDeleteEntry(&dirop, fnamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, cnamep);
+#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
} else {
InterlockedDecrement(&scp->activeRPCs);
if (code == CM_ERROR_NOSUCHFILE) {
dscp->cbServerp = NULL;
}
}
+
cm_SyncOpDone(dscp, NULL, sflags);
lock_ReleaseWrite(&dscp->rw);
- if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
- cm_DirDeleteEntry(&dirop, fnamep);
-#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&dirop, cnamep);
-#endif
- }
cm_EndDirOp(&dirop);
if (invalidate && RDR_Initialized &&
!(tfid.vnode==0x1 && tfid.unique==0x1) )
{
osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
- return cm_GetSCache(&tfid, &tscp, NULL, NULL);
+ return cm_GetSCache(&tfid, NULL, &tscp, NULL, NULL);
}
#endif /* AFS_FREELANCE_CLIENT */
long filex;
AFSVolSync volSync;
cm_callbackRequest_t cbReq;
+ int lostRace;
long filesThisCall;
long i;
long j;
code = (&bbp->stats[0])->errorCode;
}
}
- } while (cm_Analyze(connp, userp, reqp, &tfid, &volSync, NULL, &cbReq, code));
+ } while (cm_Analyze(connp, userp, reqp, &tfid, 0, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
/*
if (inlinebulk && (&bbp->stats[j])->errorCode) {
cm_req_t treq = *reqp;
- cm_Analyze(NULL, userp, &treq, &tfid, &volSync, NULL, &cbReq, (&bbp->stats[j])->errorCode);
+ cm_Analyze(NULL, userp, &treq, &tfid, 0, &volSync, NULL, &cbReq, (&bbp->stats[j])->errorCode);
} else {
- code = cm_GetSCache(&tfid, &scp, userp, reqp);
+ code = cm_GetSCache(&tfid, &dscp->fid, &scp, userp, reqp);
if (code != 0)
continue;
(scp->flags & CM_SCACHEFLAG_EACCESS))
{
lock_ConvertRToW(&scp->rw);
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &bbp->callbacks[j],
- &volSync,
- CM_CALLBACK_MAINTAINCOUNT);
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &bbp->callbacks[j],
+ &volSync,
+ CM_CALLBACK_MAINTAINCOUNT);
InterlockedIncrement(&scp->activeRPCs);
- cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
+ if (!lostRace)
+ cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
lock_ReleaseWrite(&scp->rw);
} else {
lock_ReleaseRead(&scp->rw);
statusp->Mask = mask;
}
+int
+cm_IsSpaceAvailable(cm_fid_t * fidp, osi_hyper_t *sizep, cm_user_t *userp, cm_req_t *reqp)
+{
+ int spaceAvail = 1;
+ afs_uint32 code;
+ cm_conn_t *connp;
+ struct rx_connection * rxconnp;
+ AFSFetchVolumeStatus volStat;
+ cm_volume_t *volp = NULL;
+ afs_uint32 volType;
+ char *Name;
+ char *OfflineMsg;
+ char *MOTD;
+ char volName[32]="(unknown)";
+ char offLineMsg[256]="server temporarily inaccessible";
+ char motd[256]="server temporarily inaccessible";
+ osi_hyper_t freespace;
+
+ if (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
+ fidp->volume==AFS_FAKE_ROOT_VOL_ID)
+ {
+ goto _done;
+ }
+
+ volp = cm_GetVolumeByFID(fidp);
+ if (!volp) {
+ spaceAvail = 0;
+ goto _done;
+ }
+ volType = cm_VolumeType(volp, fidp->volume);
+ if (volType == ROVOL || volType == BACKVOL) {
+ spaceAvail = 0;
+ goto _done;
+ }
+
+ Name = volName;
+ OfflineMsg = offLineMsg;
+ MOTD = motd;
+
+ do {
+ code = cm_ConnFromFID(fidp, userp, reqp, &connp);
+ if (code) continue;
+
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(rxconnp, fidp->volume,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(rxconnp);
+
+ } while (cm_Analyze(connp, userp, reqp, fidp, 0, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, reqp);
+ if (code == 0) {
+ if (volStat.MaxQuota) {
+ freespace.QuadPart = 1024 * (afs_int64)min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
+ } else {
+ freespace.QuadPart = 1024 * (afs_int64)volStat.PartBlocksAvail;
+ }
+ spaceAvail = LargeIntegerGreaterThanOrEqualTo(freespace, *sizep);
+ }
+ /* the rpc failed, assume there is space and we can fail it later. */
+
+ _done:
+ if (volp)
+ cm_PutVolume(volp);
+
+ return spaceAvail;
+}
+
/* set the file size, and make sure that all relevant buffers have been
* truncated. Ensure that any partially truncated buffers have been zeroed
* to the end of the buffer.
}
else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
/* really extending the file */
- scp->length = *sizep;
- scp->mask |= CM_SCACHEMASK_LENGTH;
+ /* Check to see if we have sufficient quota */
+ if (cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp)) {
+ scp->length = *sizep;
+ scp->mask |= CM_SCACHEMASK_LENGTH;
+ } else {
+ code = CM_ERROR_SPACE;
+ goto syncopdone;
+ }
}
/* done successfully */
code = 0;
+ syncopdone:
cm_SyncOpDone(scp, NULL,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &scp->fid, &volSync, NULL, NULL, code));
+ &scp->fid, 1, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
cm_fid_t newFid;
cm_scache_t *scp = NULL;
int didEnd;
+ int lostRace;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newFileStatus;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, &cbReq, code));
+ &dscp->fid, 1, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
if (code)
dirop.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&dscp->rw);
- if (code == 0)
+ if (code == 0) {
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- else
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirCreateEntry(&dirop, fnamep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
+ } else {
InterlockedDecrement(&dscp->activeRPCs);
+ }
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &newFileCallback, &volSync, 0);
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &newFileCallback, &volSync, 0);
InterlockedIncrement(&scp->activeRPCs);
- cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
- userp, reqp, 0);
+ if (!lostRace)
+ cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
- if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
- cm_DirCreateEntry(&dirop, fnamep, &newFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
-#endif
- }
cm_EndDirOp(&dirop);
if (fnamep)
cm_fid_t newFid;
cm_scache_t *scp = NULL;
int didEnd;
+ int lostRace;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newDirStatus;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, &cbReq, code));
+ &dscp->fid, 1, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
if (code)
dirop.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&dscp->rw);
- if (code == 0)
+ if (code == 0) {
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- else
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirCreateEntry(&dirop, fnamep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
+ } else {
InterlockedDecrement(&dscp->activeRPCs);
+ }
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &newDirCallback, &volSync, 0);
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &newDirCallback, &volSync, 0);
InterlockedIncrement(&scp->activeRPCs);
- cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
- userp, reqp, 0);
+ if (!lostRace)
+ cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
- if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
- cm_DirCreateEntry(&dirop, fnamep, &newFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
-#endif
- }
cm_EndDirOp(&dirop);
free(fnamep);
rx_PutConnection(rxconnp);
osi_Log1(afsd_logp," RXAFS_Link returns 0x%x", code);
- } while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, reqp, &dscp->fid, 1, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
invalidate = 1;
- } else {
- InterlockedDecrement(&dscp->activeRPCs);
- }
- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&dscp->rw);
- if (code == 0) {
if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
cm_DirCreateEntry(&dirop, fnamep, &sscp->fid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&dirop, cnamep, &sscp->fid);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
if (invalidate && RDR_Initialized)
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ &dscp->fid, 1, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
dirop.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&dscp->rw);
- if (code == 0)
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- else
- InterlockedDecrement(&dscp->activeRPCs);
- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&dscp->rw);
-
if (code == 0) {
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
cm_DirCreateEntry(&dirop, fnamep, &newFid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
/* now try to create the new dir's entry, too, but be careful to
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ &dscp->fid, 1, &volSync, NULL, NULL, code));
code = cm_MapRPCErrorRmdir(code, reqp);
if (code)
if (code == 0) {
cm_dnlcRemove(dscp, cnamep);
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- } else {
- InterlockedDecrement(&dscp->activeRPCs);
- }
- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&dscp->rw);
-
- if (code == 0) {
if (cm_CheckDirOpForSingleChange(&dirop) && cnamep != NULL) {
+ lock_ReleaseWrite(&dscp->rw);
cm_DirDeleteEntry(&dirop, fnamep);
#ifdef USE_BPLUS
cm_BPlusDirDeleteEntry(&dirop, cnamep);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
if (scp) {
cm_req_t *reqp)
{
cm_conn_t *connp;
- long code;
+ long code = 0;
AFSFid oldDirAFSFid;
AFSFid newDirAFSFid;
- int didEnd;
AFSFetchStatus updatedOldDirStatus;
AFSFetchStatus updatedNewDirStatus;
AFSVolSync volSync;
- int oneDir;
+ int oneDir = 0;
+ int bTargetExists = 0;
struct rx_connection * rxconnp;
cm_dirOp_t oldDirOp;
cm_fid_t fileFid;
cm_dirOp_t newDirOp;
fschar_t * newNamep = NULL;
int free_oldNamep = FALSE;
- cm_scache_t *oldScp = NULL, *newScp = NULL;
+ cm_scache_t *oldScp = NULL, *oldTargetScp = NULL;
+ int rpc_skipped = 0;
memset(&volSync, 0, sizeof(volSync));
cm_ClientStrLen(cNewNamep) == 0)
return CM_ERROR_INVAL;
- /*
- * Before we permit the operation, make sure that we do not already have
- * an object in the destination directory that has a case-insensitive match
- * for this name UNLESS the matching object is the object we are renaming.
- */
- code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
- if (code) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed",
- oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
- goto done;
- }
-
- /* Case sensitive lookup. If this succeeds we are done. */
- code = cm_Lookup(newDscp, cNewNamep, 0, userp, reqp, &newScp);
- if (code) {
- /*
- * Case insensitive lookup. If this succeeds, it could have found the
- * same file with a name that differs only by case or it could be a
- * different file entirely.
- */
- code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
- if (code == 0) {
- /* found a matching object with the new name */
- if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
- /* and they don't match so return an error */
- osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
- newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
- code = CM_ERROR_EXISTS;
- }
- cm_ReleaseSCache(newScp);
- newScp = NULL;
- } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
- code = CM_ERROR_EXISTS;
- } else {
- /* The target does not exist. Clear the error and perform the rename. */
- code = 0;
- }
+ /* check for identical names */
+ if (oldDscp == newDscp &&
+ cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_RENAME_IDENTICAL",
+ oldDscp, newDscp);
+ return CM_ERROR_RENAME_IDENTICAL;
}
/* Check for RO volume */
- if (code == 0 &&
- (oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
- code = CM_ERROR_READONLY;
+ if ((oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
+ return CM_ERROR_READONLY;
}
- if (code)
- goto done;
-
if (oldNamep == NULL) {
code = -1;
#ifdef USE_BPLUS
}
}
-
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our call
* completes. We do this in vnode order so that we don't deadlock,
* which makes the code a little verbose.
*/
if (oldDscp == newDscp) {
- /* check for identical names */
- if (cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_RENAME_IDENTICAL",
- oldDscp, newDscp);
- code = CM_ERROR_RENAME_IDENTICAL;
- goto done;
- }
-
oneDir = 1;
cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
CM_DIROP_FLAG_NONE, &oldDirOp);
if (code)
goto done;
- didEnd = 0;
+ /*
+ * The source and destination directories are now locked and no other local
+ * changes can occur.
+ *
+ * Before we permit the operation, make sure that we do not already have
+ * an object in the destination directory that has a case-insensitive match
+ * for this name UNLESS the matching object is the object we are renaming.
+ */
+ code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
+ if (code) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed",
+ oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
+ rpc_skipped = 1;
+ goto post_rpc;
+ }
+
+ /* Case sensitive lookup. If this succeeds we are done. */
+ code = cm_Lookup(newDscp, cNewNamep, 0, userp, reqp, &oldTargetScp);
+ if (code) {
+ /*
+ * Case insensitive lookup. If this succeeds, it could have found the
+ * same file with a name that differs only by case or it could be a
+ * different file entirely.
+ */
+ code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &oldTargetScp);
+ if (code == 0) {
+ /* found a matching object with the new name */
+ if (cm_FidCmp(&oldScp->fid, &oldTargetScp->fid)) {
+ /* and they don't match so return an error */
+ osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
+ newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+ code = CM_ERROR_EXISTS;
+ }
+ cm_ReleaseSCache(oldTargetScp);
+ oldTargetScp = NULL;
+ } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+ code = CM_ERROR_EXISTS;
+ } else {
+ /* The target does not exist. Clear the error and perform the rename. */
+ code = 0;
+ }
+ } else {
+ bTargetExists = 1;
+ }
+
+ if (code) {
+ rpc_skipped = 1;
+ goto post_rpc;
+ }
newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
&volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
+ } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid, 1,
&volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
else
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
+ post_rpc:
/* update the individual stat cache entries for the directories */
if (oldDirOp.scp) {
lock_ObtainWrite(&oldDirOp.scp->dirlock);
oldDirOp.lockType = CM_DIRLOCK_WRITE;
}
- lock_ObtainWrite(&oldDscp->rw);
- if (code == 0)
+ lock_ObtainWrite(&oldDscp->rw);
+ if (code == 0) {
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
userp, reqp, CM_MERGEFLAG_DIROP);
- else
- InterlockedDecrement(&oldDscp->activeRPCs);
- cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&oldDscp->rw);
-
- if (code == 0 && cm_CheckDirOpForSingleChange(&oldDirOp)) {
+ if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (bTargetExists && oneDir) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, newNamep);
#ifdef USE_BPLUS
- diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
- if (diropCode == CM_ERROR_INEXACT_MATCH)
- diropCode = 0;
- else if (diropCode == EINVAL)
+ cm_BPlusDirDeleteEntry(&oldDirOp, cNewNamep);
#endif
- diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+ }
- if (diropCode == 0) {
- if (oneDir) {
- diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+ diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
+ if (diropCode == CM_ERROR_INEXACT_MATCH)
+ diropCode = 0;
+ else if (diropCode == EINVAL)
#endif
- }
+ diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
if (diropCode == 0) {
- diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+ if (oneDir) {
+ diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+ cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
#endif
+ }
+
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+#endif
+ }
}
+ lock_ObtainWrite(&oldDscp->rw);
}
+ } else {
+ if (!rpc_skipped)
+ InterlockedDecrement(&oldDscp->activeRPCs);
}
+ cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&oldDscp->rw);
+
cm_EndDirOp(&oldDirOp);
/* and update it for the new one, too, if necessary */
newDirOp.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&newDscp->rw);
- if (code == 0)
+ if (code == 0) {
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
userp, reqp, CM_MERGEFLAG_DIROP);
- else
- InterlockedIncrement(&newDscp->activeRPCs);
- cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&newDscp->rw);
-#if 0
- /*
- * The following optimization does not work.
- * When the file server processed a RXAFS_Rename() request the
- * FID of the object being moved between directories is not
- * preserved. The client does not know the new FID nor the
- * version number of the target. Not only can we not create
- * the directory entry in the new directory, but we can't
- * preserve the cached data for the file. It must be re-read
- * from the file server. - jaltman, 2009/02/20
- */
- if (code == 0) {
- /* we only make the local change if we successfully made
- the change in the old directory AND there was only one
- change in the new directory */
+ /*
+ * we only make the local change if we successfully made
+ * the change in the old directory AND there was only one
+ * change in the new directory
+ */
if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
+ lock_ReleaseWrite(&newDscp->rw);
+
+ if (bTargetExists && !oneDir) {
+ diropCode = cm_DirDeleteEntry(&newDirOp, newNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&newDirOp, cNewNamep);
+#endif
+ }
+
cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&newDirOp, cNewNamep, &fileFid);
#endif
+ lock_ObtainWrite(&newDscp->rw);
}
+ } else {
+ if (!rpc_skipped)
+ InterlockedIncrement(&newDscp->activeRPCs);
}
-#endif /* 0 */
+ cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&newDscp->rw);
+
cm_EndDirOp(&newDirOp);
}
- /*
- * After the rename the file server has invalidated the callbacks
- * on the file that was moved nor do we have a directory reference
- * to it anymore.
- */
- lock_ObtainWrite(&oldScp->rw);
- cm_DiscardSCache(oldScp);
- lock_ReleaseWrite(&oldScp->rw);
+ if (code == 0) {
+ /*
+ * After the rename the file server has invalidated the callbacks
+ * on the file that was moved and destroyed any target file.
+ */
+ lock_ObtainWrite(&oldScp->rw);
+ cm_DiscardSCache(oldScp);
+ lock_ReleaseWrite(&oldScp->rw);
+
+ if (RDR_Initialized)
+ RDR_InvalidateObject(oldScp->fid.cell, oldScp->fid.volume, oldScp->fid.vnode, oldScp->fid.unique,
+ oldScp->fid.hash, oldScp->fileType, AFS_INVALIDATE_CALLBACK);
+
+ if (oldTargetScp) {
+ lock_ObtainWrite(&oldTargetScp->rw);
+ cm_DiscardSCache(oldTargetScp);
+ lock_ReleaseWrite(&oldTargetScp->rw);
+
+ if (RDR_Initialized)
+ RDR_InvalidateObject(oldTargetScp->fid.cell, oldTargetScp->fid.volume, oldTargetScp->fid.vnode, oldTargetScp->fid.unique,
+ oldTargetScp->fid.hash, oldTargetScp->fileType, AFS_INVALIDATE_CALLBACK);
+ }
+ }
- if (RDR_Initialized)
- RDR_InvalidateObject(oldScp->fid.cell, oldScp->fid.volume, oldScp->fid.vnode, oldScp->fid.unique,
- oldScp->fid.hash, oldScp->fileType, AFS_INVALIDATE_CALLBACK);
done:
if (oldScp)
cm_ReleaseSCache(oldScp);
+ if (oldTargetScp)
+ cm_ReleaseSCache(oldTargetScp);
+
if (free_oldNamep)
free(oldNamep);
afs_int64 int_begin;
afs_int64 int_end;
- int_begin = MAX(pos->offset, neg->offset);
- int_end = MIN(pos->offset+pos->length, neg->offset+neg->length);
+ int_begin = max(pos->offset, neg->offset);
+ int_end = min(pos->offset+pos->length, neg->offset+neg->length);
if (int_begin < int_end) {
if (int_begin == pos->offset) {
osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
- if ((lockType != LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount != 0) ||
- (lockType == LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount < 0))
- {
- code = CM_ERROR_LOCK_NOT_GRANTED;
+#if 0
+ /*
+ * The file server prior to 1.6.2 does not report an accurate value
+ * and callbacks are not issued if the lock is dropped due to expiration.
+ */
+ if ((lockType != LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount != 0) ||
+ (lockType == LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount < 0))
+ {
+ code = CM_ERROR_LOCK_NOT_GRANTED;
osi_Log2(afsd_logp, "CALL SetLock FAILURE, fsLockCount %d code 0x%x", scp->fsLockCount, code);
- return code;
- }
+ return code;
+ }
+#endif
memset(&volSync, 0, sizeof(volSync));
&volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ } while (cm_Analyze(connp, userp, reqp, &cfid, 1, &volSync,
NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
code = RXAFS_ReleaseLock(rxconnp, &tfid, &volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ } while (cm_Analyze(connp, userp, reqp, &cfid, 1, &volSync,
NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
osi_Log1(afsd_logp, " ExtendLock returns %d", code);
} while (cm_Analyze(connp, userp, &req,
- &cfid, &volSync, NULL, NULL,
+ &cfid, 1, &volSync, NULL, NULL,
code));
code = cm_MapRPCError(code, &req);