}
/* return success if we can open this file in this mode */
-long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
- unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp,
+long cm_CheckNTOpen(cm_scache_t *scp,
+ unsigned int desiredAccess,
+ unsigned int shareAccess,
+ unsigned int createDisp,
+ afs_offs_t process_id,
+ afs_offs_t handle_id,
+ cm_user_t *userp, cm_req_t *reqp,
cm_lock_data_t **ldpp)
{
long rights;
long code = 0;
+ afs_uint16 session_id;
osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
+ /* compute the session id */
+ if (reqp->flags & CM_REQ_SOURCE_SMB)
+ session_id = CM_SESSION_SMB;
+ else if (reqp->flags & CM_REQ_SOURCE_REDIR)
+ session_id = CM_SESSION_IFS;
+ else
+ session_id = CM_SESSION_CMINT;
+
+ /* Ignore the SYNCHRONIZE privilege */
+ desiredAccess &= ~SYNCHRONIZE;
+
/* Always allow delete; the RPC will tell us if it's OK */
rights = 0;
if (desiredAccess == DELETE)
goto done_2;
+ /* Always allow reading attributes (Hidden, System, Readonly, ...) */
+ if (desiredAccess == FILE_READ_ATTRIBUTES)
+ goto done_2;
+
if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
code = CM_ERROR_NOACCESS;
if (code == 0 &&
- ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
- scp->fileType == CM_SCACHETYPE_FILE) {
+ !(shareAccess & FILE_SHARE_WRITE) &&
+ ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
+ scp->fileType == CM_SCACHETYPE_FILE) {
cm_key_t key;
unsigned int sLockType;
LARGE_INTEGER LOffset, LLength;
/* Check if there's some sort of lock on the file at the
moment. */
- key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
if (rights & PRSFS_WRITE)
sLockType = 0;
else
sLockType = LOCKING_ANDX_SHARED_LOCK;
+ key = cm_GenerateKey(session_id, process_id, 0);
+
/* single byte lock at offset 0x0100 0000 0000 0000 */
LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
LOffset.LowPart = CM_FLSHARE_OFFSET_LOW;
code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
if (code == 0) {
- (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
- if (!*ldpp) {
- code = ENOMEM;
- goto _done;
- }
+ (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
+ if (!*ldpp) {
+ code = ENOMEM;
+ goto _done;
+ }
- (*ldpp)->key = key;
- (*ldpp)->sLockType = sLockType;
- (*ldpp)->LOffset.HighPart = LOffset.HighPart;
- (*ldpp)->LOffset.LowPart = LOffset.LowPart;
- (*ldpp)->LLength.HighPart = LLength.HighPart;
- (*ldpp)->LLength.LowPart = LLength.LowPart;
+ (*ldpp)->key = key;
+ (*ldpp)->sLockType = sLockType;
+ (*ldpp)->LOffset.HighPart = LOffset.HighPart;
+ (*ldpp)->LOffset.LowPart = LOffset.LowPart;
+ (*ldpp)->LLength.HighPart = LLength.HighPart;
+ (*ldpp)->LLength.LowPart = LLength.LowPart;
} else {
- /* In this case, we allow the file open to go through even
- though we can't enforce mandatory locking on the
- file. */
+ /*
+ * In this case, we allow the file open to go through even
+ * though we can't enforce mandatory locking on the
+ * file. */
if (code == CM_ERROR_NOACCESS &&
- !(rights & PRSFS_WRITE))
+ !(rights & PRSFS_WRITE))
code = 0;
else {
- if (code == CM_ERROR_LOCK_NOT_GRANTED)
- code = CM_ERROR_SHARING_VIOLATION;
- }
+ if (code == CM_ERROR_LOCK_NOT_GRANTED)
+ code = CM_ERROR_SHARING_VIOLATION;
+ }
}
} else if (code != 0) {
goto _done;
extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
cm_lock_data_t ** ldpp)
{
- osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+ osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, ldpp ? *ldpp : 0);
lock_ObtainWrite(&scp->rw);
- if (*ldpp) {
+ if (ldpp && *ldpp) {
cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
(*ldpp)->key, 0, userp, reqp);
free(*ldpp);
return code;
}
-int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
+int cm_ExpandSysName(cm_req_t * reqp, clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
{
clientchar_t *tp;
int prefixCount;
+#ifdef _WIN64
+ int use_sysname64 = 0;
+
+ if (cm_sysName64Count > 0 && reqp && (reqp->flags & CM_REQ_WOW64) && (reqp->flags & CM_REQ_SOURCE_REDIR))
+ use_sysname64 = 1;
+#endif
tp = cm_ClientStrRChr(inp, '@');
if (tp == NULL)
if (outp == NULL)
return 1;
+#ifdef _WIN64
+ if (use_sysname64 && index >= cm_sysName64Count)
+ return -1;
+ else
+#endif
if (index >= cm_sysNameCount)
return -1;
prefixCount = (int)(tp - inp);
cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount); /* copy out "a." from "a.@sys" */
- outp[prefixCount] = 0; /* null terminate the "a." */
- cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
+ outp[prefixCount] = 0; /* null terminate the "a." */
+#ifdef _WIN64
+ if (use_sysname64)
+ cm_ClientStrCat(outp, outSizeCch, cm_sysName64List[index]);
+ else
+#endif
+ cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);
+
return 1;
}
return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
}
- if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
+ if (cm_ExpandSysName(reqp, namep, NULL, 0, 0) > 0) {
for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
- code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
+ code = cm_ExpandSysName(reqp, namep, tname, lengthof(tname), sysNameIndex);
if (code > 0) {
code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
#ifdef DEBUG_REFCOUNT
cm_dirOp_t dirop;
cm_scache_t *scp = NULL;
int free_fnamep = FALSE;
+ int invalidate = 0;
memset(&volSync, 0, sizeof(volSync));
}
/* make the RPC */
+ InterlockedIncrement(&dscp->activeRPCs);
+
afsFid.Volume = dscp->fid.volume;
afsFid.Vnode = dscp->fid.vnode;
afsFid.Unique = dscp->fid.unique;
cm_dnlcRemove(dscp, cnamep);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- } else if (code == CM_ERROR_NOSUCHFILE) {
- /* windows would not have allowed the request to delete the file
- * if it did not believe the file existed. therefore, we must
- * have an inconsistent view of the world.
- */
- dscp->cbServerp = NULL;
+ 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) {
+ /* windows would not have allowed the request to delete the file
+ * if it did not believe the file existed. therefore, we must
+ * have an inconsistent view of the world.
+ */
+ 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 &&
+ scp->fileType != CM_SCACHETYPE_FILE && scp->fileType != CM_SCACHETYPE_DIRECTORY)
+ RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+ dscp->fid.unique, dscp->fid.hash,
+ dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
+
if (scp) {
cm_ReleaseSCache(scp);
if (code == 0) {
}
cm_DiscardSCache(scp);
lock_ReleaseWrite(&scp->rw);
+ if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+ !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+ scp->fid.unique, scp->fid.hash,
+ scp->fileType, AFS_INVALIDATE_DELETED))
+ buf_ClearRDRFlag(scp, "unlink");
}
}
&bbp->callbacks[j],
&volSync,
CM_CALLBACK_MAINTAINCOUNT);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
lock_ReleaseWrite(&scp->rw);
} else {
lock_ReleaseRead(&scp->rw);
/* now make the RPC */
+ InterlockedIncrement(&scp->activeRPCs);
+
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
do {
code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
if (code == 0)
cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp, reqp,
CM_MERGEFLAG_FORCE|CM_MERGEFLAG_STOREDATA);
+ else
+ InterlockedDecrement(&scp->activeRPCs);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
/* if we're changing the mode bits, discard the ACL cache,
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
- if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
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);
+ 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);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_EndCallbackGrantingCall(scp, &cbReq,
&newFileCallback, &volSync, 0);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
userp, reqp, 0);
didEnd = 1;
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)
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
- if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
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);
+ 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);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_EndCallbackGrantingCall(scp, &cbReq,
&newDirCallback, &volSync, 0);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
userp, reqp, 0);
didEnd = 1;
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);
struct rx_connection * rxconnp;
cm_dirOp_t dirop;
fschar_t * fnamep = NULL;
+ int invalidate = 0;
memset(&volSync, 0, sizeof(volSync));
fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
lock_ObtainWrite(&dscp->rw);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- }
- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseWrite(&dscp->rw);
+ invalidate = 1;
- 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)
+ RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+ dscp->fid.unique, dscp->fid.hash,
+ dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
+
/* Update the linked object status */
if (code == 0) {
lock_ObtainWrite(&sscp->rw);
+ InterlockedIncrement(&sscp->activeRPCs);
cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
lock_ReleaseWrite(&sscp->rw);
}
}
long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, long flags,
- cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
+ cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp)
{
cm_conn_t *connp;
long code;
cm_dirOp_t dirop;
fschar_t *fnamep = NULL;
+ if (scpp)
+ *scpp = NULL;
+
/* Check for RO volume */
if (dscp->flags & CM_SCACHEFLAG_RO)
return CM_ERROR_READONLY;
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
dirop.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&dscp->rw);
- if (code == 0)
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- 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);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
userp, reqp, 0);
}
lock_ReleaseWrite(&scp->rw);
- cm_ReleaseSCache(scp);
+
+ if (scpp) {
+ *scpp = scp;
+ } else {
+ cm_ReleaseSCache(scp);
+ }
}
}
didEnd = 0;
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code == 0) {
cm_dnlcRemove(dscp, cnamep);
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- }
- 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_RemoveSCacheFromHashTable(scp);
lock_ReleaseWrite(&cm_scacheLock);
lock_ReleaseWrite(&scp->rw);
+ if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+ !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+ scp->fid.unique, scp->fid.hash,
+ scp->fileType, AFS_INVALIDATE_DELETED))
+ buf_ClearRDRFlag(scp, "rmdir");
}
}
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;
- }
-
- 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 {
- 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);
/* try the RPC now */
+ InterlockedIncrement(&oldDscp->activeRPCs);
+ if (!oneDir)
+ InterlockedIncrement(&newDscp->activeRPCs);
osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
oldDscp, newDscp);
do {
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);
- 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_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+#endif
+ }
+
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+ 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);
- 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);
+ }
+ }
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) {
AFSVolSync volSync;
afs_uint32 reqflags = reqp->flags;
+ 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;
+ osi_Log2(afsd_logp, "CALL SetLock FAILURE, fsLockCount %d code 0x%x", scp->fsLockCount, code);
+ return code;
+ }
+
memset(&volSync, 0, sizeof(volSync));
tfid.Volume = scp->fid.volume;
tfid.Unique = scp->fid.unique;
cfid = scp->fid;
- osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
-
reqp->flags |= CM_REQ_NORETRY;
lock_ReleaseWrite(&scp->rw);
if (force_client_lock && code != CM_ERROR_WOULDBLOCK)
code = 0;
+ cm_HoldUser(userp);
+
lock_ObtainWrite(&cm_scacheLock);
fileLock = cm_GetFileLock();
- lock_ReleaseWrite(&cm_scacheLock);
#ifdef DEBUG
fileLock->fid = scp->fid;
#endif
fileLock->key = key;
fileLock->lockType = Which;
- cm_HoldUser(userp);
fileLock->userp = userp;
fileLock->range = range;
fileLock->flags = (code == 0 ? 0 :
fileLock->lastUpdate = (code == 0 && !force_client_lock) ? time(NULL) : 0;
- lock_ObtainWrite(&cm_scacheLock);
osi_QAddT(&scp->fileLocksH, &scp->fileLocksT, &fileLock->fileq);
cm_HoldSCacheNoLock(scp);
fileLock->scp = scp;
fileLock->range.length,
fileLock->lockType);
- if (scp->fileLocksT == q)
- scp->fileLocksT = osi_QPrev(q);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
if (IS_LOCK_CLIENTONLY(fileLock)) {
fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+ cm_ReleaseUser(fileLock->userp);
+ cm_ReleaseSCacheNoLock(scp);
+
+ fileLock->userp = NULL;
+ fileLock->scp = NULL;
+
n_unlocks++;
}
}
return 0;
}
- osi_Log1(afsd_logp, "cm_UnlockByKey done with %d locks", n_unlocks);
-
+ code = cm_IntUnlock(scp, userp, reqp);
osi_Log1(afsd_logp, "cm_UnlockByKey code 0x%x", code);
+
osi_Log4(afsd_logp, " Leaving scp with excl[%d], shared[%d], client[%d], serverLock[%d]",
scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
(int)(signed char) scp->serverLock);
return code;
}
+/* Called with scp->rw held */
long cm_Unlock(cm_scache_t *scp,
unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
/* discard lock record */
lock_ConvertRToW(&cm_scacheLock);
- if (scp->fileLocksT == q)
- scp->fileLocksT = osi_QPrev(q);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
/*
}
fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+
+ if (userp != NULL) {
+ cm_ReleaseUser(fileLock->userp);
+ } else {
+ userp = fileLock->userp;
+ release_userp = TRUE;
+ }
+ cm_ReleaseSCacheNoLock(scp);
+ fileLock->userp = NULL;
+ fileLock->scp = NULL;
lock_ReleaseWrite(&cm_scacheLock);
+ code = cm_IntUnlock(scp, userp, reqp);
+
if (release_userp) {
cm_ReleaseUser(userp);
release_userp = FALSE;
fileLock->userp = NULL;
fileLock->scp = NULL;
- lock_ReleaseWrite(&cm_scacheLock);
- lock_ObtainWrite(&scp->rw);
- code = cm_IntUnlock(scp, userp, &req);
- lock_ReleaseWrite(&scp->rw);
-
- cm_ReleaseUser(fileLock->userp);
- lock_ObtainWrite(&cm_scacheLock);
- cm_ReleaseSCacheNoLock(scp);
+ if (scp && userp) {
+ lock_ReleaseWrite(&cm_scacheLock);
+ lock_ObtainWrite(&scp->rw);
+ code = cm_IntUnlock(scp, userp, &req);
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseUser(userp);
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_ReleaseSCacheNoLock(scp);
+ }
osi_QRemove(&cm_allFileLocks, q);
cm_PutFileLock(fileLock);
handleCode:
if (code != 0 && code != CM_ERROR_WOULDBLOCK) {
lock_ObtainWrite(&cm_scacheLock);
- if (scp->fileLocksT == &oldFileLock->fileq)
- scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
lock_ReleaseWrite(&cm_scacheLock);
}
return code;
}
-cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint64 file_id)
{
cm_key_t key;
int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
{
return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
- ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
+ ((flags & CM_UNLOCK_FLAG_BY_FID) || (k1->process_id == k2->process_id));
}
void cm_ReleaseAllLocks(void)