#include <osi.h>
#include "afsd.h"
+#include "cm_btree.h"
#ifdef DEBUG
extern void afsi_log(char *pattern, ...);
int cm_enableServerLocks = 1;
+int cm_followBackupPath = 0;
+
/*
* Case-folding array. This was constructed by inspecting of SMBtrace output.
* I do not know anything more about it.
if (openMode == 1 || openMode == 2 || trunc)
rights |= PRSFS_WRITE;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
_done:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
long rights;
long code;
- osi_assert(ldpp != NULL);
+ osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
/* Always allow delete; the RPC will tell us if it's OK */
rights = 0;
- if (desiredAccess & AFS_ACCESS_READ)
+ if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
/* We used to require PRSFS_WRITE if createDisp was 4
if (desiredAccess & AFS_ACCESS_WRITE)
rights |= PRSFS_WRITE;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
(*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
if (!*ldpp) {
code = ENOMEM;
- goto _done;
+ goto _syncopdone;
}
(*ldpp)->key = key;
goto _done;
}
+ _syncopdone:
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
_done:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ osi_Log3(afsd_logp,"cm_CheckNTOpen scp 0x%p ldp 0x%p code 0x%x", scp, *ldpp, code);
return code;
}
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);
if (*ldpp) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
(*ldpp)->key, userp, reqp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
free(*ldpp);
*ldpp = NULL;
}
long code;
osi_hyper_t thyper;
cm_buf_t *bufferp;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
unsigned short *hashTable;
unsigned int i, idx;
int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
+ int releaseLock = 0;
/* First check permissions */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_DELETE,
CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
if (code)
return code;
return code;
thyper.HighPart = 0; thyper.LowPart = 0;
- lock_ObtainRead(&scp->bufCreateLock);
code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
if (code)
return code;
lock_ObtainMutex(&bufferp->mx);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
+ releaseLock = 1;
while (1) {
code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_READ
| CM_SCACHESYNC_BUFLOCKED);
if (code)
- break;
+ goto done;
if (cm_HaveBuffer(scp, bufferp, 1))
break;
/* otherwise, load the buffer and try again */
lock_ReleaseMutex(&bufferp->mx);
code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainMutex(&bufferp->mx);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (code)
- break;
+ goto done;
}
+ lock_ReleaseWrite(&scp->rw);
+ releaseLock = 0;
+
/* We try to determine emptiness without looking beyond the first page,
* and without assuming "." and ".." are present and are on the first
* page (though these assumptions might, after all, be reasonable).
done:
lock_ReleaseMutex(&bufferp->mx);
buf_Release(bufferp);
- lock_ReleaseMutex(&scp->mx);
+ if (releaseLock)
+ lock_ReleaseWrite(&scp->rw);
return code;
}
{
char *tp;
long code;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
cm_buf_t *bufferp;
long temp;
osi_hyper_t dirLength;
int numDirChunks; /* # of 32 byte dir chunks in this entry */
/* get the directory size */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ if (code)
return code;
- }
- if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
- lock_ReleaseMutex(&scp->mx);
+ if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
return CM_ERROR_NOTDIR;
- }
if (retscp) /* if this is a lookup call */
{
cm_lookupSearch_t* sp = parmp;
+ if (
#ifdef AFS_FREELANCE_CLIENT
/* Freelance entries never end up in the DNLC because they
* do not have an associated cm_server_t
*/
- if ( !(cm_freelanceEnabled &&
+ !(cm_freelanceEnabled &&
sp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
- sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) )
-#endif /* AFS_FREELANCE_CLIENT */
- {
- int casefold = sp->caseFold;
- sp->caseFold = 0; /* we have a strong preference for exact matches */
- if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
+ sp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+#else /* !AFS_FREELANCE_CLIENT */
+ TRUE
+#endif
+ )
{
+ int casefold = sp->caseFold;
+ sp->caseFold = 0; /* we have a strong preference for exact matches */
+ if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
+ {
+ sp->caseFold = casefold;
+ return 0;
+ }
sp->caseFold = casefold;
- lock_ReleaseMutex(&scp->mx);
- return 0;
+
+ /* see if we can find it using the directory hash tables.
+ we can only do exact matches, since the hash is case
+ sensitive. */
+ {
+ cm_dirOp_t dirop;
+#ifdef USE_BPLUS
+ int usedBplus = 0;
+#endif
+
+ code = ENOENT;
+
+ code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ if (code == 0) {
+
+#ifdef USE_BPLUS
+ code = cm_BPlusDirLookup(&dirop, sp->searchNamep, &sp->fid);
+ if (code != EINVAL)
+ usedBplus = 1;
+ else
+#endif
+ code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
+
+ cm_EndDirOp(&dirop);
+ }
+
+ if (code == 0) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = TRUE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+#ifdef USE_BPLUS
+ if (usedBplus) {
+ if (sp->caseFold && code == CM_ERROR_INEXACT_MATCH) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = FALSE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+
+ return CM_ERROR_BPLUS_NOMATCH;
+ }
+#endif
+ }
}
- sp->caseFold = casefold;
- }
}
/*
*/
dirLength = scp->length;
- lock_ReleaseMutex(&scp->mx);
-
bufferp = NULL;
bufferOffset.LowPart = bufferOffset.HighPart = 0;
if (startOffsetp)
bufferp = NULL;
}
- lock_ObtainRead(&scp->bufCreateLock);
code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
if (code) {
/* if buf_Get() fails we do not have a buffer object to lock */
bufferp = NULL;
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);
+ lock_ObtainWrite(&scp->rw);
if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
&& (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
{
scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
scp->bulkStatProgress = thyper;
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
#endif
lock_ObtainMutex(&bufferp->mx);
/* now get the data in the cache */
while (1) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, bufferp, userp, reqp,
PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_READ
| CM_SCACHESYNC_BUFLOCKED);
if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (cm_HaveBuffer(scp, bufferp, 1)) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
lock_ReleaseMutex(&bufferp->mx);
code = cm_GetBuffer(scp, bufferp, NULL, userp,
reqp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainMutex(&bufferp->mx);
if (code)
break;
}
/* read the contents of a mount point into the appropriate string.
- * called with locked scp, and returns with locked scp.
+ * called with write locked scp, and returns with locked scp.
*/
long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
{
return 0;
/* otherwise, we have to read it in */
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
- lock_ObtainRead(&scp->bufCreateLock);
thyper.LowPart = thyper.HighPart = 0;
code = buf_Get(scp, &thyper, &bufp);
- lock_ReleaseRead(&scp->bufCreateLock);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (code)
return code;
/* called with a locked scp and chases the mount point, yielding outScpp.
- * scp remains locked, just for simplicity of describing the interface.
+ * scp remains write locked, just for simplicity of describing the interface.
*/
long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
cm_req_t *reqp, cm_scache_t **outScpp)
char mtType;
cm_fid_t tfid;
size_t vnLength;
- int type;
+ int targetType;
if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
tfid = scp->mountRootFid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
code = cm_GetSCache(&tfid, outScpp, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
return code;
}
strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
strcpy(volNamep, cp+1);
/* now look up the cell */
+ lock_ReleaseWrite(&scp->rw);
cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
+ lock_ObtainWrite(&scp->rw);
}
else {
/* normal mt pt */
strcpy(volNamep, mpNamep+1);
- cellp = cm_FindCellByID(scp->fid.cell);
+ cellp = cm_FindCellByID(scp->fid.cell, 0);
}
if (!cellp) {
vnLength = strlen(volNamep);
if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
- type = BACKVOL;
+ targetType = BACKVOL;
else if (vnLength >= 10
&& strcmp(volNamep + vnLength - 9, ".readonly") == 0)
- type = ROVOL;
+ targetType = ROVOL;
else
- type = RWVOL;
+ targetType = RWVOL;
/* check for backups within backups */
- if (type == BACKVOL
+ if (targetType == BACKVOL
&& (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
== CM_SCACHEFLAG_RO) {
code = CM_ERROR_NOSUCHVOLUME;
}
/* now we need to get the volume */
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
if (cm_VolNameIsID(volNamep)) {
code = cm_GetVolumeByID(cellp, atoi(volNamep), userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
code = cm_GetVolumeByName(cellp, volNamep, userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
}
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (code == 0) {
+ afs_uint32 cell, volume;
+
/* save the parent of the volume root for this is the
* place where the volume is mounted and we must remember
* this in the volume structure rather than just in the
volp->dotdotFid = dscp->fid;
lock_ReleaseMutex(&volp->mx);
- scp->mountRootFid.cell = cellp->cellID;
+ cell = cellp->cellID;
+
+ /* if the mt pt originates in a .backup volume (not a .readonly)
+ * and FollowBackupPath is active, and if there is a .backup
+ * volume for the target, then use the .backup of the target
+ * instead of the read-write.
+ */
+ if (cm_followBackupPath &&
+ volp->bk.ID != 0 &&
+ (dscp->flags & (CM_SCACHEFLAG_RO|CM_SCACHEFLAG_PURERO)) == CM_SCACHEFLAG_RO &&
+ (targetType == RWVOL || targetType == ROVOL && volp->ro.ID == 0)
+ ) {
+ targetType = BACKVOL;
+ }
/* if the mt pt is in a read-only volume (not just a
* backup), and if there is a read-only volume for the
- * target, and if this is a type '#' mount point, use
+ * target, and if this is a targetType '#' mount point, use
* the read-only, otherwise use the one specified.
*/
- if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
- && volp->ro.ID != 0 && type == RWVOL)
- type = ROVOL;
- if (type == ROVOL)
- scp->mountRootFid.volume = volp->ro.ID;
- else if (type == BACKVOL)
- scp->mountRootFid.volume = volp->bk.ID;
+ else if (mtType == '#' && targetType == RWVOL &&
+ (scp->flags & CM_SCACHEFLAG_PURERO) &&
+ volp->ro.ID != 0) {
+ targetType = ROVOL;
+ }
+ if (targetType == ROVOL)
+ volume = volp->ro.ID;
+ else if (targetType == BACKVOL)
+ volume = volp->bk.ID;
else
- scp->mountRootFid.volume = volp->rw.ID;
+ volume = volp->rw.ID;
/* the rest of the fid is a magic number */
- scp->mountRootFid.vnode = 1;
- scp->mountRootFid.unique = 1;
+ cm_SetFid(&scp->mountRootFid, cell, volume, 1, 1);
scp->mountRootGen = cm_data.mountRootGen;
tfid = scp->mountRootFid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
code = cm_GetSCache(&tfid, outScpp, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
}
done:
cm_lookupSearch_t rock;
int getroot;
+ memset(&rock, 0, sizeof(rock));
+
if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
&& strcmp(namep, "..") == 0) {
if (dscp->dotdotFid.volume == 0)
goto haveFid;
}
- memset(&rock, 0, sizeof(rock));
+ if (flags & CM_FLAG_NOMOUNTCHASE) {
+ /* In this case, we should go and call cm_Dir* functions
+ directly since the following cm_ApplyDir() function will
+ not. */
+
+ cm_dirOp_t dirop;
+#ifdef USE_BPLUS
+ int usedBplus = 0;
+#endif
+
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ if (code == 0) {
+#ifdef USE_BPLUS
+ code = cm_BPlusDirLookup(&dirop, namep, &rock.fid);
+ if (code != EINVAL)
+ usedBplus = 1;
+ else
+#endif
+ code = cm_DirLookup(&dirop, namep, &rock.fid);
+
+ cm_EndDirOp(&dirop);
+ }
+
+ if (code == 0) {
+ /* found it */
+ rock.found = TRUE;
+ goto haveFid;
+ }
+#ifdef USE_BPLUS
+ if (usedBplus) {
+ if (code == CM_ERROR_INEXACT_MATCH && (flags & CM_FLAG_CASEFOLD)) {
+ /* found it */
+ code = 0;
+ rock.found = TRUE;
+ goto haveFid;
+ }
+
+ return CM_ERROR_BPLUS_NOMATCH;
+ }
+#endif
+ }
+
rock.fid.cell = dscp->fid.cell;
rock.fid.volume = dscp->fid.volume;
rock.searchNamep = namep;
else
return CM_ERROR_NOSUCHFILE;
}
- else { /* nonexistent dir on freelance root, so add it */
+ else if (!strchr(namep, '#') && !strchr(namep, '%') &&
+ strcmp(namep, "srvsvc") && strcmp(namep, "wkssvc") &&
+ strcmp(namep, "ipc$")) {
+ /* nonexistent dir on freelance root, so add it */
char fullname[200] = ".";
int found = 0;
osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s",
osi_LogSaveString(afsd_logp,namep));
+
+ /*
+ * There is an ugly behavior where a share name "foo" will be searched
+ * for as "fo". If the searched for name differs by an already existing
+ * symlink or mount point in the Freelance directory, do not add the
+ * new value automatically.
+ */
+
+ code = -1;
if (namep[0] == '.') {
if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
found = 1;
- if ( stricmp(&namep[1], &fullname[1]) )
+ if (!cm_FreelanceMountPointExists(fullname, 0))
+ code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
+ if ( stricmp(&namep[1], &fullname[1]) &&
+ !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+ !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, &fullname[1], "root.cell.", 1, &rock.fid);
}
} else {
if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
found = 1;
- if ( stricmp(namep, fullname) )
+ if (!cm_FreelanceMountPointExists(fullname, 0))
+ code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
+ if ( stricmp(namep, fullname) &&
+ !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+ !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, fullname, "root.cell.", 0, &rock.fid);
}
}
if (!found || code < 0) { /* add mount point failed, so give up */
}
/* tscp is now held */
- lock_ObtainMutex(&tscp->mx);
+ lock_ObtainWrite(&tscp->rw);
code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
return code;
}
if (code == 0)
code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
&mountedScp);
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
if (code) {
return code;
tscp = mountedScp;
}
else {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
}
/* copy back pointer */
/* insert scache in dnlc */
if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
/* lock the directory entry to prevent racing callback revokes */
- lock_ObtainMutex(&dscp->mx);
+ lock_ObtainRead(&dscp->rw);
if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
cm_dnlcEnter(dscp, namep, tscp);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseRead(&dscp->rw);
}
/* and return */
if (outp == NULL)
return 1;
- if (index >= MAXNUMSYSNAMES)
+ if (index >= cm_sysNameCount)
return -1;
/* otherwise generate the properly expanded @sys name */
cm_cell_t * cellp = NULL;
cm_volume_t * volp = NULL;
cm_fid_t fid;
+ afs_uint32 volume;
int volType;
int mountType = RWVOL;
if (code != 0)
goto _exit_cleanup;
- fid.cell = cellp->cellID;
-
if (volType == BACKVOL)
- fid.volume = volp->bk.ID;
+ volume = volp->bk.ID;
else if (volType == ROVOL ||
(volType == RWVOL && mountType == ROVOL && volp->ro.ID != 0))
- fid.volume = volp->ro.ID;
+ volume = volp->ro.ID;
else
- fid.volume = volp->rw.ID;
+ volume = volp->rw.ID;
- fid.vnode = 1;
- fid.unique = 1;
+ cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
code = cm_GetSCache(&fid, outpScpp, userp, reqp);
#endif
{
long code;
- char tname[256];
+ char tname[AFSPATHMAX];
int sysNameIndex = 0;
cm_scache_t *scp = NULL;
AFSFetchStatus newDirStatus;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
#ifdef AFS_FREELANCE_CLIENT
if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
#endif
/* make sure we don't screw up the dir status during the merge */
- lock_ObtainMutex(&dscp->mx);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+
+ lock_ObtainWrite(&dscp->rw);
sflags = CM_SCACHESYNC_STOREDATA;
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
- lock_ReleaseMutex(&dscp->mx);
- if (code)
+ lock_ReleaseWrite(&dscp->rw);
+ if (code) {
+ cm_EndDirOp(&dirop);
return code;
+ }
/* make the RPC */
afsFid.Volume = dscp->fid.volume;
else
osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_dnlcRemove(dscp, namep);
cm_SyncOpDone(dscp, NULL, sflags);
- if (code == 0)
- cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
- else if (code == CM_ERROR_NOSUCHFILE) {
+ if (code == 0) {
+ cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 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;
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0 && cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirDeleteEntry(&dirop, namep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, namep);
+#endif
+ }
+ cm_EndDirOp(&dirop);
return code;
}
-/* called with a locked vnode, and fills in the link info.
- * returns this the vnode still locked.
+/* called with a write locked vnode, and fills in the link info.
+ * returns this the vnode still write locked.
*/
long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
{
long temp;
osi_hyper_t thyper;
- lock_AssertMutex(&linkScp->mx);
+ lock_AssertWrite(&linkScp->rw);
if (!linkScp->mountPointStringp[0]) {
/* read the link data */
- lock_ReleaseMutex(&linkScp->mx);
+ lock_ReleaseWrite(&linkScp->rw);
thyper.LowPart = thyper.HighPart = 0;
code = buf_Get(linkScp, &thyper, &bufp);
- lock_ObtainMutex(&linkScp->mx);
+ lock_ObtainWrite(&linkScp->rw);
if (code)
return code;
while (1) {
if (!linkScp->mountPointStringp[0]) {
strncpy(linkScp->mountPointStringp, bufp->datap, temp);
linkScp->mountPointStringp[temp] = 0; /* null terminate */
+
+ if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
+ linkScp->fileType = CM_SCACHETYPE_DFSLINK;
}
buf_Release(bufp);
} /* don't have sym link contents cached */
char *linkp;
cm_space_t *tsp;
- lock_ObtainMutex(&linkScp->mx);
+ *newRootScpp = NULL;
+ *newSpaceBufferp = NULL;
+
+ lock_ObtainWrite(&linkScp->rw);
code = cm_HandleLink(linkScp, userp, reqp);
- if (code)
+ if (code)
goto done;
/* if we may overflow the buffer, bail out; buffer is signficantly
* being a little conservative here.
*/
if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
- >= CM_UTILS_SPACESIZE)
- return CM_ERROR_TOOBIG;
+ >= CM_UTILS_SPACESIZE) {
+ code = CM_ERROR_TOOBIG;
+ goto done;
+ }
tsp = cm_GetSpace();
linkp = linkScp->mountPointStringp;
} else {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_PATH_NOT_COVERED;
}
- } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
+ } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
+ !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_PATH_NOT_COVERED;
} else if (*linkp == '\\' || *linkp == '/') {
#if 0
*/
linkScp->fileType = CM_SCACHETYPE_INVALID;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_NOSUCHPATH;
#endif
} else {
/* a relative link */
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
}
if (pathSuffixp[0] != 0) { /* if suffix string is non-null */
strcat(tsp->data, "\\");
strcat(tsp->data, pathSuffixp);
}
- *newSpaceBufferp = tsp;
+ if (code == 0)
+ *newSpaceBufferp = tsp;
+ else {
+ cm_FreeSpace(tsp);
+
+ if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp)
+ cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+ }
done:
- lock_ReleaseMutex(&linkScp->mx);
+ lock_ReleaseWrite(&linkScp->rw);
return code;
}
#ifdef DEBUG_REFCOUNT
char *tp; /* ptr moving through input buffer */
char tc; /* temp char */
int haveComponent; /* has new component started? */
- char component[256]; /* this is the new component */
+ char component[AFSPATHMAX]; /* this is the new component */
char *cp; /* component name being assembled */
cm_scache_t *tscp; /* current location in the hierarchy */
cm_scache_t *nscp; /* next dude down */
int symlinkCount; /* count of # of symlinks traversed */
int extraFlag; /* avoid chasing mt pts for dir cmd */
int phase = 1; /* 1 = tidPathp, 2 = pathp */
+#define MAX_FID_COUNT 512
+ cm_fid_t fids[MAX_FID_COUNT]; /* array of fids processed in this path walk */
+ int fid_count = 0; /* number of fids processed in this path walk */
+ int i;
#ifdef DEBUG_REFCOUNT
afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
code = cm_Lookup(tscp, component,
flags | extraFlag,
userp, reqp, &nscp);
- if (code) {
+
+ if (code == 0) {
+ if (!strcmp(component,"..") || !strcmp(component,".")) {
+ /*
+ * roll back the fid list until we find the fid
+ * that matches where we are now. Its not necessarily
+ * one or two fids because they might have been
+ * symlinks or mount points or both that were crossed.
+ */
+ for ( i=fid_count-1; i>=0; i--) {
+ if (!cm_FidCmp(&nscp->fid, &fids[i]))
+ break;
+ }
+ fid_count = i+1;
+ } else {
+ /* add the new fid to the list */
+ for ( i=0; i<fid_count; i++) {
+ if ( !cm_FidCmp(&nscp->fid, &fids[i]) ) {
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
+ cm_ReleaseSCache(nscp);
+ nscp = NULL;
+ break;
+ }
+ }
+ if (i == fid_count && fid_count < MAX_FID_COUNT) {
+ fids[fid_count++] = nscp->fid;
+ }
+ }
+ }
+
+ 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) {
+ if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
+ 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);
/* now, if tscp is a symlink, we should follow
* it and assemble the path again.
*/
- lock_ObtainMutex(&tscp->mx);
+ lock_ObtainWrite(&tscp->rw);
code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
tscp = NULL;
if (dirScp) {
if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
/* this is a symlink; assemble a new buffer */
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
cm_ReleaseSCache(tscp);
tscp = NULL;
else
restp = tp;
code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
+
+ if (code == 0 && linkScp != NULL) {
+ if (linkScp == cm_data.rootSCachep)
+ fid_count = 0;
+ else {
+ for ( i=0; i<fid_count; i++) {
+ if ( !cm_FidCmp(&linkScp->fid, &fids[i]) ) {
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
+ cm_ReleaseSCache(linkScp);
+ nscp = NULL;
+ break;
+ }
+ }
+ }
+ if (i == fid_count && fid_count < MAX_FID_COUNT) {
+ fids[fid_count++] = linkScp->fid;
+ }
+ }
+
if (code) {
/* something went wrong */
cm_ReleaseSCache(tscp);
}
} else {
/* not a symlink, we may be done */
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
if (tc == 0) {
if (phase == 1) {
phase = 2;
CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
userp, NULL, reqp, outScpp);
- if (code == CM_ERROR_NOSUCHFILE)
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
code = CM_ERROR_NOSUCHPATH;
/* this stuff is allocated no matter what happened on the namei call,
cm_FreeSpace(spacep);
cm_ReleaseSCache(newRootScp);
+ if (linkScp == *outScpp) {
+ cm_ReleaseSCache(*outScpp);
+ *outScpp = NULL;
+ code = CM_ERROR_NOSUCHPATH;
+ }
+
return code;
}
if (strcmp(dep->name, ".") == 0 || strcmp(dep->name, "..") == 0)
return 0;
- tfid.cell = scp->fid.cell;
- tfid.volume = scp->fid.volume;
- tfid.vnode = ntohl(dep->fid.vnode);
- tfid.unique = ntohl(dep->fid.unique);
+ cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
tscp = cm_FindSCache(&tfid);
if (tscp) {
- if (lock_TryMutex(&tscp->mx)) {
+ if (lock_TryWrite(&tscp->rw)) {
/* we have an entry that we can look at */
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.
*/
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
return 0;
}
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
} /* got lock */
cm_ReleaseSCache(tscp);
} /* found entry */
return 0;
}
-/* called with a locked scp and a pointer to a buffer. Make bulk stat
+/* called with a write locked scp and a pointer to a buffer. Make bulk stat
* calls on all undeleted files in the page of the directory specified.
*/
afs_int32
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);
+ osi_assertx((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0, "invalid offset");
memset(&bb, 0, sizeof(bb));
bb.bufOffset = *offsetp;
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* first, assemble the file IDs we need to stat */
code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp, reqp, NULL);
/* if we failed, bail out early */
if (code && code != CM_ERROR_STOPNOW) {
- lock_ObtainMutex(&dscp->mx);
+ lock_ObtainWrite(&dscp->rw);
return code;
}
/* otherwise, we should do the merges */
for (i = 0; i<filesThisCall; i++) {
j = filex + i;
- tfid.cell = dscp->fid.cell;
- tfid.volume = bb.fids[j].Volume;
- tfid.vnode = bb.fids[j].Vnode;
- tfid.unique = bb.fids[j].Unique;
+ cm_SetFid(&tfid, dscp->fid.cell, bb.fids[j].Volume, bb.fids[j].Vnode, bb.fids[j].Unique);
code = cm_GetSCache(&tfid, &scp, userp, reqp);
if (code != 0)
continue;
/* otherwise, if this entry has no callback info,
* merge in this.
*/
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* now, we have to be extra paranoid on merging in this
* information, since we didn't use cm_SyncOp before
* starting the fetch to make sure that no bad races
CM_CALLBACK_MAINTAINCOUNT);
cm_MergeStatus(dscp, scp, &bb.stats[j], &volSync, userp, 0);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
} /* all files in the response */
/* now tell it to drop the count,
filex += filesThisCall;
} /* while there are still more files to process */
- lock_ObtainMutex(&dscp->mx);
+ lock_ObtainWrite(&dscp->rw);
/* If we did the InlineBulk RPC pull out the return code and log it */
if (inlinebulk) {
lock_ObtainWrite(&scp->bufCreateLock);
/* verify that this is a file, not a dir or a symlink */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code)
else
shrinking = 0;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
- /* can't hold scp->mx lock here, since we may wait for a storeback to
+ /* can't hold scp->rw lock here, since we may wait for a storeback to
* finish if the buffer package is cleaning a buffer by storing it to
* the server.
*/
buf_Truncate(scp, userp, reqp, sizep);
/* now ensure that file length is short enough, and update truncPos */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* make sure we have a callback (so we have the right value for the
* length), and wait for it to be safe to do a truncate.
| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
done:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ReleaseWrite(&scp->bufCreateLock);
return code;
if (attrp->mask & CM_ATTRMASK_LENGTH)
return cm_SetLength(scp, &attrp->length, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* 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);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
+ lock_ConvertWToR(&scp->rw);
/* 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);
+ lock_ReleaseRead(&scp->rw);
/* now make the RPC */
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
else
osi_Log0(afsd_logp, "CALL StoreStatus SUCCESS");
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
if (code == 0)
cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp,
*/
if (afsInStatus.Mask & AFS_SETMODE)
cm_FreeAllACLEnts(scp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
cm_callbackRequest_t cbReq;
AFSFid newAFSFid;
cm_fid_t newFid;
- cm_scache_t *scp;
+ cm_scache_t *scp = NULL;
int didEnd;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSCallBack newFileCallback;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold files */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
/* before starting the RPC, mark that we're changing the file data, so
* that someone who does a chmod will know to wait until our call
* completes.
*/
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
+ } else {
+ cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
else
osi_Log0(afsd_logp, "CALL CreateFile SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* now try to create the file's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
&newFileCallback, 0);
didEnd = 1;
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
*scpp = scp;
}
}
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirCreateEntry(&dirop, namep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+#endif
+ }
+ cm_EndDirOp(&dirop);
+
return code;
}
{
long code;
- lock_ObtainWrite(&scp->bufCreateLock);
code = buf_CleanVnode(scp, userp, reqp);
- lock_ReleaseWrite(&scp->bufCreateLock);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
| CM_SCACHEMASK_CLIENTMODTIME
scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
}
return code;
}
cm_callbackRequest_t cbReq;
AFSFid newAFSFid;
cm_fid_t newFid;
- cm_scache_t *scp;
+ cm_scache_t *scp = NULL;
int didEnd;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSCallBack newDirCallback;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold subdirectories */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
/* 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
+ } else {
+ cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
else
osi_Log0(afsd_logp, "CALL MakeDir SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* now try to create the new dir's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
userp, 0);
&newDirCallback, 0);
didEnd = 1;
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
}
}
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirCreateEntry(&dirop, namep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+#endif
+ }
+ cm_EndDirOp(&dirop);
+
/* and return error code */
return code;
}
AFSFetchStatus newLinkStatus;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
if (dscp->fid.cell != sscp->fid.cell ||
dscp->fid.volume != sscp->fid.volume) {
return CM_ERROR_CROSSDEVLINK;
}
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&dirop);
if (code)
return code;
else
osi_Log0(afsd_logp, "CALL Link SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ }
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirCreateEntry(&dirop, namep, &sscp->fid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &sscp->fid);
+#endif
+ }
}
- lock_ReleaseMutex(&dscp->mx);
+ cm_EndDirOp(&dirop);
return code;
}
AFSFetchStatus newLinkStatus;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
/* 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&dirop);
if (code) {
return code;
}
else
osi_Log0(afsd_logp, "CALL Symlink SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ }
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+
+ cm_DirCreateEntry(&dirop, namep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+#endif
+ }
}
- lock_ReleaseMutex(&dscp->mx);
+ cm_EndDirOp(&dirop);
/* now try to create the new dir's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
userp, 0);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
}
}
AFSFetchStatus updatedDirStatus;
AFSVolSync volSync;
struct rx_connection * callp;
+ cm_dirOp_t dirop;
/* 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
if (code) {
+ cm_EndDirOp(&dirop);
return code;
}
didEnd = 0;
else
osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_dnlcRemove(dscp, namep);
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ }
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirDeleteEntry(&dirop, namep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, namep);
+#endif
+ }
}
- lock_ReleaseMutex(&dscp->mx);
+ cm_EndDirOp(&dirop);
/* and return error code */
return code;
long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
{
/* grab mutex on contents */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* reset the prefetch info */
scp->prefetch.base.LowPart = 0; /* base */
scp->prefetch.end.HighPart = 0;
/* release mutex on contents */
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
/* we're done */
return 0;
AFSVolSync volSync;
int oneDir;
struct rx_connection * callp;
+ cm_dirOp_t oldDirOp;
+ cm_fid_t fileFid;
+ int diropCode = -1;
+ cm_dirOp_t newDirOp;
/* 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
return CM_ERROR_RENAME_IDENTICAL;
oneDir = 1;
- lock_ObtainMutex(&oldDscp->mx);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, oldNamep);
cm_dnlcRemove(oldDscp, newNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0) {
+ cm_EndDirOp(&oldDirOp);
+ }
}
else {
/* two distinct dir vnodes */
return CM_ERROR_CROSSDEVLINK;
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
- lock_ObtainMutex(&oldDscp->mx);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&oldDirOp);
if (code == 0) {
- lock_ObtainMutex(&newDscp->mx);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ lock_ReleaseWrite(&newDscp->rw);
if (code) {
+ cm_EndDirOp(&newDirOp);
+
/* cleanup first one */
- lock_ObtainMutex(&oldDscp->mx);
+ lock_ObtainWrite(&oldDscp->rw);
cm_SyncOpDone(oldDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ cm_EndDirOp(&oldDirOp);
}
}
}
else {
/* lock the new vnode entry first */
- lock_ObtainMutex(&newDscp->mx);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ lock_ReleaseWrite(&newDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&newDirOp);
if (code == 0) {
- lock_ObtainMutex(&oldDscp->mx);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&oldDirOp);
if (code) {
/* cleanup first one */
- lock_ObtainMutex(&newDscp->mx);
+ lock_ObtainWrite(&newDscp->rw);
cm_SyncOpDone(newDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ lock_ReleaseWrite(&newDscp->rw);
+ cm_EndDirOp(&newDirOp);
}
}
}
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
/* update the individual stat cache entries for the directories */
- lock_ObtainMutex(&oldDscp->mx);
+ if (oldDirOp.scp) {
+ lock_ObtainWrite(&oldDirOp.scp->dirlock);
+ oldDirOp.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&oldDscp->rw);
cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0) {
+
+ if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
- userp, 0);
+ userp, CM_MERGEFLAG_DIROP);
+ lock_ReleaseWrite(&oldDscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
+
+#ifdef USE_BPLUS
+ diropCode = cm_BPlusDirLookup(&oldDirOp, oldNamep, &fileFid);
+ if (diropCode == CM_ERROR_INEXACT_MATCH)
+ diropCode = 0;
+ else if (diropCode == EINVAL)
+#endif
+ diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+
+ if (diropCode == 0) {
+ if (oneDir) {
+ diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#endif
+ }
+
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&oldDirOp, oldNamep);
+#endif
+ }
+ }
+ }
}
- lock_ReleaseMutex(&oldDscp->mx);
+ cm_EndDirOp(&oldDirOp);
/* and update it for the new one, too, if necessary */
if (!oneDir) {
- lock_ObtainMutex(&newDscp->mx);
+ if (newDirOp.scp) {
+ lock_ObtainWrite(&newDirOp.scp->dirlock);
+ newDirOp.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&newDscp->rw);
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0) {
+ if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
- userp, 0);
+ userp, CM_MERGEFLAG_DIROP);
+ lock_ReleaseWrite(&newDscp->rw);
+
+ 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 */
+ if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
+ cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&newDirOp, newNamep, &fileFid);
+#endif
+ }
}
- lock_ReleaseMutex(&newDscp->mx);
+ cm_EndDirOp(&newDirOp);
}
/* and return error code */
}
}
-/* Called with scp->mx held. Returns 0 if all is clear to read the
+/* Called with scp->rw held. Returns 0 if all is clear to read the
specified range by the client identified by key.
*/
long cm_LockCheckRead(cm_scache_t *scp,
#endif
}
-/* Called with scp->mx held. Returns 0 if all is clear to write the
+/* Called with scp->rw held. Returns 0 if all is clear to write the
specified range by the client identified by key.
*/
long cm_LockCheckWrite(cm_scache_t *scp,
#endif
}
-/* Forward dcl. */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp);
-
/* Called with cm_scacheLock write locked */
static cm_file_lock_t * cm_GetFileLock(void) {
cm_file_lock_t * l;
osi_QRemove(&cm_freeFileLocks, &l->q);
} else {
l = malloc(sizeof(cm_file_lock_t));
- osi_assert(l);
+ osi_assertx(l, "null cm_file_lock_t");
}
memset(l, 0, sizeof(cm_file_lock_t));
osi_QAdd(&cm_freeFileLocks, &l->q);
}
-/* called with scp->mx held. May release it during processing, but
+/* called with scp->rw 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) {
cm_conn_t * connp;
struct rx_connection * callp;
AFSVolSync volSync;
+ afs_uint32 reqflags = reqp->flags;
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
- lock_ReleaseMutex(&scp->mx);
+ reqp->flags |= CM_REQ_NORETRY;
+ lock_ReleaseWrite(&scp->rw);
do {
code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
}
- lock_ObtainMutex(&scp->mx);
-
+ lock_ObtainWrite(&scp->rw);
+ reqp->flags = reqflags;
return code;
}
-/* called with scp->mx held. Releases it during processing */
+/* called with scp->rw held. Releases it during processing */
long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
cm_req_t * reqp) {
long code = 0;
tfid.Unique = scp->fid.unique;
cfid = scp->fid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
osi_Log0(afsd_logp,
"CALL ReleaseLock SUCCESS");
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
return code;
}
-/* called with scp->mx held. May release it during processing, but
+/* called with scp->rw held. May release it during processing, but
will exit with lock held.
This will return:
rights |= PRSFS_WRITE | PRSFS_LOCK;
else {
/* hmmkay */
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid lock type");
return 0;
}
return code;
}
-/* called with scp->mx held */
+/* called with scp->rw held */
long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
cm_key_t key,
osi_Log0(afsd_logp,
" attempting to UPGRADE from LockRead to LockWrite.");
osi_Log1(afsd_logp,
- " dataVersion on scp: %d", scp->dataVersion);
+ " dataVersion on scp: %I64d", scp->dataVersion);
/* we assume at this point (because scp->serverLock
was valid) that we had a valid server lock. */
newLock = Which;
/* am I sane? */
- osi_assert(newLock == LockRead);
+ osi_assertx(newLock == LockRead, "lock type not read");
code = cm_IntSetLock(scp, userp, newLock, reqp);
}
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags);
-/* Called with scp->mx held */
+/* Called with scp->rw held */
long cm_UnlockByKey(cm_scache_t * scp,
cm_key_t key,
int flags,
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
/* 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);
+ osi_Log1(afsd_logp, " dataVersion on scp = %I64d", scp->dataVersion);
code = cm_IntReleaseLock(scp, userp, reqp);
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",
+ osi_Log2(afsd_logp, " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
if (!IS_LOCK_DELETED(fileLock) &&
lock_ReleaseRead(&cm_scacheLock);
/* The lock didn't exist anyway. *shrug* */
- return 0;
+ return CM_ERROR_RANGE_NOT_LOCKED;
}
- lock_ReleaseRead(&cm_scacheLock);
-
/* discard lock record */
- lock_ObtainWrite(&cm_scacheLock);
+ lock_ConvertRToW(&cm_scacheLock);
if (scp->fileLocksT == q)
scp->fileLocksT = osi_QPrev(q);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
/* 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);
+ osi_Log1(afsd_logp, " dataVersion on scp is %I64d", scp->dataVersion);
/* before we downgrade, make sure that we have enough
permissions to get the read lock. */
osi_Log0(afsd_logp,
"Data version mismatch while downgrading lock");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
return code;
}
-/* called with scp->mx held */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp)
+/* called with scp->rw held */
+void cm_LockMarkSCacheLost(cm_scache_t * scp)
{
cm_file_lock_t *fileLock;
osi_queue_t *q;
#ifdef DEBUG
/* With the current code, we can't lose a lock on a RO scp */
- osi_assert(!(scp->flags & CM_SCACHEFLAG_RO));
+ osi_assertx(!(scp->flags & CM_SCACHEFLAG_RO), "CM_SCACHEFLAG_RO unexpected");
#endif
/* cm_scacheLock needed because we are modifying fileLock->flags */
/* Server locks must have been enabled for us to have
received an active non-client-only lock. */
- osi_assert(cm_enableServerLocks);
+ osi_assertx(cm_enableServerLocks, "!cm_enableServerLocks");
scp = fileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
cm_HoldSCacheNoLock(scp);
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid");
}
#endif
/* Server locks are extended once per scp per refresh
osi_Log1(afsd_logp, "cm_CheckLocks Updating scp 0x%x", scp);
lock_ReleaseWrite(&cm_scacheLock);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* did the lock change while we weren't holding the lock? */
if (!IS_LOCK_ACTIVE(fileLock))
goto post_syncopdone;
}
- /* cm_SyncOp releases scp->mx during which the lock
+ /* cm_SyncOp releases scp->rw during which the lock
may get released. */
if (!IS_LOCK_ACTIVE(fileLock))
goto pre_syncopdone;
- if (scp->serverLock != -1) {
+ if (scp->serverLock != -1 && !(scp->flags & CM_SCACHEFLAG_DELETED)) {
cm_fid_t cfid;
cm_user_t * userp;
scp,
(int) scp->serverLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
do {
code = cm_ConnFromFID(&cfid, userp,
code = cm_MapRPCError(code, &req);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (code) {
osi_Log1(afsd_logp, "CALL ExtendLock FAILURE, code 0x%x", code);
"Data version mismatch on scp 0x%p",
scp);
osi_Log2(afsd_logp,
- " Data versions: before=%d, after=%d",
+ " Data versions: before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
}
}
- if (code == EINVAL || code == CM_ERROR_INVAL) {
+ if (code == EINVAL || code == CM_ERROR_INVAL ||
+ code == CM_ERROR_BADFD) {
cm_LockMarkSCacheLost(scp);
}
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
post_syncopdone:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainWrite(&cm_scacheLock);
osi_Log1(afsd_logp, "cm_CheckLocks completes lock check cycle %d", cm_lockRefreshCycle);
}
-/* NOT called with scp->mx held. */
+/* NOT called with scp->rw held. */
long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
{
long code = 0;
scp = oldFileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
lock_ReleaseRead(&cm_scacheLock);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_LockCheckPerms(scp, oldFileLock->lockType,
oldFileLock->userp,
}
code = 0;
} else if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
}
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return 0;
}
if (code != 0) {
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
goto handleCode;
}
oldFileLock->flags |= CM_FILELOCK_FLAG_WAITLOCK;
}
- osi_assert(IS_LOCK_WAITLOCK(oldFileLock));
+ osi_assertx(IS_LOCK_WAITLOCK(oldFileLock), "!IS_LOCK_WAITLOCK");
if (force_client_lock ||
!SERVERLOCKS_ENABLED(scp) ||
}
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return 0;
if (scp->serverLock == LockRead) {
- osi_assert(newLock == LockWrite);
+ osi_assertx(newLock == LockWrite, "!LockWrite");
osi_Log0(afsd_logp, " Attempting to UPGRADE from LockRead to LockWrite");
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
lock_ReleaseWrite(&cm_scacheLock);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
updateLock:
lock_ObtainWrite(&cm_scacheLock);
cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int 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);
+ osi_assertx((process_id & 0xffffffff) == process_id, "unexpected process_id");
+ osi_assertx((session_id & 0xffff) == session_id, "unexpected session_id");
+ osi_assertx((file_id & 0xffff) == file_id, "unexpected file_id");
#endif
return
{
for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
while (scp->fileLocksH != NULL) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
lock_ObtainWrite(&cm_scacheLock);
if (!scp->fileLocksH) {
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
fileLock = (cm_file_lock_t *)((char *) scp->fileLocksH - offsetof(cm_file_lock_t, fileq));
cm_UnlockByKey(scp, key, 0, userp, &req);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
}
}
}