#include <afs/param.h>
#include <afs/stds.h>
-#ifndef DJGPP
#include <windows.h>
#include <winsock2.h>
-#endif /* !DJGPP */
#include <stddef.h>
#include <malloc.h>
#include <string.h>
extern void afsi_log(char *pattern, ...);
#endif
-int cm_enableServerLocks = 0;
+int cm_enableServerLocks = 1;
/*
* Case-folding array. This was constructed by inspecting of SMBtrace output.
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_NEEDCALLBACK);
+ | CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_LOCK);
if (code == 0 &&
((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
}
}
}
+
+ } else if (code != 0) {
+ goto _done;
}
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+ _done:
+
lock_ReleaseMutex(&scp->mx);
return code;
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_NEEDCALLBACK);
+ | CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_LOCK);
/*
* If the open will fail because the volume is readonly, then we will
*/
if (code == CM_ERROR_READONLY)
code = CM_ERROR_NOACCESS;
- else if (code == 0 &&
+
+ if (code == 0 &&
((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
scp->fileType == CM_SCACHETYPE_FILE) {
cm_key_t key;
}
}
}
+ } else if (code != 0) {
+ goto _done;
}
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+ _done:
lock_ReleaseMutex(&scp->mx);
return code;
/* First check permissions */
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
- CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_NEEDCALLBACK);
+ CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
lock_ReleaseMutex(&dscp->mx);
if (code)
return code;
lock_ReleaseMutex(&scp->mx);
lock_ObtainMutex(&bufferp->mx);
lock_ObtainMutex(&scp->mx);
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (code)
break;
}
}
#ifdef AFSIFS
- /* for the IFS version, we bulkstat the dirents because this
- routine is used in place of smb_ReceiveCoreSearchDir. our
- other option is to modify smb_ReceiveCoreSearchDir itself,
- but this seems to be the proper use for cm_ApplyDir. */
+ /* for the IFS version, we bulkstat the dirents because this
+ routine is used in place of smb_ReceiveCoreSearchDir. our
+ other option is to modify smb_ReceiveCoreSearchDir itself,
+ but this seems to be the proper use for cm_ApplyDir. */
lock_ObtainMutex(&scp->mx);
if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
&& (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
{
scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
- cm_TryBulkStat(scp, &thyper, userp, reqp);
+ code = cm_TryBulkStat(scp, &thyper, userp, reqp);
scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
scp->bulkStatProgress = thyper;
}
lock_ReleaseMutex(&scp->mx);
break;
}
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (cm_HaveBuffer(scp, bufferp, 1)) {
lock_ReleaseMutex(&scp->mx);
return 0;
sp->found = 1;
- if(!sp->caseFold)
+ if (!sp->caseFold)
sp->ExactFound = 1;
if (!sp->caseFold || matchName == shortName) {
if (code) {
goto done;
}
+ cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
if (cm_HaveBuffer(scp, bufp, 0))
break;
/* parse the volume name */
mpNamep = scp->mountPointStringp;
- osi_assert(mpNamep[0]);
+ if (!mpNamep[0])
+ return CM_ERROR_NOSUCHPATH;
tlen = (int)strlen(scp->mountPointStringp);
mtType = *scp->mountPointStringp;
cellNamep = malloc(tlen);
return CM_ERROR_NOSUCHVOLUME;
rock.fid = dscp->dotdotFid;
goto haveFid;
+ } else if (strcmp(namep, ".") == 0) {
+ rock.fid = dscp->fid;
+ goto haveFid;
}
memset(&rock, 0, sizeof(rock));
cm_ReleaseSCache(tscp);
return code;
}
+ cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
/* tscp is now locked */
if (!(flags & CM_FLAG_NOMOUNTCHASE)
if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
/* lock the directory entry to prevent racing callback revokes */
lock_ObtainMutex(&dscp->mx);
- if ( dscp->cbServerp && dscp->cbExpires )
+ if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
cm_dnlcEnter(dscp, namep, tscp);
lock_ReleaseMutex(&dscp->mx);
}
return 1;
}
+#ifdef DEBUG_REFCOUNT
+long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+ cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
+#else
long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
cm_req_t *reqp, cm_scache_t **outpScpp)
+#endif
{
long code;
char tname[256];
int sysNameIndex = 0;
- cm_scache_t *scp = 0;
+ cm_scache_t *scp = NULL;
+
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_Lookup dscp 0x%p ref %d", file, line, dscp, dscp->refCount, file, line);
+ osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
+#endif
if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
if (flags & CM_FLAG_CHECKPATH)
code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
if (code > 0) {
code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_LookupInternal (1) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+ osi_Log3(afsd_logp, "cm_LookupInternal (1) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+#endif
+
if (code == 0) {
*outpScpp = scp;
return 0;
}
if (scp) {
cm_ReleaseSCache(scp);
- scp = 0;
+ scp = NULL;
}
} else {
- return cm_LookupInternal(dscp, namep, flags, userp, reqp, outpScpp);
+ code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+ osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+#endif
+ *outpScpp = scp;
+ return code;
}
}
cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0)
cm_MergeStatus(dscp, &newDirStatus, &volSync, userp, 0);
+ 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;
+ }
lock_ReleaseMutex(&dscp->mx);
return code;
buf_Release(bufp);
return code;
}
+ cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
if (cm_HaveBuffer(linkScp, bufp, 0))
break;
lock_ReleaseMutex(&linkScp->mx);
return code;
}
-
+#ifdef DEBUG_REFCOUNT
+long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
+ cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp,
+ char * file, long line)
+#else
long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
+#endif
{
long code;
char *tp; /* ptr moving through input buffer */
int extraFlag; /* avoid chasing mt pts for dir cmd */
int phase = 1; /* 1 = tidPathp, 2 = pathp */
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
+ osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
+ rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>",
+ flags);
+#endif
+
tp = tidPathp;
if (tp == NULL) {
tp = pathp;
tscp = rootSCachep;
cm_HoldSCache(tscp);
symlinkCount = 0;
- dirScp = 0;
+ dirScp = NULL;
+
while (1) {
tc = *tp++;
* is a symlink, we have more to do.
*/
*cp++ = 0; /* add null termination */
- extraFlag = 0;
- if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
- extraFlag = CM_FLAG_NOMOUNTCHASE;
- code = cm_Lookup(tscp, component,
- flags | extraFlag,
- userp, reqp, &nscp);
- if (code) {
- cm_ReleaseSCache(tscp);
- if (dirScp)
+ if (!strcmp(".",component)) {
+ code = 0;
+ if (dirScp) {
cm_ReleaseSCache(dirScp);
- if (psp)
- cm_FreeSpace(psp);
- if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK)
- return CM_ERROR_NOSUCHPATH;
- else
- return code;
- }
- haveComponent = 0; /* component done */
- if (dirScp)
- cm_ReleaseSCache(dirScp);
- dirScp = tscp; /* for some symlinks */
- tscp = nscp; /* already held */
- nscp = 0;
- if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
+ dirScp = NULL;
+ }
+ break;
+ }
+ extraFlag = 0;
+ if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
+ extraFlag = CM_FLAG_NOMOUNTCHASE;
+ code = cm_Lookup(tscp, component,
+ flags | extraFlag,
+ userp, reqp, &nscp);
+ if (code) {
+ cm_ReleaseSCache(tscp);
+ if (dirScp)
+ cm_ReleaseSCache(dirScp);
+ if (psp)
+ cm_FreeSpace(psp);
+ if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK) {
+ osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
+ return CM_ERROR_NOSUCHPATH;
+ } else {
+ osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
+ return code;
+ }
+ }
+ haveComponent = 0; /* component done */
+ if (dirScp)
+ cm_ReleaseSCache(dirScp);
+ dirScp = tscp; /* for some symlinks */
+ tscp = nscp; /* already held */
+ nscp = NULL;
+ if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
code = 0;
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
break;
}
if (code) {
lock_ReleaseMutex(&tscp->mx);
cm_ReleaseSCache(tscp);
- tscp = 0;
+ tscp = NULL;
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
break;
}
+ cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
/* this is a symlink; assemble a new buffer */
lock_ReleaseMutex(&tscp->mx);
if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
cm_ReleaseSCache(tscp);
- tscp = 0;
+ tscp = NULL;
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
if (psp)
cm_FreeSpace(psp);
+ osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_TOO_MANY_SYMLINKS");
return CM_ERROR_TOO_MANY_SYMLINKS;
}
if (tc == 0)
if (code) {
/* something went wrong */
cm_ReleaseSCache(tscp);
- tscp = 0;
+ tscp = NULL;
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
break;
}
tp = psp->data;
cm_ReleaseSCache(tscp);
tscp = linkScp;
- linkScp = 0;
+ linkScp = NULL;
/* already held
* by AssembleLink
* now, if linkScp is null, that's
*/
if (tscp == NULL) {
tscp = dirScp;
- dirScp = 0;
+ dirScp = NULL;
}
} else {
/* not a symlink, we may be done */
}
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
code = 0;
break;
}
if (dirScp) {
cm_ReleaseSCache(dirScp);
- dirScp = 0;
+ dirScp = NULL;
}
} /* end of a component */
else
*outScpp = tscp;
else if (tscp)
cm_ReleaseSCache(tscp);
+
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
+#endif
+ osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
return code;
}
* check anyway, but we want to minimize the chance that we have to leave stuff
* unstat'd.
*/
-#define CM_BULKMAX 128
+#define CM_BULKMAX (3 * AFSCBMAX)
/* rock for bulk stat calls */
typedef struct cm_bulkStat {
if (tscp) {
if (lock_TryMutex(&tscp->mx)) {
/* we have an entry that we can look at */
- if (cm_HaveCallback(tscp)) {
+ 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.
/* called with a locked scp and a pointer to a buffer. Make bulk stat
* calls on all undeleted files in the page of the directory specified.
*/
-void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
- cm_req_t *reqp)
+afs_int32
+cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
+ cm_req_t *reqp)
{
long code;
- cm_bulkStat_t bb; /* this is *BIG*, probably 12K or so;
+ cm_bulkStat_t bb; /* this is *BIG*, probably 16K or so;
* watch for stack problems */
AFSCBFids fidStruct;
AFSBulkStats statStruct;
cm_scache_t *scp;
cm_fid_t tfid;
struct rx_connection * callp;
+ int inlinebulk = 0; /* Did we use InlineBulkStatus RPC or not? */
osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
/* should be on a buffer boundary */
osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
- bb.counter = 0;
+ memset(&bb, 0, sizeof(bb));
bb.bufOffset = *offsetp;
lock_ReleaseMutex(&dscp->mx);
/* if we failed, bail out early */
if (code && code != CM_ERROR_STOPNOW) {
lock_ObtainMutex(&dscp->mx);
- return;
+ return code;
}
/* otherwise, we may have one or more bulk stat's worth of stuff in bb;
continue;
callp = cm_GetRxConn(connp);
- code = RXAFS_BulkStatus(callp, &fidStruct,
+ if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
+ code = RXAFS_InlineBulkStatus(callp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
+ if (code == RXGEN_OPCODE) {
+ cm_SetServerNoInlineBulk(connp->serverp, 0);
+ } else {
+ inlinebulk = 1;
+ }
+ }
+ if (!inlinebulk) {
+ code = RXAFS_BulkStatus(callp, &fidStruct,
+ &statStruct, &callbackStruct, &volSync);
+ }
rx_PutConnection(callp);
} while (cm_Analyze(connp, userp, reqp, &dscp->fid,
&volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
-
if (code)
- osi_Log1(afsd_logp, "CALL BulkStatus FAILURE code 0x%x", code);
+ osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x",
+ inlinebulk ? "Inline" : "", code);
else
- osi_Log0(afsd_logp, "CALL BulkStatus SUCCESS");
+ osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
/* may as well quit on an error, since we're not going to do
* much better on the next immediate call, either.
* Right now, be pretty conservative: if there's a
* callback or a pending call, skip it.
*/
- if (scp->cbServerp == NULL
+ if ((scp->cbServerp == NULL || (scp->flags & CM_SCACHEFLAG_EACCESS))
&& !(scp->flags &
(CM_SCACHEFLAG_FETCHING
| CM_SCACHEFLAG_STORING
cm_EndCallbackGrantingCall(scp, &cbReq,
&bb.callbacks[j],
CM_CALLBACK_MAINTAINCOUNT);
- cm_MergeStatus(scp, &bb.stats[j], &volSync,
- userp, 0);
+ cm_MergeStatus(scp, &bb.stats[j], &volSync, userp, 0);
}
lock_ReleaseMutex(&scp->mx);
cm_ReleaseSCache(scp);
filex += filesThisCall;
} /* while there are still more files to process */
lock_ObtainMutex(&dscp->mx);
- osi_Log0(afsd_logp, "END cm_TryBulkStat");
+
+#if 0
+ /* If we did the InlineBulk RPC pull out the return code */
+ if (inlinebulk) {
+ if ((&bb.stats[0])->errorCode) {
+ cm_Analyze(NULL /*connp was released by the previous cm_Analyze */,
+ userp, reqp, &dscp->fid, &volSync, NULL, NULL, (&bb.stats[0])->errorCode);
+ code = cm_MapRPCError((&bb.stats[0])->errorCode, reqp);
+ }
+ } else
+#endif
+ {
+ code = 0;
+ }
+
+ osi_Log1(afsd_logp, "END cm_TryBulkStat code = 0x%x", code);
+ return code;
}
void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code)
goto done;
-
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
if (scp->fileType != CM_SCACHETYPE_FILE) {
code = CM_ERROR_ISDIR;
goto done;
/* done successfully */
code = 0;
+ cm_SyncOpDone(scp, NULL,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
+
done:
lock_ReleaseMutex(&scp->mx);
lock_ReleaseWrite(&scp->bufCreateLock);
cm_req_t *reqp)
{
long code;
- int flags;
AFSFetchStatus afsOutStatus;
AFSVolSync volSync;
cm_conn_t *connp;
if (attrp->mask & CM_ATTRMASK_LENGTH)
return cm_SetLength(scp, &attrp->length, userp, reqp);
- flags = CM_SCACHESYNC_STORESTATUS;
-
lock_ObtainMutex(&scp->mx);
/* otherwise, we have to make an RPC to get the status */
code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
+ if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ return code;
+ }
/* make the attr structure */
cm_StatusFromAttr(&afsInStatus, scp, attrp);
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
tfid.Unique = scp->fid.unique;
-
- lock_ReleaseMutex(&scp->mx);
- if (code)
- return code;
+ lock_ReleaseMutex(&scp->mx);
/* now make the RPC */
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainMutex(&scp->mx);
+ scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(scp, &newFileStatus, &volSync,
userp, 0);
lock_ReleaseWrite(&scp->bufCreateLock);
if (code == 0) {
lock_ObtainMutex(&scp->mx);
- scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA
- | CM_SCACHEFLAG_OUTOFSPACE);
+
if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
| CM_SCACHEMASK_CLIENTMODTIME
| CM_SCACHEMASK_LENGTH))
code = cm_StoreMini(scp, userp, reqp);
+
+ if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
+ code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
+ scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
+ }
+
lock_ReleaseMutex(&scp->mx);
}
return code;
lock_ReleaseMutex(&newDscp->mx);
if (code) {
/* cleanup first one */
- lock_ObtainMutex(&newDscp->mx);
+ lock_ObtainMutex(&oldDscp->mx);
cm_SyncOpDone(oldDscp, NULL,
CM_SCACHESYNC_STOREDATA);
lock_ReleaseMutex(&oldDscp->mx);
/* unsafe */
#define CONTAINS_RANGE(r1,r2) (((r2).offset+(r2).length) <= ((r1).offset+(r1).length) && (r1).offset <= (r2).offset)
-#define SERVERLOCKS_ENABLED(scp) (!(((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks))
+#if defined(VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS) && !defined(LOCK_TESTING)
+#define SCP_SUPPORTS_BRLOCKS(scp) ((scp)->cbServerp && ((scp)->cbServerp->capabilities & VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS))
+#else
+#define SCP_SUPPORTS_BRLOCKS(scp) (1)
+#endif
+
+#define SERVERLOCKS_ENABLED(scp) (!((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks && SCP_SUPPORTS_BRLOCKS(scp))
static void cm_LockRangeSubtract(cm_range_t * pos, const cm_range_t * neg)
{
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) {
+ if (int_begin < int_end) {
+ if (int_begin == pos->offset) {
pos->length = pos->offset + pos->length - int_end;
pos->offset = int_end;
- } else if(int_end == pos->offset + pos->length) {
+ } else if (int_end == pos->offset + pos->length) {
pos->length = int_begin - pos->offset;
}
lock_ObtainRead(&cm_scacheLock);
- for(q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
if (INTERSECT_RANGE(range, fileLock->range)) {
- if(IS_LOCK_ACTIVE(fileLock)) {
- if(fileLock->key == key) {
+ if (IS_LOCK_ACTIVE(fileLock)) {
+ if (fileLock->key == key) {
/* If there is an active lock for this client, it
is safe to substract ranges.*/
cm_LockRangeSubtract(&range, &fileLock->range);
substract_ranges = TRUE;
} else {
- if(fileLock->lockType != LockRead) {
+ if (fileLock->lockType != LockRead) {
code = CM_ERROR_LOCK_CONFLICT;
break;
}
is, unless we have already seen an active lock
belonging to the client, in which case there
can't be any lost locks for this client. */
- if(substract_ranges)
+ if (substract_ranges)
cm_LockRangeSubtract(&range, &fileLock->range);
}
- } else if(IS_LOCK_LOST(fileLock) &&
+ } else if (IS_LOCK_LOST(fileLock) &&
(fileLock->key == key || fileLock->lockType == LockWrite)) {
code = CM_ERROR_BADFD;
break;
lock_ObtainRead(&cm_scacheLock);
- for(q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
- if(INTERSECT_RANGE(range, fileLock->range)) {
- if(IS_LOCK_ACTIVE(fileLock)) {
- if(fileLock->key == key) {
- if(fileLock->lockType == LockWrite) {
+ if (INTERSECT_RANGE(range, fileLock->range)) {
+ if (IS_LOCK_ACTIVE(fileLock)) {
+ if (fileLock->key == key) {
+ if (fileLock->lockType == LockWrite) {
/* if there is an active lock for this client, it
is safe to substract ranges */
code = CM_ERROR_LOCK_CONFLICT;
break;
}
- } else if(IS_LOCK_LOST(fileLock)) {
+ } else if (IS_LOCK_LOST(fileLock)) {
code = CM_ERROR_BADFD;
break;
}
cm_file_lock_t * l;
l = (cm_file_lock_t *) cm_freeFileLocks;
- if(l) {
+ if (l) {
osi_QRemove(&cm_freeFileLocks, &l->q);
} else {
l = malloc(sizeof(cm_file_lock_t));
osi_QAdd(&cm_freeFileLocks, &l->q);
}
+/* called with scp->mx held. May release it during processing, but
+ leaves it held on exit. */
+long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
+ cm_req_t * reqp) {
+ long code = 0;
+ AFSFid tfid;
+ cm_fid_t cfid;
+ cm_conn_t * connp;
+ struct rx_connection * callp;
+ AFSVolSync volSync;
+
+ tfid.Volume = scp->fid.volume;
+ tfid.Vnode = scp->fid.vnode;
+ tfid.Unique = scp->fid.unique;
+ cfid = scp->fid;
+
+ osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
+
+ lock_ReleaseMutex(&scp->mx);
+
+ do {
+ code = cm_Conn(&cfid, userp, reqp, &connp);
+ if (code)
+ break;
+
+ callp = cm_GetRxConn(connp);
+ code = RXAFS_SetLock(callp, &tfid, lockType,
+ &volSync);
+ rx_PutConnection(callp);
+
+ } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ NULL, NULL, code));
+
+ code = cm_MapRPCError(code, reqp);
+ if (code) {
+ osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
+ } else {
+ osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
+ }
+
+ lock_ObtainMutex(&scp->mx);
+
+ return code;
+}
+
+/* called with scp->mx held. Releases it during processing */
+long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
+ cm_req_t * reqp) {
+ long code = 0;
+ AFSFid tfid;
+ cm_fid_t cfid;
+ cm_conn_t * connp;
+ struct rx_connection * callp;
+ AFSVolSync volSync;
+
+ tfid.Volume = scp->fid.volume;
+ tfid.Vnode = scp->fid.vnode;
+ tfid.Unique = scp->fid.unique;
+ cfid = scp->fid;
+
+ lock_ReleaseMutex(&scp->mx);
+
+ osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
+
+ do {
+ code = cm_Conn(&cfid, userp, reqp, &connp);
+ if (code)
+ break;
+
+ callp = cm_GetRxConn(connp);
+ code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
+ rx_PutConnection(callp);
+
+ } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ NULL, NULL, code));
+ code = cm_MapRPCError(code, reqp);
+ if (code)
+ osi_Log1(afsd_logp,
+ "CALL ReleaseLock FAILURE, code 0x%x", code);
+ else
+ osi_Log0(afsd_logp,
+ "CALL ReleaseLock SUCCESS");
+
+ lock_ObtainMutex(&scp->mx);
+
+ return code;
+}
+
+/* called with scp->mx held. May release it during processing, but
+ will exit with lock held.
+
+ This will return:
+
+ - 0 if the user has permission to get the specified lock for the scp
+
+ - CM_ERROR_NOACCESS if not
+
+ Any other error from cm_SyncOp will be sent down untranslated.
+*/
+long cm_LockCheckPerms(cm_scache_t * scp,
+ int lock_type,
+ cm_user_t * userp,
+ cm_req_t * reqp)
+{
+ long rights = 0;
+ long code = 0;
+
+ /* lock permissions are slightly tricky because of the 'i' bit.
+ If the user has PRSFS_LOCK, she can read-lock the file. If the
+ user has PRSFS_WRITE, she can write-lock the file. However, if
+ the user has PRSFS_INSERT, then she can write-lock new files,
+ but not old ones. Since we don't have information about
+ whether a file is new or not, we assume that if the user owns
+ the scp, then she has the permissions that are granted by
+ PRSFS_INSERT. */
+
+ osi_Log3(afsd_logp, "cm_LockCheckPerms for scp[0x%p] type[%d] user[0x%p]",
+ scp, lock_type, userp);
+
+ if (lock_type == LockRead)
+ rights |= PRSFS_LOCK;
+ else if (lock_type == LockWrite)
+ rights |= PRSFS_WRITE;
+ else {
+ /* hmmkay */
+ osi_assert(FALSE);
+ return 0;
+ }
+
+ code = cm_SyncOp(scp, NULL, userp, reqp, rights,
+ CM_SCACHESYNC_GETSTATUS |
+ CM_SCACHESYNC_NEEDCALLBACK);
+
+ if (code == CM_ERROR_NOACCESS &&
+ lock_type == LockWrite &&
+ scp->creator == userp) {
+ /* check for PRSFS_INSERT. */
+
+ code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_INSERT,
+ CM_SCACHESYNC_GETSTATUS |
+ CM_SCACHESYNC_NEEDCALLBACK);
+
+ if (code == CM_ERROR_NOACCESS)
+ osi_Log0(afsd_logp, "cm_LockCheckPerms user is creator but has no INSERT bits for scp");
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ osi_Log1(afsd_logp, "cm_LockCheckPerms returning code %d", code);
+
+ return code;
+}
+
/* called with scp->mx held */
long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
{
long code = 0;
int Which = ((sLockType & LOCKING_ANDX_SHARED_LOCK) ? LockRead : LockWrite);
- AFSFid tfid;
- AFSVolSync volSync;
- cm_conn_t *connp;
cm_file_lock_t *fileLock;
osi_queue_t *q;
- struct rx_connection * callp;
cm_range_t range;
int wait_unlock = FALSE;
+ int force_client_lock = FALSE;
osi_Log4(afsd_logp, "cm_Lock scp 0x%x type 0x%x offset %d length %d",
scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
lock_ObtainRead(&cm_scacheLock);
- for(q = scp->fileLocksH; q; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
- if(IS_LOCK_LOST(fileLock)) {
+ if (IS_LOCK_LOST(fileLock)) {
if (fileLock->key == key) {
code = CM_ERROR_BADFD;
break;
/* we don't need to check for deleted locks here since deleted
locks are dequeued from scp->fileLocks */
- if(IS_LOCK_ACCEPTED(fileLock) &&
+ if (IS_LOCK_ACCEPTED(fileLock) &&
INTERSECT_RANGE(range, fileLock->range)) {
- if((sLockType & LOCKING_ANDX_SHARED_LOCK) == 0 ||
+ if ((sLockType & LOCKING_ANDX_SHARED_LOCK) == 0 ||
fileLock->lockType != LockRead) {
wait_unlock = TRUE;
code = CM_ERROR_WOULDBLOCK;
lock_ReleaseRead(&cm_scacheLock);
- if(code == 0 && SERVERLOCKS_ENABLED(scp)) {
- if(Which == scp->serverLock ||
+ if (code == 0 && SERVERLOCKS_ENABLED(scp)) {
+ if (Which == scp->serverLock ||
(Which == LockRead && scp->serverLock == LockWrite)) {
/* we already have the lock we need */
osi_Log3(afsd_logp, " we already have the correct lock. exclusives[%d], shared[%d], serverLock[%d]",
scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
- code = 0; /* redundant */
- } else if((scp->exclusiveLocks > 0) ||
- (scp->sharedLocks > 0 && scp->serverLock != LockRead)) {
+ code = cm_LockCheckPerms(scp, Which, userp, reqp);
+
+ /* special case: if we don't have permission to read-lock
+ the file, then we force a clientside lock. This is to
+ compensate for applications that obtain a read-lock for
+ reading files off of directories that don't grant
+ read-locks to the user. */
+ if (code == CM_ERROR_NOACCESS && Which == LockRead) {
+ osi_Log0(afsd_logp, " User has no read-lock perms. Forcing client-side lock");
+ force_client_lock = TRUE;
+ }
+
+ } else if ((scp->exclusiveLocks > 0) ||
+ (scp->sharedLocks > 0 && scp->serverLock != LockRead)) {
/* We are already waiting for some other lock. We should
wait for the daemon to catch up instead of generating a
flood of SetLock calls. */
osi_Log3(afsd_logp, " already waiting for other lock. exclusives[%d], shared[%d], serverLock[%d]",
scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
- code = CM_ERROR_WOULDBLOCK;
+
+ /* see if we have permission to create the lock in the
+ first place. */
+ code = cm_LockCheckPerms(scp, Which, userp, reqp);
+ if (code == 0)
+ code = CM_ERROR_WOULDBLOCK;
+ else if (code == CM_ERROR_NOACCESS && Which == LockRead) {
+ osi_Log0(afsd_logp, " User has no read-lock perms. Forcing client-side lock");
+ force_client_lock = TRUE;
+ }
+
+ /* leave any other codes as-is */
} else {
- cm_fid_t cfid;
int newLock;
+ int check_data_version = FALSE;
+
+ /* first check if we have permission to elevate or obtain
+ the lock. */
+ code = cm_LockCheckPerms(scp, Which, userp, reqp);
+ if (code) {
+ if (code == CM_ERROR_NOACCESS && Which == LockRead) {
+ osi_Log0(afsd_logp, " User has no read-lock perms. Forcing client-side lock");
+ force_client_lock = TRUE;
+ }
+ goto check_code;
+ }
if (scp->serverLock == LockRead && Which == LockWrite) {
-
+
/* We want to escalate the lock to a LockWrite.
Unfortunately that's not really possible without
letting go of the current lock. But for now we do
it anyway. */
- osi_Log0(afsd_logp, " attempting to UPGRADE from LockRead to LockWrite.");
-
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- lock_ReleaseMutex(&scp->mx);
-
- osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
+ osi_Log0(afsd_logp,
+ " attempting to UPGRADE from LockRead to LockWrite.");
+ osi_Log1(afsd_logp,
+ " dataVersion on scp: %d", scp->dataVersion);
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
- code = cm_MapRPCError(code, reqp);
-
- if (code)
- osi_Log1(afsd_logp, "CALL ReleaseLock FAILURE, code 0x%x", code);
- else
- osi_Log0(afsd_logp, "CALL ReleaseLock SUCCESS");
+ /* we assume at this point (because scp->serverLock
+ was valid) that we had a valid server lock. */
+ scp->lockDataVersion = scp->dataVersion;
+ check_data_version = TRUE;
- lock_ObtainMutex(&scp->mx);
+ code = cm_IntReleaseLock(scp, userp, reqp);
if (code) {
/* We couldn't release the lock */
/* We need to obtain a server lock of type Which in order
to assert this file lock */
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
#ifndef AGGRESSIVE_LOCKS
newLock = Which;
#else
newLock = LockWrite;
#endif
- osi_Log3(afsd_logp, "CALL SetLock scp 0x%p from %d to %d", scp, (int) scp->serverLock, newLock);
-
- lock_ReleaseMutex(&scp->mx);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, newLock,
- &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
-
- code = cm_MapRPCError(code, reqp);
-
- if (code) {
- osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
- } else {
- osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
- }
+ code = cm_IntSetLock(scp, userp, newLock, reqp);
if (code == CM_ERROR_WOULDBLOCK && newLock != Which) {
- /* we wanted LockRead. We tried LockWrite. Now try LockRead again */
+ /* we wanted LockRead. We tried LockWrite. Now try
+ LockRead again */
newLock = Which;
/* am I sane? */
osi_assert(newLock == LockRead);
-
- osi_Log3(afsd_logp, "CALL SetLock AGAIN scp 0x%p from %d to %d",
- scp, (int) scp->serverLock, newLock);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, newLock,
- &volSync);
- rx_PutConnection(callp);
+ code = cm_IntSetLock(scp, userp, newLock, reqp);
+ }
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
+ if (code == 0 && check_data_version &&
+ scp->dataVersion != scp->lockDataVersion) {
+ /* We lost a race. Although we successfully obtained
+ a lock, someone modified the file in between. The
+ locks have all been technically lost. */
- code = cm_MapRPCError(code, reqp);
+ osi_Log0(afsd_logp,
+ " Data version mismatch while upgrading lock.");
+ osi_Log2(afsd_logp,
+ " Data versions before=%d, after=%d",
+ scp->lockDataVersion,
+ scp->dataVersion);
+ osi_Log1(afsd_logp,
+ " Releasing stale lock for scp 0x%x", scp);
- if (code) {
- osi_Log1(afsd_logp, "CALL SetLock FAILURE AGAIN, code 0x%x", code);
- } else {
- osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
- }
- }
+ code = cm_IntReleaseLock(scp, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ scp->serverLock = -1;
- if(code == 0)
+ code = CM_ERROR_INVAL;
+ } else if (code == 0) {
scp->serverLock = newLock;
- else {
- if ((scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
+ scp->lockDataVersion = scp->dataVersion;
+ }
+
+ if (code != 0 &&
+ (scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
scp->serverLock == -1) {
/* Oops. We lost the lock. */
cm_LockMarkSCacheLost(scp);
}
}
- }
} else if (code == 0) { /* server locks not enabled */
osi_Log0(afsd_logp,
" Skipping server lock for scp");
check_code:
- if (code != 0) {
+ if (code != 0 && !force_client_lock) {
/* Special case error translations
Applications don't expect certain errors from a
}
}
- if (code == 0 || (code == CM_ERROR_WOULDBLOCK && allowWait)) {
+ if (code == 0 || (code == CM_ERROR_WOULDBLOCK && allowWait) ||
+ force_client_lock) {
+
+ /* clear the error if we are forcing a client lock, so we
+ don't get confused later. */
+ if (force_client_lock && code != CM_ERROR_WOULDBLOCK)
+ code = 0;
lock_ObtainWrite(&cm_scacheLock);
fileLock = cm_GetFileLock();
CM_FILELOCK_FLAG_WAITUNLOCK :
CM_FILELOCK_FLAG_WAITLOCK));
- if (!SERVERLOCKS_ENABLED(scp))
+ if (force_client_lock || !SERVERLOCKS_ENABLED(scp))
fileLock->flags |= CM_FILELOCK_FLAG_CLIENTONLY;
- fileLock->lastUpdate = (code == 0) ? time(NULL) : 0;
-
- osi_QAddT(&scp->fileLocksH, &scp->fileLocksT, &fileLock->fileq);
+ 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;
osi_QAdd(&cm_allFileLocks, &fileLock->q);
*lockpp = fileLock;
}
- if (IS_LOCK_ACCEPTED(fileLock)) {
- if(Which == LockRead)
+ if (IS_LOCK_CLIENTONLY(fileLock)) {
+ scp->clientLocks++;
+ } else if (IS_LOCK_ACCEPTED(fileLock)) {
+ if (Which == LockRead)
scp->sharedLocks++;
else
scp->exclusiveLocks++;
}
- osi_Log2(afsd_logp, "cm_Lock Lock added 0x%p flags 0x%x", fileLock, fileLock->flags);
- osi_Log4(afsd_logp, " scp[0x%p] exclusives[%d] shared[%d] serverLock[%d]",
- scp, scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
+ osi_Log3(afsd_logp,
+ "cm_Lock Lock added 0x%p flags 0x%x to scp [0x%p]",
+ fileLock, fileLock->flags, scp);
+ osi_Log4(afsd_logp,
+ " exclusives[%d] shared[%d] client[%d] serverLock[%d]",
+ scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
+ (int)(signed char) scp->serverLock);
+ } else {
+ osi_Log1(afsd_logp,
+ "cm_Lock Rejecting lock (code = 0x%x)", code);
}
return code;
cm_req_t * reqp)
{
long code = 0;
- AFSFid tfid;
- AFSVolSync volSync;
- cm_conn_t *connp;
cm_file_lock_t *fileLock;
osi_queue_t *q, *qn;
- struct rx_connection * callp;
int n_unlocks = 0;
- osi_Log3(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x",
- scp, (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
+ osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
+ scp,
+ (unsigned long)(key >> 32),
+ (unsigned long)(key & 0xffffffff),
+ flags);
lock_ObtainWrite(&cm_scacheLock);
- for(q = scp->fileLocksH; q; q = qn) {
+ for (q = scp->fileLocksH; q; q = qn) {
qn = osi_QNext(q);
fileLock = (cm_file_lock_t *)
#ifdef DEBUG
osi_Log4(afsd_logp, " Checking lock[0x%x] range[%d,+%d] type[%d]",
- fileLock, (unsigned long) fileLock->range.offset, (unsigned long) fileLock->range.length,
+ fileLock,
+ (unsigned long) fileLock->range.offset,
+ (unsigned long) fileLock->range.length,
fileLock->lockType);
osi_Log3(afsd_logp, " key[0x%x:%x] flags[0x%x]",
(unsigned long)(fileLock->key >> 32),
(unsigned long)(fileLock->key & 0xffffffff),
fileLock->flags);
- if(cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
+ if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
osi_Log0(afsd_logp, "!!fileLock->fid != scp->fid");
osi_Log4(afsd_logp, " fileLock->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
fileLock->fid.cell,
if (scp->fileLocksT == q)
scp->fileLocksT = osi_QPrev(q);
- osi_QRemove(&scp->fileLocksH,q);
+ osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
- if(IS_LOCK_ACCEPTED(fileLock)) {
- if(fileLock->lockType == LockRead)
+ if (IS_LOCK_CLIENTONLY(fileLock)) {
+ scp->clientLocks--;
+ } else if (IS_LOCK_ACCEPTED(fileLock)) {
+ if (fileLock->lockType == LockRead)
scp->sharedLocks--;
else
scp->exclusiveLocks--;
lock_ReleaseWrite(&cm_scacheLock);
- if(n_unlocks == 0) {
+ if (n_unlocks == 0) {
osi_Log0(afsd_logp, "cm_UnlockByKey no locks found");
osi_Log3(afsd_logp, " Leaving scp with exclusives[%d], shared[%d], serverLock[%d]",
scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
osi_assertx(scp->sharedLocks >= 0, "scp->sharedLocks < 0");
osi_assertx(scp->exclusiveLocks >= 0, "scp->exclusiveLocks < 0");
+ osi_assertx(scp->clientLocks >= 0, "scp->clientLocks < 0");
if (!SERVERLOCKS_ENABLED(scp)) {
osi_Log0(afsd_logp, " Skipping server lock for scp");
* in that manner is done cm_RetryLock() manually.
*/
- if (scp->serverLock == LockWrite && scp->exclusiveLocks == 0 && scp->sharedLocks > 0) {
-
- cm_fid_t cfid;
+ if (scp->serverLock == LockWrite &&
+ scp->exclusiveLocks == 0 &&
+ scp->sharedLocks > 0) {
/* The serverLock should be downgraded to LockRead */
osi_Log0(afsd_logp, " DOWNGRADE lock from LockWrite to LockRead");
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- lock_ReleaseMutex(&scp->mx);
-
- osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
- code = cm_MapRPCError(code, reqp);
+ /* since scp->serverLock looked sane, we are going to assume
+ that we have a valid server lock. */
+ scp->lockDataVersion = scp->dataVersion;
+ osi_Log1(afsd_logp, " dataVersion on scp = %d", scp->dataVersion);
- if (code)
- osi_Log1(afsd_logp, "CALL ReleaseLock FAILURE, code 0x%x", code);
- else
- osi_Log0(afsd_logp, "CALL ReleaseLock SUCCESS");
-
- lock_ObtainMutex(&scp->mx);
+ code = cm_IntReleaseLock(scp, userp, reqp);
if (code) {
/* so we couldn't release it. Just let the lock be for now */
scp->serverLock = -1;
}
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- osi_Log3(afsd_logp, "CALL SetLock scp 0x%p from %d to %d", scp, (int) scp->serverLock, LockRead);
+ code = cm_IntSetLock(scp, userp, LockRead, reqp);
- lock_ReleaseMutex(&scp->mx);
-
- do {
-
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, LockRead,
- &volSync);
-
- rx_PutConnection(callp);
+ if (code == 0 && scp->lockDataVersion == scp->dataVersion) {
+ scp->serverLock = LockRead;
+ } else if (code == 0 && scp->lockDataVersion != scp->dataVersion) {
+ /* We lost a race condition. Although we have a valid
+ lock on the file, the data has changed and essentially
+ we have lost the lock we had during the transition. */
+
+ osi_Log0(afsd_logp, "Data version mismatch during lock downgrade");
+ osi_Log2(afsd_logp, " Data versions before=%d, after=%d",
+ scp->lockDataVersion,
+ scp->dataVersion);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
+ code = cm_IntReleaseLock(scp, userp, reqp);
- if (code)
- osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
- else {
- osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
+ code = CM_ERROR_INVAL;
+ scp->serverLock = -1;
}
- lock_ObtainMutex(&scp->mx);
-
- if(code == 0)
- scp->serverLock = LockRead;
- else {
- if ((scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
+ if (code != 0 &&
+ (scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
(scp->serverLock == -1)) {
/* Oopsie */
cm_LockMarkSCacheLost(scp);
}
- }
/* failure here has no bearing on the return value of
cm_Unlock() */
code = 0;
- } else if(scp->serverLock != (-1) && scp->exclusiveLocks == 0 && scp->sharedLocks == 0) {
- cm_fid_t cfid;
-
+ } else if (scp->serverLock != (-1) &&
+ scp->exclusiveLocks == 0 &&
+ scp->sharedLocks == 0) {
/* The serverLock should be released entirely */
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- lock_ReleaseMutex(&scp->mx);
-
- osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
- code = cm_MapRPCError(code, reqp);
-
- if (code)
- osi_Log1(afsd_logp, "CALL ReleaseLock FAILURE, code 0x%x", code);
- else
- osi_Log0(afsd_logp, "CALL ReleaseLock SUCCESS");
-
- lock_ObtainMutex(&scp->mx);
+ code = cm_IntReleaseLock(scp, userp, reqp);
if (code == 0)
scp->serverLock = (-1);
done:
osi_Log1(afsd_logp, "cm_UnlockByKey code 0x%x", code);
- osi_Log3(afsd_logp, " Leaving scp with exclusives[%d], shared[%d], serverLock[%d]",
- scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
+ 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;
}
{
long code = 0;
int Which = ((sLockType & LOCKING_ANDX_SHARED_LOCK) ? LockRead : LockWrite);
- AFSFid tfid;
- AFSVolSync volSync;
- cm_conn_t *connp;
cm_file_lock_t *fileLock;
osi_queue_t *q;
int release_userp = FALSE;
- struct rx_connection * callp;
osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
lock_ObtainRead(&cm_scacheLock);
- for(q = scp->fileLocksH; q; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
fileLock = (cm_file_lock_t *)
((char *) q - offsetof(cm_file_lock_t, fileq));
#ifdef DEBUG
- if(cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
+ if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
osi_Log0(afsd_logp, "!!fileLock->fid != scp->fid");
osi_Log4(afsd_logp, " fileLock->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
fileLock->fid.cell,
}
}
- if(!q) {
+ if (!q) {
osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
lock_ReleaseRead(&cm_scacheLock);
return 0;
}
+ lock_ReleaseRead(&cm_scacheLock);
+
/* discard lock record */
+ lock_ObtainWrite(&cm_scacheLock);
if (scp->fileLocksT == q)
scp->fileLocksT = osi_QPrev(q);
- osi_QRemove(&scp->fileLocksH, q);
-
- lock_ReleaseRead(&cm_scacheLock);
+ osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
/*
* Don't delete it here; let the daemon delete it, to simplify
* the daemon's traversal of the list.
*/
- lock_ObtainWrite(&cm_scacheLock);
-
- if(IS_LOCK_ACCEPTED(fileLock)) {
- if(fileLock->lockType == LockRead)
+ if (IS_LOCK_CLIENTONLY(fileLock)) {
+ scp->clientLocks--;
+ } else if (IS_LOCK_ACCEPTED(fileLock)) {
+ if (fileLock->lockType == LockRead)
scp->sharedLocks--;
else
scp->exclusiveLocks--;
* in that manner is done cm_RetryLock() manually.
*/
- if (scp->serverLock == LockWrite && scp->exclusiveLocks == 0 && scp->sharedLocks > 0) {
-
- cm_fid_t cfid;
+ if (scp->serverLock == LockWrite &&
+ scp->exclusiveLocks == 0 &&
+ scp->sharedLocks > 0) {
/* The serverLock should be downgraded to LockRead */
osi_Log0(afsd_logp, " DOWNGRADE lock from LockWrite to LockRead");
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
+ /* Since we already had a lock, we assume that there is a
+ valid server lock. */
+ scp->lockDataVersion = scp->dataVersion;
+ osi_Log1(afsd_logp, " dataVersion on scp is %d", scp->dataVersion);
- lock_ReleaseMutex(&scp->mx);
-
- osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
-
- code = cm_MapRPCError(code, reqp);
-
- if (code)
- osi_Log1(afsd_logp, "CALL ReleaseLock FAILURE, code 0x%x", code);
- else
- osi_Log0(afsd_logp, "CALL ReleaseLock SUCCESS");
-
- lock_ObtainMutex(&scp->mx);
+ code = cm_IntReleaseLock(scp, userp, reqp);
if (code) {
/* so we couldn't release it. Just let the lock be for now */
scp->serverLock = -1;
}
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- osi_Log3(afsd_logp, "CALL SetLock scp 0x%p from %d to %d", scp, (int) scp->serverLock, LockRead);
-
- lock_ReleaseMutex(&scp->mx);
-
- do {
-
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
+ code = cm_IntSetLock(scp, userp, LockRead, reqp);
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, LockRead,
- &volSync);
-
- rx_PutConnection(callp);
+ if (code == 0 && scp->lockDataVersion == scp->dataVersion) {
+ scp->serverLock = LockRead;
+ } else if (code == 0 && scp->lockDataVersion != scp->dataVersion) {
+ /* Lost a race. We obtained a new lock, but that is
+ meaningless since someone modified the file
+ inbetween. */
+
+ osi_Log0(afsd_logp,
+ "Data version mismatch while downgrading lock");
+ osi_Log2(afsd_logp,
+ " Data versions before=%d, after=%d",
+ scp->lockDataVersion,
+ scp->dataVersion);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
+ code = cm_IntReleaseLock(scp, userp, reqp);
- if (code)
- osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
- else {
- osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
+ scp->serverLock = -1;
+ code = CM_ERROR_INVAL;
}
- lock_ObtainMutex(&scp->mx);
-
- if(code == 0)
- scp->serverLock = LockRead;
- else {
- if ((scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
+ if (code != 0 &&
+ (scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
(scp->serverLock == -1)) {
/* Oopsie */
cm_LockMarkSCacheLost(scp);
}
- }
/* failure here has no bearing on the return value of
cm_Unlock() */
code = 0;
- } else if(scp->serverLock != (-1) && scp->exclusiveLocks == 0 && scp->sharedLocks == 0) {
- cm_fid_t cfid;
-
+ } else if (scp->serverLock != (-1) &&
+ scp->exclusiveLocks == 0 &&
+ scp->sharedLocks == 0) {
/* The serverLock should be released entirely */
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
-
- lock_ReleaseMutex(&scp->mx);
-
- osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
-
- do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
- if (code)
- break;
-
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
- NULL, NULL, code));
- code = cm_MapRPCError(code, reqp);
-
- if (code)
- osi_Log1(afsd_logp, "CALL ReleaseLock FAILURE, code 0x%x", code);
- else
- osi_Log0(afsd_logp, "CALL ReleaseLock SUCCESS");
-
- lock_ObtainMutex(&scp->mx);
+ code = cm_IntReleaseLock(scp, userp, reqp);
if (code == 0) {
scp->serverLock = (-1);
done:
- osi_Log4(afsd_logp, "cm_Unlock code 0x%x leaving scp with exclusives[%d], shared[%d], serverLock[%d]",
- code, scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
+ osi_Log1(afsd_logp, "cm_Unlock 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;
}
/* cm_scacheLock needed because we are modifying fileLock->flags */
lock_ObtainWrite(&cm_scacheLock);
- for(q = scp->fileLocksH; q; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
- if(IS_LOCK_ACTIVE(fileLock)) {
+ if (IS_LOCK_ACTIVE(fileLock) &&
+ !IS_LOCK_CLIENTONLY(fileLock)) {
if (fileLock->lockType == LockRead)
scp->sharedLocks--;
else
}
scp->serverLock = -1;
+ scp->lockDataVersion = -1;
lock_ReleaseWrite(&cm_scacheLock);
}
osi_Log1(afsd_logp, "cm_CheckLocks starting lock check cycle %d", cm_lockRefreshCycle);
- for(q = cm_allFileLocks; q; q = nq) {
+ for (q = cm_allFileLocks; q; q = nq) {
fileLock = (cm_file_lock_t *) q;
nq = osi_QNext(q);
code = -1;
/* Server locks must have been enabled for us to have
received an active non-client-only lock. */
- //osi_assert(cm_enableServerLocks);
+ osi_assert(cm_enableServerLocks);
scp = fileLock->scp;
osi_assert(scp != NULL);
cm_HoldSCacheNoLock(scp);
#ifdef DEBUG
- if(cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
+ if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
osi_Log0(afsd_logp, "!!fileLock->fid != scp->fid");
osi_Log4(afsd_logp, " fileLock->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
fileLock->fid.cell,
| CM_SCACHESYNC_LOCK);
if (code) {
- osi_Log1(smb_logp, "cm_CheckLocks SyncOp failure code 0x%x", code);
+ osi_Log1(smb_logp,
+ "cm_CheckLocks SyncOp failure code 0x%x", code);
goto post_syncopdone;
}
if (!IS_LOCK_ACTIVE(fileLock))
goto pre_syncopdone;
- if(scp->serverLock != -1) {
+ if (scp->serverLock != -1) {
cm_fid_t cfid;
cm_user_t * userp;
if (code) {
osi_Log1(afsd_logp, "CALL ExtendLock FAILURE, code 0x%x", code);
- if (code == EINVAL || code == CM_ERROR_INVAL)
- cm_LockMarkSCacheLost(scp);
} else {
osi_Log0(afsd_logp, "CALL ExtendLock SUCCESS");
+ scp->lockDataVersion = scp->dataVersion;
+ }
+
+ if ((code == EINVAL || code == CM_ERROR_INVAL) &&
+ scp->lockDataVersion == scp->dataVersion) {
+ int lockType;
+
+ lockType =
+ (scp->exclusiveLocks > 0) ? LockWrite: LockRead;
+
+ /* we might still have a chance to obtain a
+ new lock */
+
+ code = cm_IntSetLock(scp, userp, lockType, &req);
+
+ if (code) {
+ code = CM_ERROR_INVAL;
+ } else if (scp->lockDataVersion != scp->dataVersion) {
+
+ /* now check if we still have the file at
+ the right data version. */
+ osi_Log1(afsd_logp,
+ "Data version mismatch on scp 0x%p",
+ scp);
+ osi_Log2(afsd_logp,
+ " Data versions: before=%d, after=%d",
+ scp->lockDataVersion,
+ scp->dataVersion);
+
+ code = cm_IntReleaseLock(scp, userp, &req);
+
+ code = CM_ERROR_INVAL;
+ }
+ }
+
+ if (code == EINVAL || code == CM_ERROR_INVAL) {
+ cm_LockMarkSCacheLost(scp);
}
+
} else {
/* interestingly, we have found an active lock
belonging to an scache that has no
{
long code = 0;
cm_scache_t *scp = NULL;
- AFSFid tfid;
- AFSVolSync volSync;
- cm_conn_t *connp;
cm_file_lock_t *fileLock;
osi_queue_t *q;
cm_req_t req;
- struct rx_connection * callp;
int newLock = -1;
+ int force_client_lock = FALSE;
cm_InitReq(&req);
(unsigned)(oldFileLock->flags));
/* if the lock has already been granted, then we have nothing to do */
- if(IS_LOCK_ACTIVE(oldFileLock)) {
+ if (IS_LOCK_ACTIVE(oldFileLock)) {
lock_ReleaseRead(&cm_scacheLock);
osi_Log0(afsd_logp, "cm_RetryLock lock already granted");
return 0;
}
/* we can't do anything with lost or deleted locks at the moment. */
- if(IS_LOCK_LOST(oldFileLock) || IS_LOCK_DELETED(oldFileLock)) {
+ if (IS_LOCK_LOST(oldFileLock) || IS_LOCK_DELETED(oldFileLock)) {
code = CM_ERROR_BADFD;
osi_Log0(afsd_logp, "cm_RetryLock lock is lost or deleted");
lock_ReleaseRead(&cm_scacheLock);
lock_ReleaseRead(&cm_scacheLock);
lock_ObtainMutex(&scp->mx);
+
+ code = cm_LockCheckPerms(scp, oldFileLock->lockType,
+ oldFileLock->userp,
+ &req);
+
+ if (code == CM_ERROR_NOACCESS && oldFileLock->lockType == LockRead) {
+ force_client_lock = TRUE;
+ code = 0;
+ } else if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ return code;
+ }
+
lock_ObtainWrite(&cm_scacheLock);
/* Check if we already have a sufficient server lock to allow this
- lock to go through */
- if(IS_LOCK_WAITLOCK(oldFileLock) &&
- (!SERVERLOCKS_ENABLED(scp) ||
- scp->serverLock == oldFileLock->lockType ||
- scp->serverLock == LockWrite)) {
+ lock to go through. */
+ if (IS_LOCK_WAITLOCK(oldFileLock) &&
+ (!SERVERLOCKS_ENABLED(scp) ||
+ scp->serverLock == oldFileLock->lockType ||
+ scp->serverLock == LockWrite)) {
oldFileLock->flags &= ~CM_FILELOCK_FLAG_WAITLOCK;
return 0;
}
- if(IS_LOCK_WAITUNLOCK(oldFileLock)) {
+ if (IS_LOCK_WAITUNLOCK(oldFileLock)) {
/* check if the conflicting locks have dissappeared already */
-
- for(q = scp->fileLocksH; q; q = osi_QNext(q)) {
+ for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
fileLock = (cm_file_lock_t *)
((char *) q - offsetof(cm_file_lock_t, fileq));
- if(IS_LOCK_LOST(fileLock)) {
+ if (IS_LOCK_LOST(fileLock)) {
if (fileLock->key == oldFileLock->key) {
code = CM_ERROR_BADFD;
oldFileLock->flags |= CM_FILELOCK_FLAG_LOST;
}
}
- if(IS_LOCK_ACCEPTED(fileLock) &&
- INTERSECT_RANGE(oldFileLock->range, fileLock->range)) {
+ if (IS_LOCK_ACCEPTED(fileLock) &&
+ INTERSECT_RANGE(oldFileLock->range, fileLock->range)) {
- if(oldFileLock->lockType != LockRead ||
+ if (oldFileLock->lockType != LockRead ||
fileLock->lockType != LockRead) {
osi_Log1(afsd_logp, " found conflicting lock %p", fileLock);
oldFileLock->flags |= CM_FILELOCK_FLAG_WAITLOCK;
}
- if (!SERVERLOCKS_ENABLED(scp) ||
+ if (force_client_lock ||
+ !SERVERLOCKS_ENABLED(scp) ||
scp->serverLock == oldFileLock->lockType ||
(oldFileLock->lockType == LockRead &&
scp->serverLock == LockWrite)) {
oldFileLock->flags &= ~CM_FILELOCK_FLAG_WAITLOCK;
+ if ((force_client_lock ||
+ !SERVERLOCKS_ENABLED(scp)) &&
+ !IS_LOCK_CLIENTONLY(oldFileLock)) {
+
+ oldFileLock->flags |= CM_FILELOCK_FLAG_CLIENTONLY;
+
+ if (oldFileLock->lockType == LockRead)
+ scp->sharedLocks--;
+ else
+ scp->exclusiveLocks--;
+
+ scp->clientLocks++;
+ }
+
lock_ReleaseWrite(&cm_scacheLock);
lock_ReleaseMutex(&scp->mx);
return 0;
} else {
- cm_fid_t cfid;
cm_user_t * userp;
code = cm_SyncOp(scp, NULL, oldFileLock->userp, &req, 0,
goto post_syncopdone;
}
- if(!IS_LOCK_WAITLOCK(oldFileLock))
+ if (!IS_LOCK_WAITLOCK(oldFileLock))
goto pre_syncopdone;
- tfid.Volume = scp->fid.volume;
- tfid.Vnode = scp->fid.vnode;
- tfid.Unique = scp->fid.unique;
- cfid = scp->fid;
userp = oldFileLock->userp;
#ifndef AGGRESSIVE_LOCKS
newLock = LockWrite;
#endif
- osi_Log1(afsd_logp, "CALL SetLock lock 0x%p", oldFileLock);
-
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
-
- do {
- code = cm_Conn(&cfid, userp, &req, &connp);
- if (code)
- break;
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, newLock,
- &volSync);
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, &req,
- &cfid, &volSync,
- NULL, NULL, code));
- code = cm_MapRPCError(code, &req);
-
- if (code) {
- osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
- } else {
- osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
- }
+ code = cm_IntSetLock(scp, userp, newLock, &req);
- lock_ObtainMutex(&scp->mx);
pre_syncopdone:
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
post_syncopdone:
handleCode:
if (code != 0 && code != CM_ERROR_WOULDBLOCK) {
+ lock_ObtainWrite(&cm_scacheLock);
if (scp->fileLocksT == &oldFileLock->fileq)
scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
- osi_QRemove(&scp->fileLocksH, &oldFileLock->fileq);
+ osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
+ lock_ReleaseWrite(&cm_scacheLock);
} else if (code == 0 && IS_LOCK_WAITLOCK(oldFileLock)) {
scp->serverLock = newLock;
}
cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
{
- return (((cm_key_t) process_id) << 32) |
- (((cm_key_t) session_id) << 16) |
- (((cm_key_t) file_id));
+#ifdef DEBUG
+ osi_assert((process_id & 0xffffffff) == process_id);
+ osi_assert((session_id & 0xffff) == session_id);
+ osi_assert((file_id & 0xffff) == file_id);
+#endif
+
+ return
+ (((cm_key_t) (process_id & 0xffffffff)) << 32) |
+ (((cm_key_t) (session_id & 0xffff)) << 16) |
+ (((cm_key_t) (file_id & 0xffff)));
}
static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags)
cm_user_t *userp;
cm_key_t key;
cm_file_lock_t *fileLock;
- int i;
+ unsigned int i;
for (i = 0; i < cm_data.hashTableSize; i++)
{