/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
#include <afsconfig.h>
#include <afs/param.h>
+#include <afs/stds.h>
#include <roken.h>
-#include <afs/stds.h>
+#include <afs/unified_afs.h>
#include <windows.h>
#include <winsock2.h>
-#include <stddef.h>
-#include <malloc.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
#include <osi.h>
long code;
rights = 0;
- if (openMode != 1)
+ if (openMode != 1)
rights |= PRSFS_READ;
- if (openMode == 1 || openMode == 2 || trunc)
+ if (openMode == 1 || openMode == 2 || trunc)
rights |= PRSFS_WRITE;
-
+
lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
| CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_LOCK);
- if (code == 0 &&
+ if (code == 0 &&
((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
scp->fileType == CM_SCACHETYPE_FILE) {
!(rights & PRSFS_WRITE))
code = 0;
else {
- switch (code) {
- case CM_ERROR_ALLOFFLINE:
- case CM_ERROR_ALLDOWN:
- case CM_ERROR_ALLBUSY:
- case CM_ERROR_TIMEDOUT:
- case CM_ERROR_RETRY:
- case CM_ERROR_WOULDBLOCK:
- break;
- default:
+ if (code == CM_ERROR_LOCK_NOT_GRANTED)
code = CM_ERROR_SHARING_VIOLATION;
- }
}
}
}
/* return success if we can open this file in this mode */
-long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
- unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp,
+long cm_CheckNTOpen(cm_scache_t *scp,
+ unsigned int desiredAccess,
+ unsigned int shareAccess,
+ unsigned int createDisp,
+ afs_offs_t process_id,
+ afs_offs_t handle_id,
+ cm_user_t *userp, cm_req_t *reqp,
cm_lock_data_t **ldpp)
{
long rights;
long code = 0;
+ afs_uint16 session_id;
osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
+ /* compute the session id */
+ if (reqp->flags & CM_REQ_SOURCE_SMB)
+ session_id = CM_SESSION_SMB;
+ else if (reqp->flags & CM_REQ_SOURCE_REDIR)
+ session_id = CM_SESSION_IFS;
+ else
+ session_id = CM_SESSION_CMINT;
+
+ /* Ignore the SYNCHRONIZE privilege */
+ desiredAccess &= ~SYNCHRONIZE;
+
/* Always allow delete; the RPC will tell us if it's OK */
rights = 0;
if (desiredAccess == DELETE)
goto done_2;
+ /* Always allow reading attributes (Hidden, System, Readonly, ...) */
+ if (desiredAccess == FILE_READ_ATTRIBUTES)
+ goto done_2;
+
if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
code = CM_ERROR_NOACCESS;
if (code == 0 &&
- ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
- scp->fileType == CM_SCACHETYPE_FILE) {
+ !(shareAccess & FILE_SHARE_WRITE) &&
+ ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
+ scp->fileType == CM_SCACHETYPE_FILE) {
cm_key_t key;
unsigned int sLockType;
LARGE_INTEGER LOffset, LLength;
/* Check if there's some sort of lock on the file at the
moment. */
- key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
if (rights & PRSFS_WRITE)
sLockType = 0;
else
sLockType = LOCKING_ANDX_SHARED_LOCK;
+ key = cm_GenerateKey(session_id, process_id, 0);
+
/* single byte lock at offset 0x0100 0000 0000 0000 */
LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
LOffset.LowPart = CM_FLSHARE_OFFSET_LOW;
code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
if (code == 0) {
- (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
- if (!*ldpp) {
- code = ENOMEM;
- goto _done;
- }
+ (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
+ if (!*ldpp) {
+ code = ENOMEM;
+ goto _done;
+ }
- (*ldpp)->key = key;
- (*ldpp)->sLockType = sLockType;
- (*ldpp)->LOffset.HighPart = LOffset.HighPart;
- (*ldpp)->LOffset.LowPart = LOffset.LowPart;
- (*ldpp)->LLength.HighPart = LLength.HighPart;
- (*ldpp)->LLength.LowPart = LLength.LowPart;
+ (*ldpp)->key = key;
+ (*ldpp)->sLockType = sLockType;
+ (*ldpp)->LOffset.HighPart = LOffset.HighPart;
+ (*ldpp)->LOffset.LowPart = LOffset.LowPart;
+ (*ldpp)->LLength.HighPart = LLength.HighPart;
+ (*ldpp)->LLength.LowPart = LLength.LowPart;
} else {
- /* In this case, we allow the file open to go through even
- though we can't enforce mandatory locking on the
- file. */
+ /*
+ * In this case, we allow the file open to go through even
+ * though we can't enforce mandatory locking on the
+ * file. */
if (code == CM_ERROR_NOACCESS &&
- !(rights & PRSFS_WRITE))
+ !(rights & PRSFS_WRITE))
code = 0;
else {
- switch (code) {
- case CM_ERROR_ALLOFFLINE:
- case CM_ERROR_ALLDOWN:
- case CM_ERROR_ALLBUSY:
- case CM_ERROR_TIMEDOUT:
- case CM_ERROR_RETRY:
- case CM_ERROR_WOULDBLOCK:
- break;
- default:
- code = CM_ERROR_SHARING_VIOLATION;
- }
- }
+ if (code == CM_ERROR_LOCK_NOT_GRANTED)
+ code = CM_ERROR_SHARING_VIOLATION;
+ }
}
} else if (code != 0) {
goto _done;
return code;
}
-extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
+extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
cm_lock_data_t ** ldpp)
{
- osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+ osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, ldpp ? *ldpp : 0);
lock_ObtainWrite(&scp->rw);
- if (*ldpp) {
- cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
+ if (ldpp && *ldpp) {
+ cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
(*ldpp)->key, 0, userp, reqp);
free(*ldpp);
*ldpp = NULL;
return code;
thyper.HighPart = 0; thyper.LowPart = 0;
- code = buf_Get(scp, &thyper, reqp, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, 0, &bufferp);
if (code)
return code;
if (code)
goto done;
- if (cm_HaveBuffer(scp, bufferp, 1))
+ if (cm_HaveBuffer(scp, bufferp, 1)) {
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
break;
+ }
/* otherwise, load the buffer and try again */
lock_ReleaseMutex(&bufferp->mx);
code = CM_ERROR_NOTEMPTY;
else
code = 0;
- done:
+ done:
lock_ReleaseMutex(&bufferp->mx);
buf_Release(bufferp);
if (releaseLock)
lock_ReleaseWrite(&scp->rw);
return code;
-}
+}
/*
* Iterate through all entries in a directory.
* When the function funcp is called, the buffer is locked but the
* directory vnode is not.
*
- * If the retscp parameter is not NULL, the parmp must be a
- * cm_lookupSearch_t object.
+ * If the retscp parameter is not NULL, the parmp must be a
+ * cm_lookupSearch_t object.
*/
long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
int slotInPage;
long nextEntryCookie;
int numDirChunks; /* # of 32 byte dir chunks in this entry */
-
+
/* get the directory size */
lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
lock_ReleaseWrite(&scp->rw);
if (code)
return code;
-
+
if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
return CM_ERROR_NOTDIR;
#else /* !AFS_FREELANCE_CLIENT */
TRUE
#endif
- )
+ )
{
int casefold = sp->caseFold;
sp->caseFold = 0; /* we have a strong preference for exact matches */
}
#endif
}
- }
+ }
/*
* XXX We only get the length once. It might change when we drop the
else {
curOffset.HighPart = 0;
curOffset.LowPart = 0;
- }
+ }
while (1) {
/* make sure that curOffset.LowPart doesn't point to the first
else {
/* we're in a later dir page */
if (temp < 32) temp = 32;
- }
-
+ }
+
/* make sure the low order 5 bits are zero */
temp &= ~(32-1);
-
+
/* now put temp bits back ito curOffset.LowPart */
curOffset.LowPart &= ~(2048-1);
curOffset.LowPart |= temp;
/* check if we've passed the dir's EOF */
if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength))
break;
-
+
/* see if we can use the bufferp we have now; compute in which
* page the current offset would be, and check whether that's
* the offset of the buffer we have. If not, get the buffer.
bufferp = NULL;
}
- code = buf_Get(scp, &thyper, reqp, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, 0, &bufferp);
if (code) {
/* if buf_Get() fails we do not have a buffer object to lock */
bufferp = NULL;
break;
}
cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
-
+
if (cm_HaveBuffer(scp, bufferp, 1)) {
lock_ReleaseWrite(&scp->rw);
break;
reqp);
lock_ReleaseWrite(&scp->rw);
lock_ObtainMutex(&bufferp->mx);
- if (code)
+ if (code)
break;
}
if (code) {
break;
}
} /* if (wrong buffer) ... */
-
+
/* now we have the buffer containing the entry we're interested
* in; copy it out if it represents a non-deleted entry.
*/
* dir listing stream.
*/
numDirChunks = cm_NameEntries(dep->name, NULL);
-
+
/* compute the offset of the cookie representing the next entry */
nextEntryCookie = curOffset.LowPart
+ (CM_DIR_CHUNKSIZE * numDirChunks);
if (dep->fid.vnode != 0) {
/* this is one of the entries to use: it is not deleted */
code = (*funcp)(scp, dep, parmp, &curOffset);
- if (code)
+ if (code)
break;
} /* if we're including this name */
-
+
nextEntry:
/* and adjust curOffset to be where the new cookie is */
thyper.HighPart = 0;
if (match != 0
&& sp->hasTilde
+ && cm_shortNames
&& !cm_Is8Dot3(matchName)) {
cm_Gen8Dot3NameInt(dep->name, &dep->fid, matchName, NULL);
return 0;
sp->found = 1;
- if (!sp->caseFold)
+ if (!sp->caseFold)
sp->ExactFound = 1;
if (!sp->caseFold || looking_for_short_name) {
inexact:
cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
return 0;
-}
+}
/* read the contents of a mount point into the appropriate string.
* 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)
{
- long code;
- cm_buf_t *bufp = NULL;
- osi_hyper_t thyper;
- int tlen;
+ long code = 0;
+
+ code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_FETCHDATA);
+ if (code)
+ return code;
+
+ if (scp->mountPointStringp[0] &&
+ scp->mpDataVersion == scp->dataVersion) {
+ code = 0;
+ goto done;
+ }
- if (scp->mountPointStringp[0])
- return 0;
-
#ifdef AFS_FREELANCE_CLIENT
/* File servers do not have data for freelance entries */
if (cm_freelanceEnabled &&
scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
scp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
- {
+ {
code = cm_FreelanceFetchMountPointString(scp);
- } else
-#endif /* AFS_FREELANCE_CLIENT */
+ } else
+#endif /* AFS_FREELANCE_CLIENT */
{
- /* otherwise, we have to read it in */
- lock_ReleaseWrite(&scp->rw);
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t offset;
+ afs_uint32 bytesRead = 0;
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(scp, &thyper, reqp, &bufp);
-
- lock_ObtainWrite(&scp->rw);
+ /* otherwise, we have to read it in */
+ offset.LowPart = offset.HighPart = 0;
+ code = cm_GetData(scp, &offset, temp, MOUNTPOINTLEN, &bytesRead, userp, reqp);
if (code)
- return code;
-
- while (1) {
- code = cm_SyncOp(scp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
- if (code)
- goto done;
-
- cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
-
- if (cm_HaveBuffer(scp, bufp, 0))
- break;
+ goto done;
- /* otherwise load buffer */
- code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
- if (code)
- goto done;
- }
- /* locked, has callback, has valid data in buffer */
- if ((tlen = scp->length.LowPart) > MOUNTPOINTLEN - 1)
- return CM_ERROR_TOOBIG;
- if (tlen <= 0) {
- code = CM_ERROR_INVAL;
+ /*
+ * scp->length is the actual length of the mount point string.
+ * It is current because cm_GetData merged the most up to date
+ * status info into scp and has not dropped the rwlock since.
+ */
+ if (scp->length.LowPart > MOUNTPOINTLEN - 1) {
+ code = CM_ERROR_TOOBIG;
goto done;
}
- /* someone else did the work while we were out */
- if (scp->mountPointStringp[0]) {
- code = 0;
+ if (scp->length.LowPart == 0) {
+ code = CM_ERROR_INVAL;
goto done;
}
- /* otherwise, copy out the link */
- memcpy(scp->mountPointStringp, bufp->datap, tlen);
+ /* convert the terminating dot to a NUL */
+ temp[scp->length.LowPart - 1] = 0;
+ memcpy(scp->mountPointStringp, temp, scp->length.LowPart);
+ scp->mpDataVersion = scp->dataVersion;
+ }
- /* now make it null-terminated. Note that the original contents of a
- * link that is a mount point is "#volname." where "." is there just to
- * be turned into a null. That is, we can trash the last char of the
- * link without damaging the vol name. This is a stupid convention,
- * but that's the protocol.
- */
- scp->mountPointStringp[tlen-1] = 0;
- code = 0;
+ done:
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_FETCHDATA);
- done:
- if (bufp)
- buf_Release(bufp);
- }
return code;
}
if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
tfid = scp->mountRootFid;
lock_ReleaseWrite(&scp->rw);
- code = cm_GetSCache(&tfid, outScpp, userp, reqp);
+ code = cm_GetSCache(&tfid, NULL, outScpp, userp, reqp);
lock_ObtainWrite(&scp->rw);
return code;
}
/* now look up the cell */
lock_ReleaseWrite(&scp->rw);
- cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
+ cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE|CM_FLAG_NOPROBE);
lock_ObtainWrite(&scp->rw);
} else {
/* normal mt pt */
volNamep = cm_FsStrDup(mpNamep + 1);
#ifdef AFS_FREELANCE_CLIENT
- /*
+ /*
* Mount points in the Freelance cell should default
* to the workstation cell.
*/
if (cm_freelanceEnabled &&
scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
scp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
- {
+ {
fschar_t rootCellName[256]="";
cm_GetRootCellName(rootCellName);
cellp = cm_GetCell(rootCellName, 0);
- } else
-#endif /* AFS_FREELANCE_CLIENT */
+ } else
+#endif /* AFS_FREELANCE_CLIENT */
cellp = cm_FindCellByID(scp->fid.cell, 0);
}
if (targetType == BACKVOL
&& (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
== CM_SCACHEFLAG_RO) {
- code = CM_ERROR_NOSUCHVOLUME;
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
goto done;
}
/* now we need to get the volume */
lock_ReleaseWrite(&scp->rw);
if (cm_VolNameIsID(volNamep)) {
- code = cm_FindVolumeByID(cellp, atoi(volNamep), userp, reqp,
+ code = cm_FindVolumeByID(cellp, atoi(volNamep), userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
} else {
- code = cm_FindVolumeByName(cellp, volNamep, userp, reqp,
+ code = cm_FindVolumeByName(cellp, volNamep, userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
}
lock_ObtainWrite(&scp->rw);
-
+
if (code == 0) {
afs_uint32 cell, volume;
cm_vol_state_t *statep;
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 &&
+ if (cm_followBackupPath &&
volp->vol[BACKVOL].ID != 0 &&
(dscp->flags & (CM_SCACHEFLAG_RO|CM_SCACHEFLAG_PURERO)) == CM_SCACHEFLAG_RO &&
(targetType == RWVOL || targetType == ROVOL && volp->vol[ROVOL].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 targetType '#' mount point, use
* the read-only, otherwise use the one specified.
*/
- else if (mtType == '#' && targetType == RWVOL &&
- (scp->flags & CM_SCACHEFLAG_PURERO) &&
+ else if (mtType == '#' && targetType == RWVOL &&
+ (scp->flags & CM_SCACHEFLAG_PURERO) &&
volp->vol[ROVOL].ID != 0) {
targetType = ROVOL;
}
tfid = scp->mountRootFid;
lock_ReleaseWrite(&scp->rw);
- code = cm_GetSCache(&tfid, outScpp, userp, reqp);
+ code = cm_GetSCache(&tfid, NULL, outScpp, userp, reqp);
lock_ObtainWrite(&scp->rw);
}
if (volNamep)
free(volNamep);
return code;
-}
+}
long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
cm_req_t *reqp, cm_scache_t **outScpp)
rock.found = TRUE;
goto haveFid;
}
-
+
code = CM_ERROR_BPLUS_NOMATCH;
goto notfound;
}
* that we stopped early, probably because we found the entry we're
* looking for. Any other non-zero code is an error.
*/
- if (code && code != CM_ERROR_STOPNOW && code != CM_ERROR_BPLUS_NOMATCH) {
- /* if the cm_scache_t we are searching in is not a directory
- * we must return path not found because the error
+ if (code && code != CM_ERROR_STOPNOW) {
+ /* if the cm_scache_t we are searching in is not a directory
+ * we must return path not found because the error
* is to describe the final component not an intermediary
*/
if (code == CM_ERROR_NOTDIR) {
notfound:
getroot = (dscp==cm_data.rootSCachep) ;
if (!rock.found) {
- if (!cm_freelanceEnabled || !getroot) {
+ if (!(cm_freelanceEnabled && cm_freelanceDiscovery) || !getroot) {
if (flags & CM_FLAG_CHECKPATH)
code = CM_ERROR_NOSUCHPATH;
else
!cm_ClientStrChr(cnamep, '%') &&
cm_ClientStrCmpI(cnamep, _C("srvsvc")) &&
cm_ClientStrCmpI(cnamep, _C("wkssvc")) &&
- cm_ClientStrCmpI(cnamep, _C("ipc$")))
+ cm_ClientStrCmpI(cnamep, _C("ipc$")))
{
/* nonexistent dir on freelance root, so add it */
fschar_t fullname[CELL_MAXNAMELEN + 1] = "."; /* +1 so that when we skip the . the size is still CELL_MAXNAMELEN */
int found = 0;
int retry = 0;
- osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %S",
+ osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %S",
osi_LogSaveClientString(afsd_logp,cnamep));
- /*
+ /*
* 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
+ * symlink or mount point in the Freelance directory, do not add the
* new value automatically.
*/
if (cnamep[0] == '.') {
if (cm_GetCell_Gen(&fnamep[1], &fullname[1], CM_FLAG_CREATE)) {
found = 1;
- code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
+ code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell", 1, &rock.fid);
if ( cm_FsStrCmpI(&fnamep[1], &fullname[1])) {
/*
* Do not permit symlinks that are one of:
} else {
if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
found = 1;
- code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
+ code = cm_FreelanceAddMount(fullname, fullname, "root.cell", 0, &rock.fid);
if ( cm_FsStrCmpI(fnamep, fullname)) {
/*
* Do not permit symlinks that are one of:
haveFid:
if ( !tscp ) /* we did not find it in the dnlc */
{
- dnlcHit = 0;
- code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
- if (code)
+ dnlcHit = 0;
+ code = cm_GetSCache(&rock.fid, &dscp->fid, &tscp, userp, reqp);
+ if (code)
goto done;
}
/* tscp is now held */
lock_ObtainWrite(&tscp->rw);
- code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
- CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
- if (code) {
- lock_ReleaseWrite(&tscp->rw);
- cm_ReleaseSCache(tscp);
- goto done;
+
+ /*
+ * Do not get status if we do not already have a callback or know the type.
+ * The process of reading the mount point string will obtain status information
+ * in a single RPC. No reason to add a second round trip.
+ *
+ * If we do have a callback, use cm_SyncOp to get status in case the
+ * current cm_user_t is not the same as the one that obtained the
+ * mount point string contents.
+ */
+ if (cm_HaveCallback(tscp) || tscp->fileType == CM_SCACHETYPE_UNKNOWN) {
+ code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ goto done;
+ }
+ cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
}
- cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
/* tscp is now locked */
if (!(flags & CM_FLAG_NOMOUNTCHASE)
lock_ObtainRead(&dscp->rw);
if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 ) {
/* TODO: reuse nnamep from above */
- if (nnamep)
+ if (nnamep)
free(nnamep);
nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
if (nnamep)
return code;
}
-int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
+int cm_ExpandSysName(cm_req_t * reqp, clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
{
clientchar_t *tp;
int prefixCount;
+#ifdef _WIN64
+ int use_sysname64 = 0;
+
+ if (cm_sysName64Count > 0 && reqp && !(reqp->flags & CM_REQ_WOW64) && (reqp->flags & CM_REQ_SOURCE_REDIR))
+ use_sysname64 = 1;
+#endif
tp = cm_ClientStrRChr(inp, '@');
- if (tp == NULL)
+ if (tp == NULL)
return 0; /* no @sys */
- if (cm_ClientStrCmp(tp, _C("@sys")) != 0)
+ if (cm_ClientStrCmp(tp, _C("@sys")) != 0)
return 0; /* no @sys */
/* caller just wants to know if this is a valid @sys type of name */
- if (outp == NULL)
+ if (outp == NULL)
return 1;
+#ifdef _WIN64
+ if (use_sysname64 && index >= cm_sysName64Count)
+ return -1;
+ else
+#endif
if (index >= cm_sysNameCount)
return -1;
prefixCount = (int)(tp - inp);
cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount); /* copy out "a." from "a.@sys" */
- outp[prefixCount] = 0; /* null terminate the "a." */
- cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
+ outp[prefixCount] = 0; /* null terminate the "a." */
+#ifdef _WIN64
+ if (use_sysname64)
+ cm_ClientStrCat(outp, outSizeCch, cm_sysName64List[index]);
+ else
+#endif
+ cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);
+
return 1;
-}
+}
long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
cm_req_t *reqp, cm_scache_t ** outScpp)
cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
- code = cm_GetSCache(&fid, outScpp, userp, reqp);
+ code = cm_GetSCache(&fid, NULL, outScpp, userp, reqp);
_exit_cleanup:
if (fnamep)
return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
}
- if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
+ if (cm_ExpandSysName(reqp, namep, NULL, 0, 0) > 0) {
for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
- code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
+ code = cm_ExpandSysName(reqp, namep, tname, lengthof(tname), sysNameIndex);
if (code > 0) {
code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
#ifdef DEBUG_REFCOUNT
\param[in] userp cm_user_t for the request.
\param[in] reqp Request tracker.
-
+
*/
long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
cm_user_t *userp, cm_req_t *reqp)
cm_dirOp_t dirop;
cm_scache_t *scp = NULL;
int free_fnamep = FALSE;
+ int invalidate = 0;
memset(&volSync, 0, sizeof(volSync));
code = cm_FreelanceRemoveMount(fnamep);
goto done;
}
-#endif
+#endif
code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
if (code)
}
/* make the RPC */
+ InterlockedIncrement(&dscp->activeRPCs);
+
afsFid.Volume = dscp->fid.volume;
afsFid.Vnode = dscp->fid.vnode;
afsFid.Unique = dscp->fid.unique;
&newDirStatus, &volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, reqp, &dscp->fid, NULL, 1, &newDirStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
}
lock_ObtainWrite(&dscp->rw);
cm_dnlcRemove(dscp, cnamep);
- cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- } else if (code == CM_ERROR_NOSUCHFILE) {
- /* windows would not have allowed the request to delete the file
- * if it did not believe the file existed. therefore, we must
- * have an inconsistent view of the world.
- */
- dscp->cbServerp = NULL;
- }
- lock_ReleaseWrite(&dscp->rw);
-
- if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
- cm_DirDeleteEntry(&dirop, fnamep);
+ code = cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ invalidate = 1;
+ if (cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirDeleteEntry(&dirop, fnamep);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&dirop, cnamep);
+ cm_BPlusDirDeleteEntry(&dirop, cnamep);
#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
+ } else {
+ InterlockedDecrement(&scp->activeRPCs);
+ if (code == CM_ERROR_NOSUCHFILE) {
+ /* windows would not have allowed the request to delete the file
+ * if it did not believe the file existed. therefore, we must
+ * have an inconsistent view of the world.
+ */
+ dscp->cbServerp = NULL;
+ }
}
+
+ cm_SyncOpDone(dscp, NULL, sflags);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
+ if (invalidate && RDR_Initialized &&
+ scp->fileType != CM_SCACHETYPE_FILE && scp->fileType != CM_SCACHETYPE_DIRECTORY)
+ RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+ dscp->fid.unique, dscp->fid.hash,
+ dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
+
if (scp) {
- cm_ReleaseSCache(scp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
- if (--scp->linkCount == 0)
- scp->flags |= CM_SCACHEFLAG_DELETED;
+ if (--scp->linkCount == 0) {
+ _InterlockedOr(&scp->flags, CM_SCACHEFLAG_DELETED);
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_AdjustScacheLRU(scp);
+ lock_ReleaseWrite(&cm_scacheLock);
+ }
cm_DiscardSCache(scp);
lock_ReleaseWrite(&scp->rw);
+ if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR))
+ RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+ scp->fid.unique, scp->fid.hash,
+ scp->fileType, AFS_INVALIDATE_DELETED);
}
+ cm_ReleaseSCache(scp);
}
done:
*/
long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
{
- long code;
- cm_buf_t *bufp;
- long temp;
- osi_hyper_t thyper;
+ long code = 0;
lock_AssertWrite(&linkScp->rw);
- if (!linkScp->mountPointStringp[0]) {
-
+ if (!linkScp->mountPointStringp[0] ||
+ linkScp->mpDataVersion != linkScp->dataVersion) {
+
#ifdef AFS_FREELANCE_CLIENT
/* File servers do not have data for freelance entries */
if (cm_freelanceEnabled &&
linkScp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
{
code = cm_FreelanceFetchMountPointString(linkScp);
- } else
-#endif /* AFS_FREELANCE_CLIENT */
+ } else
+#endif /* AFS_FREELANCE_CLIENT */
{
- /* read the link data from the file server*/
- lock_ReleaseWrite(&linkScp->rw);
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(linkScp, &thyper, reqp, &bufp);
- lock_ObtainWrite(&linkScp->rw);
- if (code)
- return code;
- while (1) {
- code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
- if (code) {
- buf_Release(bufp);
- return code;
- }
- cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
-
- if (cm_HaveBuffer(linkScp, bufp, 0))
- break;
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t offset;
+ afs_uint32 bytesRead = 0;
- code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
- if (code) {
- buf_Release(bufp);
- return code;
- }
- } /* while loop to get the data */
+ /* read the link data from the file server */
+ offset.LowPart = offset.HighPart = 0;
+ code = cm_GetData(linkScp, &offset, temp, MOUNTPOINTLEN, &bytesRead, userp, reqp);
+ if (code)
+ return code;
- /* now if we still have no link read in,
- * copy the data from the buffer */
- if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
- buf_Release(bufp);
+ /*
+ * linkScp->length is the actual length of the symlink target string.
+ * It is current because cm_GetData merged the most up to date
+ * status info into scp and has not dropped the rwlock since.
+ */
+ if (linkScp->length.LowPart > MOUNTPOINTLEN - 1)
return CM_ERROR_TOOBIG;
- }
+ if (linkScp->length.LowPart == 0)
+ return CM_ERROR_INVAL;
- /* otherwise, it fits; make sure it is still null (could have
- * lost race with someone else referencing this link above),
- * and if so, copy in the data.
- */
- if (!linkScp->mountPointStringp[0]) {
- strncpy(linkScp->mountPointStringp, bufp->datap, temp);
- linkScp->mountPointStringp[temp] = 0; /* null terminate */
- }
- buf_Release(bufp);
+ /* make sure we are NUL terminated */
+ temp[linkScp->length.LowPart] = 0;
+ memcpy(linkScp->mountPointStringp, temp, linkScp->length.LowPart + 1);
+ linkScp->mpDataVersion = linkScp->dataVersion;
}
-
+
if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- } /* don't have sym link contents cached */
+ } /* don't have symlink contents cached */
- return 0;
-}
+ return code;
+}
/* called with a held vnode and a path suffix, with the held vnode being a
* symbolic link. Our goal is to generate a new path to interpret, and return
*newSpaceBufferp = NULL;
lock_ObtainWrite(&linkScp->rw);
+ /*
+ * Do not get status if we do not already have a callback.
+ * The process of reading the symlink string will obtain status information
+ * in a single RPC. No reason to add a second round trip.
+ *
+ * If we do have a callback, use cm_SyncOp to get status in case the
+ * current cm_user_t is not the same as the one that obtained the
+ * symlink string contents.
+ */
+ if (cm_HaveCallback(linkScp)) {
+ code = cm_SyncOp(linkScp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseWrite(&linkScp->rw);
+ cm_ReleaseSCache(linkScp);
+ goto done;
+ }
+ cm_SyncOpDone(linkScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ }
code = cm_HandleLink(linkScp, userp, reqp);
if (code)
goto done;
*newRootScpp = cm_RootSCachep(userp, reqp);
cm_HoldSCache(*newRootScpp);
} else if (linkp[0] == '\\' && linkp[1] == '\\') {
- if (!strnicmp(&linkp[2], cm_NetbiosName, (len = (long)strlen(cm_NetbiosName))))
+ if (!strnicmp(&linkp[2], cm_NetbiosName, (len = (long)strlen(cm_NetbiosName))))
{
char * p = &linkp[len + 3];
if (strnicmp(p, "all", 3) == 0)
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
code = CM_ERROR_PATH_NOT_COVERED;
} else if (*linkp == '\\' || *linkp == '/') {
-#if 0
+#if 0
/* formerly, this was considered to be from the AFS root,
* but this seems to create problems. instead, we will just
* reject the link */
*newRootScpp = cm_RootSCachep(userp, reqp);
cm_HoldSCache(*newRootScpp);
#else
- /* we still copy the link data into the response so that
+ /* we still copy the link data into the response so that
* the user can see what the link points to
*/
linkScp->fileType = CM_SCACHETYPE_INVALID;
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
code = CM_ERROR_NOSUCHPATH;
-#endif
+#endif
} else {
/* a relative link */
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
} else {
code = CM_ERROR_NOSUCHPATH;
}
- }
+ }
if (code != 0) {
cm_FreeSpace(tsp);
#ifdef DEBUG_REFCOUNT
long cm_NameIDbg(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
- cm_scache_t **outScpp,
+ cm_scache_t **outScpp,
char * file, long line)
#else
long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
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);
osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
- rootSCachep, pathp ? pathp : L"<NULL>", tidPathp ? tidPathp : L"<NULL>",
+ rootSCachep, pathp ? pathp : L"<NULL>", tidPathp ? tidPathp : L"<NULL>",
flags);
#endif
/* map Unix slashes into DOS ones so we can interpret Unix
* symlinks properly
*/
- if (tc == '/')
+ if (tc == '/')
tc = '\\';
if (!haveComponent) {
*/
*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 (tscp == cm_RootSCachep(userp, reqp)) {
+ code = cm_Lookup(tscp, component, CM_FLAG_CHECKPATH, userp, reqp, &nscp);
+
+ if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE ||
+ code == CM_ERROR_BPLUS_NOMATCH) &&
+ tscp == cm_data.rootSCachep) {
+
+ clientchar_t volref[AFSPATHMAX];
+
+ if (wcschr(component, '%') != NULL || wcschr(component, '#') != NULL) {
+ /*
+ * A volume reference: <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
+ */
+ cm_ClientStrCpyN(volref, AFSPATHMAX, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
+ cm_ClientStrCat(volref, AFSPATHMAX, component);
+
+ code = cm_EvaluateVolumeReference(volref, CM_FLAG_CHECKPATH, userp, reqp, &nscp);
+ }
+#ifdef AFS_FREELANCE_CLIENT
+ else if (tscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && tscp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
+ tscp->fid.vnode == 1 && tscp->fid.unique == 1) {
+ /*
+ * If this is the Freelance volume root directory then treat unrecognized
+ * names as cell names and attempt to find the appropriate "root.cell".
+ */
+ cm_ClientStrCpyN(volref, AFSPATHMAX, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
+ if (component[0] == L'.') {
+ cm_ClientStrCat(volref, AFSPATHMAX, &component[1]);
+ cm_ClientStrCatN(volref, AFSPATHMAX, L"%", sizeof(WCHAR));
+ } else {
+ cm_ClientStrCat(volref, AFSPATHMAX, component);
+ cm_ClientStrCatN(volref, AFSPATHMAX, L"#", sizeof(WCHAR));
+ }
+ cm_ClientStrCatN(volref, AFSPATHMAX, L"root.cell", 9 * sizeof(WCHAR));
+
+ code = cm_EvaluateVolumeReference(volref, CM_FLAG_CHECKPATH, userp, reqp, &nscp);
+ }
+#endif
+ }
+ } else {
+ if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
+ extraFlag = CM_FLAG_NOMOUNTCHASE;
+ code = cm_Lookup(tscp, component,
+ flags | extraFlag,
+ userp, reqp, &nscp);
+ }
if (code == 0) {
if (!cm_ClientStrCmp(component,_C("..")) ||
!cm_ClientStrCmp(component,_C("."))) {
- /*
+ /*
* 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
cm_ReleaseSCache(nscp);
nscp = NULL;
break;
- }
+ }
fids[fid_count++] = nscp->fid;
}
}
cm_ReleaseSCache(tscp);
if (dirScp)
cm_ReleaseSCache(dirScp);
- if (psp)
+ if (psp)
cm_FreeSpace(psp);
- if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
+ 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;
cm_ReleaseSCache(dirScp);
dirScp = NULL;
}
- if (psp)
+ 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 (tc == 0)
restp = _C("");
- else
+ else
restp = tp;
{
* space allocation and tracking the
* vnode reference counts.
*/
- if (psp)
+ if (psp)
cm_FreeSpace(psp);
psp = tempsp;
tp = psp->wdata;
dirScp = NULL;
}
} /* end of a component */
- else
+ else
*cp++ = tc;
} /* we have a component */
} /* big while loop over all components */
/* already held */
if (dirScp)
cm_ReleaseSCache(dirScp);
- if (psp)
+ if (psp)
cm_FreeSpace(psp);
- if (code == 0)
+ if (code == 0)
*outScpp = tscp;
else if (tscp)
cm_ReleaseSCache(tscp);
osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
- if (code)
+ if (code)
return code;
/* now, if newRootScp is NULL, we're really being told that the symlink
if (tscp) {
if (lock_TryWrite(&tscp->rw)) {
/* we have an entry that we can look at */
- if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+ if (!cm_EAccesFindEntry(bsp->userp, &tscp->fid) && 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.
// to be bulkstat-ed, instead, we call getSCache directly and under
// getSCache, it is handled specially.
if ( cm_freelanceEnabled &&
- tfid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ tfid.cell==AFS_FAKE_ROOT_CELL_ID &&
tfid.volume==AFS_FAKE_ROOT_VOL_ID &&
!(tfid.vnode==0x1 && tfid.unique==0x1) )
- {
+ {
osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
- return cm_GetSCache(&tfid, &tscp, NULL, NULL);
+ return cm_GetSCache(&tfid, NULL, &tscp, NULL, NULL);
}
#endif /* AFS_FREELANCE_CLIENT */
bsp->fids[i].Vnode = tfid.vnode;
bsp->fids[i].Unique = tfid.unique;
return 0;
-}
+}
afs_int32
cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_req_t *reqp)
long filex;
AFSVolSync volSync;
cm_callbackRequest_t cbReq;
+ int lostRace;
long filesThisCall;
long i;
long j;
*/
for (filex = 0; filex < bbp->counter; filex += filesThisCall) {
filesThisCall = bbp->counter - filex;
- if (filesThisCall > AFSCBMAX)
+ if (filesThisCall > AFSCBMAX)
filesThisCall = AFSCBMAX;
fidStruct.AFSCBFids_len = filesThisCall;
inlinebulk = 0;
code = cm_ConnFromFID(&tfid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
rxconnp = cm_GetRxConn(connp);
- if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
+ if (SERVERHASINLINEBULK(connp)) {
code = RXAFS_InlineBulkStatus(rxconnp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
if (code == RXGEN_OPCODE) {
- cm_SetServerNoInlineBulk(connp->serverp, 0);
+ SET_SERVERHASNOINLINEBULK(connp);
} else {
inlinebulk = 1;
}
}
if (!inlinebulk) {
+ /*
+ * It is important to note that RXAFS_BulkStatus is quite braindead.
+ * The AFS 3.6 file server implementation returns arrays that are
+ * sized to hold responses for all of the requested FIDs but it only
+ * populates their contents up to the point where it detects an error.
+ * Unfortunately, it does inform the caller which entries were filled
+ * and which were not. The caller has no ability to determine which
+ * FID the RPC return code applies to or which of the FIDs valid status
+ * info and callbacks have been issued for. As a result, when an
+ * error is returned, none of the data received can be trusted.
+ */
code = RXAFS_BulkStatus(rxconnp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
}
code = (&bbp->stats[0])->errorCode;
}
}
- } while (cm_Analyze(connp, userp, reqp, &tfid, &volSync, NULL, &cbReq, code));
+ } while (cm_Analyze(connp, userp, reqp, &tfid, NULL, 0, &bbp->stats[0], &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
/*
if (code) {
osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x",
inlinebulk ? "Inline" : "", code);
+ if (!inlinebulk) {
+ /*
+ * Since an error occurred and it is impossible to determine
+ * the context in which the returned error code should be
+ * interpreted, we return the CM_ERROR_BULKSTAT_FAILURE error
+ * which indicates that Bulk Stat cannot be used for the
+ * current request. The caller should fallback to using
+ * individual RXAFS_FetchStatus calls.
+ */
+ code = CM_ERROR_BULKSTAT_FAILURE;
+ }
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
break;
}
if (inlinebulk && (&bbp->stats[j])->errorCode) {
cm_req_t treq = *reqp;
- cm_Analyze(NULL, userp, &treq, &tfid, &volSync, NULL, &cbReq, (&bbp->stats[j])->errorCode);
+ cm_Analyze(NULL, userp, &treq, &tfid, NULL, 0, &bbp->stats[j], &volSync,
+ NULL, &cbReq, (&bbp->stats[j])->errorCode);
+ switch ((&bbp->stats[j])->errorCode) {
+ case EACCES:
+ case UAEACCES:
+ case EPERM:
+ case UAEPERM:
+ cm_EAccesAddEntry(userp, &tfid, &dscp->fid);
+ }
} else {
- code = cm_GetSCache(&tfid, &scp, userp, reqp);
+ code = cm_GetSCache(&tfid, &dscp->fid, &scp, userp, reqp);
if (code != 0)
continue;
if ((scp->cbServerp == NULL &&
!(scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESTORING))) ||
(scp->flags & CM_SCACHEFLAG_PURERO) ||
- (scp->flags & CM_SCACHEFLAG_EACCESS))
+ cm_EAccesFindEntry(userp, &scp->fid))
{
lock_ConvertRToW(&scp->rw);
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &bbp->callbacks[j],
- &volSync,
- CM_CALLBACK_MAINTAINCOUNT);
- cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &bbp->callbacks[j],
+ &volSync,
+ CM_CALLBACK_MAINTAINCOUNT|CM_CALLBACK_BULKSTAT);
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
+ code = cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, CM_MERGEFLAG_BULKSTAT);
+ }
lock_ReleaseWrite(&scp->rw);
} else {
lock_ReleaseRead(&scp->rw);
bbp = malloc(sizeof(cm_bulkStat_t));
memset(bbp, 0, sizeof(cm_bulkStat_t));
+ bbp->userp = userp;
bbp->bufOffset = *offsetp;
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&dscp->rw);
free(bbp);
return 0;
-}
+}
void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
{
}
}
statusp->Mask = mask;
-}
+}
+
+int
+cm_IsSpaceAvailable(cm_fid_t * fidp, osi_hyper_t *sizep, cm_user_t *userp, cm_req_t *reqp)
+{
+ int spaceAvail = 1;
+ afs_uint32 code;
+ cm_conn_t *connp;
+ struct rx_connection * rxconnp;
+ AFSFetchVolumeStatus volStat;
+ cm_volume_t *volp = NULL;
+ afs_uint32 volType;
+ char *Name;
+ char *OfflineMsg;
+ char *MOTD;
+ char volName[32]="(unknown)";
+ char offLineMsg[256]="server temporarily inaccessible";
+ char motd[256]="server temporarily inaccessible";
+ osi_hyper_t freespace;
+ cm_fid_t vfid;
+ cm_scache_t *vscp;
+
+ if (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
+ fidp->volume==AFS_FAKE_ROOT_VOL_ID)
+ {
+ goto _done;
+ }
+
+ volp = cm_FindVolumeByFID(fidp, userp, reqp);
+ if (!volp) {
+ spaceAvail = 0;
+ goto _done;
+ }
+ volType = cm_VolumeType(volp, fidp->volume);
+ if (volType == ROVOL || volType == BACKVOL) {
+ spaceAvail = 0;
+ goto _done;
+ }
+
+ cm_SetFid(&vfid, fidp->cell, fidp->volume, 1, 1);
+ code = cm_GetSCache(&vfid, NULL, &vscp, userp, reqp);
+ if (code == 0) {
+ lock_ObtainWrite(&vscp->rw);
+ code = cm_SyncOp(vscp, NULL, userp, reqp, PRSFS_READ,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&vscp->rw);
+ if (code == 0) {
+ Name = volName;
+ OfflineMsg = offLineMsg;
+ MOTD = motd;
+
+ do {
+ code = cm_ConnFromFID(&vfid, userp, reqp, &connp);
+ if (code) continue;
+
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(rxconnp, fidp->volume,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(rxconnp);
+
+ } while (cm_Analyze(connp, userp, reqp, &vfid, NULL, 0, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, reqp);
+ }
+
+ lock_ObtainWrite(&vscp->rw);
+ cm_SyncOpDone(vscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&vscp->rw);
+ cm_ReleaseSCache(vscp);
+ }
+
+ if (code == 0) {
+ if (volStat.MaxQuota) {
+ freespace.QuadPart = 1024 * (afs_int64)min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
+ } else {
+ freespace.QuadPart = 1024 * (afs_int64)volStat.PartBlocksAvail;
+ }
+ spaceAvail = LargeIntegerGreaterThanOrEqualTo(freespace, *sizep);
+ }
+ /* the rpc failed, assume there is space and we can fail it later. */
+
+ _done:
+ if (volp)
+ cm_PutVolume(volp);
+
+ return spaceAvail;
+}
/* set the file size, and make sure that all relevant buffers have been
* truncated. Ensure that any partially truncated buffers have been zeroed
{
long code;
int shrinking;
+ int available;
/* start by locking out buffer creation */
lock_ObtainWrite(&scp->bufCreateLock);
lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code)
+ if (code)
goto done;
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
}
- if (code)
+ if (code)
goto done;
if (LargeIntegerLessThan(*sizep, scp->length)) {
* than where we're truncating the file, set truncPos to this
* new value.
*/
- if (!shrinking)
+ if (!shrinking) {
+ cm_SyncOpDone(scp, NULL,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
goto startover;
+ }
if (!(scp->mask & CM_SCACHEMASK_TRUNCPOS)
|| LargeIntegerLessThan(*sizep, scp->length)) {
/* set trunc pos */
scp->mask |= CM_SCACHEMASK_LENGTH;
}
else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
- /* really extending the file */
- scp->length = *sizep;
- scp->mask |= CM_SCACHEMASK_LENGTH;
+ /*
+ * Really extending the file so must check to see if we
+ * have sufficient quota. cm_IsSpaceAvailable() obtains
+ * the cm_scache.rw lock on the volume root directory.
+ * vnode 1 < scp->fid.vnode therefore calling cm_IsSpaceAvailable
+ * while holding scp->rw is a lock order violation.
+ * Dropping it is ok because we are holding scp->bufCreateLock
+ * which prevents the size of the file from changing.
+ */
+ afs_uint64 nextChunk = scp->length.QuadPart;
+
+ nextChunk -= (nextChunk & 0xFFFFF);
+ nextChunk += 0x100000;
+
+ if (sizep->QuadPart > nextChunk) {
+ lock_ReleaseWrite(&scp->rw);
+ available = cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp);
+ lock_ObtainWrite(&scp->rw);
+ } else {
+ /*
+ * The file server permits 1MB quota overruns so only check
+ * when the file size increases by at least that much.
+ */
+ available = 1;
+ }
+ if (available) {
+ scp->length = *sizep;
+ scp->mask |= CM_SCACHEMASK_LENGTH;
+ } else {
+ code = CM_ERROR_SPACE;
+ goto syncopdone;
+ }
}
/* done successfully */
code = 0;
- cm_SyncOpDone(scp, NULL,
+ syncopdone:
+ cm_SyncOpDone(scp, NULL,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
lock_ReleaseRead(&scp->rw);
/* now make the RPC */
+ InterlockedIncrement(&scp->activeRPCs);
+
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
do {
code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
rxconnp = cm_GetRxConn(connp);
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &scp->fid, &volSync, NULL, NULL, code));
+ &scp->fid, NULL, 1, &afsOutStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
osi_Log0(afsd_logp, "CALL StoreStatus SUCCESS");
lock_ObtainWrite(&scp->rw);
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
if (code == 0)
- cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp, reqp,
- CM_MERGEFLAG_FORCE|CM_MERGEFLAG_STOREDATA);
-
- /* if we're changing the mode bits, discard the ACL cache,
+ code = cm_MergeStatus( NULL, scp, &afsOutStatus, &volSync, userp, reqp,
+ CM_MERGEFLAG_FORCE|CM_MERGEFLAG_STOREDATA);
+ else
+ InterlockedDecrement(&scp->activeRPCs);
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
+
+ /* if we're changing the mode bits, discard the ACL cache,
* since we changed the mode bits.
*/
- if (afsInStatus.Mask & AFS_SETMODE)
+ if (afsInStatus.Mask & AFS_SETMODE)
cm_FreeAllACLEnts(scp);
lock_ReleaseWrite(&scp->rw);
return code;
-}
+}
long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
-{
+{
cm_conn_t *connp;
long code;
AFSFid dirAFSFid;
cm_fid_t newFid;
cm_scache_t *scp = NULL;
int didEnd;
+ int lostRace;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newFileStatus;
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
- if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
dirAFSFid.Volume = dscp->fid.volume;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, &cbReq, code));
+ &dscp->fid, NULL, 1, &updatedDirStatus, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
-
+
if (code)
osi_Log1(afsd_logp, "CALL CreateFile FAILURE, code 0x%x", code);
else
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, reqp, CM_MERGEFLAG_DIROP);
+ code = cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirCreateEntry(&dirop, fnamep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
- /* now try to create the file's entry, too, but be careful to
+ /* 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
* out any requests during the file's creation, we may have pretty old
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &newFileCallback, &volSync, 0);
- cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
- userp, reqp, 0);
- didEnd = 1;
- }
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &newFileCallback, &volSync, 0);
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
+ code = cm_MergeStatus( dscp, scp, &newFileStatus, &volSync,
+ userp, reqp, 0);
+ }
+ didEnd = 1;
+ }
lock_ReleaseWrite(&scp->rw);
}
}
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
- if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
- cm_DirCreateEntry(&dirop, fnamep, &newFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
-#endif
- }
cm_EndDirOp(&dirop);
if (fnamep)
cm_ReleaseSCache(scp);
}
return code;
-}
+}
/*
* locked if TRUE means write-locked
if (locked)
lock_ReleaseWrite(&scp->rw);
+
+ osi_Log2(afsd_logp, "cm_FSync scp 0x%p userp 0x%p", scp, userp);
+
code = buf_CleanVnode(scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
cm_fid_t newFid;
cm_scache_t *scp = NULL;
int didEnd;
+ int lostRace;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newDirStatus;
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
- if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
dirAFSFid.Volume = dscp->fid.volume;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, &cbReq, code));
+ &dscp->fid, NULL, 1, &updatedDirStatus, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
-
+
if (code)
osi_Log1(afsd_logp, "CALL MakeDir FAILURE, code 0x%x", code);
else
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, reqp, CM_MERGEFLAG_DIROP);
+ code = cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
+ cm_DirCreateEntry(&dirop, fnamep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ lock_ObtainWrite(&dscp->rw);
+ }
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
- /* now try to create the new dir's entry, too, but be careful to
+ /* 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
* out any requests during the file's creation, we may have pretty old
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &newDirCallback, &volSync, 0);
- cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
- userp, reqp, 0);
- didEnd = 1;
+ lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
+ &newDirCallback, &volSync, 0);
+ if (!lostRace) {
+ InterlockedIncrement(&scp->activeRPCs);
+ code = cm_MergeStatus( dscp, scp, &newDirStatus, &volSync,
+ userp, reqp, 0);
+ }
+ didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
}
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
- if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
- cm_DirCreateEntry(&dirop, fnamep, &newFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
-#endif
- }
cm_EndDirOp(&dirop);
free(fnamep);
/* and return error code */
return code;
-}
+}
long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long flags,
cm_user_t *userp, cm_req_t *reqp)
struct rx_connection * rxconnp;
cm_dirOp_t dirop;
fschar_t * fnamep = NULL;
+ int invalidate = 0;
memset(&volSync, 0, sizeof(volSync));
fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
rx_PutConnection(rxconnp);
osi_Log1(afsd_logp," RXAFS_Link returns 0x%x", code);
- } while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, reqp, &dscp->fid, NULL, 1, &updatedDirStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
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, reqp, CM_MERGEFLAG_DIROP);
- }
- lock_ReleaseWrite(&dscp->rw);
+ code = cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ invalidate = 1;
- if (code == 0) {
if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
cm_DirCreateEntry(&dirop, fnamep, &sscp->fid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&dirop, cnamep, &sscp->fid);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
+ if (invalidate && RDR_Initialized)
+ RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+ dscp->fid.unique, dscp->fid.hash,
+ dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
+
/* Update the linked object status */
if (code == 0) {
lock_ObtainWrite(&sscp->rw);
- cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
+ InterlockedIncrement(&sscp->activeRPCs);
+ code = cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
lock_ReleaseWrite(&sscp->rw);
}
}
long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, long flags,
- cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
+ cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp)
{
cm_conn_t *connp;
long code;
cm_dirOp_t dirop;
fschar_t *fnamep = NULL;
+ if (scpp)
+ *scpp = NULL;
+
/* Check for RO volume */
if (dscp->flags & CM_SCACHEFLAG_RO)
return CM_ERROR_READONLY;
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
dirAFSFid.Volume = dscp->fid.volume;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ &dscp->fid, NULL, 1, &updatedDirStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
-
+
if (code)
osi_Log1(afsd_logp, "CALL Symlink FAILURE, code 0x%x", code);
else
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, reqp, CM_MERGEFLAG_DIROP);
- }
- lock_ReleaseWrite(&dscp->rw);
-
if (code == 0) {
+ code = cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
if (cm_CheckDirOpForSingleChange(&dirop)) {
+ lock_ReleaseWrite(&dscp->rw);
cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
cm_DirCreateEntry(&dirop, fnamep, &newFid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
- /* now try to create the new dir's entry, too, but be careful to
+ /* 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
* out any requests during the file's creation, we may have pretty old
* info.
*/
if (code == 0) {
- cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
- code = cm_GetSCache(&newFid, &scp, userp, reqp);
+ code = cm_GetSCache(&newFid, &dscp->fid, &scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
- cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
- userp, reqp, 0);
- }
+ InterlockedIncrement(&scp->activeRPCs);
+ code = cm_MergeStatus( dscp, scp, &newLinkStatus, &volSync,
+ userp, reqp, 0);
+ }
lock_ReleaseWrite(&scp->rw);
- cm_ReleaseSCache(scp);
+
+ if (scpp) {
+ *scpp = scp;
+ } else {
+ cm_ReleaseSCache(scp);
+ }
}
}
free(fnamep);
-
+
/* and return error code */
return code;
}
didEnd = 0;
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
dirAFSFid.Volume = dscp->fid.volume;
rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ &dscp->fid, NULL, 1, &updatedDirStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCErrorRmdir(code, reqp);
if (code)
dirop.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&dscp->rw);
- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0) {
- cm_dnlcRemove(dscp, cnamep);
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
- }
- lock_ReleaseWrite(&dscp->rw);
-
if (code == 0) {
+ cm_dnlcRemove(dscp, cnamep);
+ code = cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
if (cm_CheckDirOpForSingleChange(&dirop) && cnamep != NULL) {
+ lock_ReleaseWrite(&dscp->rw);
cm_DirDeleteEntry(&dirop, fnamep);
#ifdef USE_BPLUS
cm_BPlusDirDeleteEntry(&dirop, cnamep);
#endif
+ lock_ObtainWrite(&dscp->rw);
}
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&dscp->rw);
+
cm_EndDirOp(&dirop);
if (scp) {
- cm_ReleaseSCache(scp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
- scp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&scp->flags, CM_SCACHEFLAG_DELETED);
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_AdjustScacheLRU(scp);
+ lock_ReleaseWrite(&cm_scacheLock);
lock_ReleaseWrite(&scp->rw);
+ if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR))
+ RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+ scp->fid.unique, scp->fid.hash,
+ scp->fileType, AFS_INVALIDATE_DELETED);
}
+ cm_ReleaseSCache(scp);
}
done:
/* we're done */
return 0;
-}
+}
/*! \brief Rename a file or directory
cm_req_t *reqp)
{
cm_conn_t *connp;
- long code;
+ long code = 0;
AFSFid oldDirAFSFid;
AFSFid newDirAFSFid;
- int didEnd;
AFSFetchStatus updatedOldDirStatus;
AFSFetchStatus updatedNewDirStatus;
AFSVolSync volSync;
- int oneDir;
+ int oneDir = 0;
+ int bTargetExists = 0;
struct rx_connection * rxconnp;
cm_dirOp_t oldDirOp;
cm_fid_t fileFid;
cm_dirOp_t newDirOp;
fschar_t * newNamep = NULL;
int free_oldNamep = FALSE;
- cm_scache_t *oldScp = NULL, *newScp = NULL;
+ cm_scache_t *oldScp = NULL, *oldTargetScp = NULL;
+ int rpc_skipped = 0;
memset(&volSync, 0, sizeof(volSync));
cm_ClientStrLen(cNewNamep) == 0)
return CM_ERROR_INVAL;
- /*
- * Before we permit the operation, make sure that we do not already have
- * an object in the destination directory that has a case-insensitive match
- * for this name UNLESS the matching object is the object we are renaming.
- */
- code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
- if (code) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed",
- oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
- goto done;
- }
-
- code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
- if (code == 0) {
- /* found a matching object with the new name */
- if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
- /* and they don't match so return an error */
- osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
- newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
- code = CM_ERROR_EXISTS;
- }
- cm_ReleaseSCache(newScp);
- newScp = NULL;
- } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
- code = CM_ERROR_EXISTS;
- } else {
- code = 0;
+ /* check for identical names */
+ if (oldDscp == newDscp &&
+ cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_RENAME_IDENTICAL",
+ oldDscp, newDscp);
+ return CM_ERROR_RENAME_IDENTICAL;
}
/* Check for RO volume */
- if (code == 0 &&
- (oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
- code = CM_ERROR_READONLY;
+ if ((oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
+ return CM_ERROR_READONLY;
}
- if (code)
- goto done;
-
if (oldNamep == NULL) {
code = -1;
#ifdef USE_BPLUS
}
#endif
if (code) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S Original Name lookup failed",
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S Original Name lookup failed",
oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
goto done;
}
}
-
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our call
* completes. We do this in vnode order so that we don't deadlock,
* which makes the code a little verbose.
*/
if (oldDscp == newDscp) {
- /* check for identical names */
- if (cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_RENAME_IDENTICAL",
- oldDscp, newDscp);
- code = CM_ERROR_RENAME_IDENTICAL;
- goto done;
- }
-
oneDir = 1;
cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
CM_DIROP_FLAG_NONE, &oldDirOp);
oneDir = 0;
if (oldDscp->fid.cell != newDscp->fid.cell ||
oldDscp->fid.volume != newDscp->fid.volume) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_CROSSDEVLINK",
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_CROSSDEVLINK",
oldDscp, newDscp);
code = CM_ERROR_CROSSDEVLINK;
goto done;
* stale info. Avoid deadlocks and quit now.
*/
if (oldDscp->fid.vnode == newDscp->fid.vnode) {
- osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p vnode collision",
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p vnode collision",
oldDscp, newDscp);
code = CM_ERROR_CROSSDEVLINK;
goto done;
CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&oldDscp->rw);
cm_EndDirOp(&oldDirOp);
- }
+ }
}
}
else {
CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&newDscp->rw);
cm_EndDirOp(&newDirOp);
- }
+ }
}
}
} /* two distinct vnodes */
- if (code)
+ if (code)
goto done;
- didEnd = 0;
+ /*
+ * The source and destination directories are now locked and no other local
+ * changes can occur.
+ *
+ * Before we permit the operation, make sure that we do not already have
+ * an object in the destination directory that has a case-insensitive match
+ * for this name UNLESS the matching object is the object we are renaming.
+ */
+ code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
+ if (code) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed",
+ oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
+ rpc_skipped = 1;
+ goto post_rpc;
+ }
+
+ /* Case sensitive lookup. If this succeeds we are done. */
+ code = cm_Lookup(newDscp, cNewNamep, 0, userp, reqp, &oldTargetScp);
+ if (code) {
+ /*
+ * Case insensitive lookup. If this succeeds, it could have found the
+ * same file with a name that differs only by case or it could be a
+ * different file entirely.
+ */
+ code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &oldTargetScp);
+ if (code == 0) {
+ /* found a matching object with the new name */
+ if (cm_FidCmp(&oldScp->fid, &oldTargetScp->fid)) {
+ /* and they don't match so return an error */
+ osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
+ newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+ code = CM_ERROR_EXISTS;
+ }
+ cm_ReleaseSCache(oldTargetScp);
+ oldTargetScp = NULL;
+ } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+ code = CM_ERROR_EXISTS;
+ } else {
+ /* The target does not exist. Clear the error and perform the rename. */
+ code = 0;
+ }
+ } else {
+ bTargetExists = 1;
+ }
+
+ if (code) {
+ rpc_skipped = 1;
+ goto post_rpc;
+ }
newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
/* try the RPC now */
- osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
+ InterlockedIncrement(&oldDscp->activeRPCs);
+ if (!oneDir)
+ InterlockedIncrement(&newDscp->activeRPCs);
+ osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
oldDscp, newDscp);
do {
code = cm_ConnFromFID(&oldDscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
oldDirAFSFid.Volume = oldDscp->fid.volume;
&volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
- &volSync, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid, NULL, 1,
+ &updatedOldDirStatus, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
-
+
if (code)
osi_Log1(afsd_logp, "CALL Rename FAILURE, code 0x%x", code);
else
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
+ post_rpc:
/* update the individual stat cache entries for the directories */
if (oldDirOp.scp) {
lock_ObtainWrite(&oldDirOp.scp->dirlock);
oldDirOp.lockType = CM_DIRLOCK_WRITE;
}
- lock_ObtainWrite(&oldDscp->rw);
- cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0)
- cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
- userp, reqp, CM_MERGEFLAG_DIROP);
- lock_ReleaseWrite(&oldDscp->rw);
+ lock_ObtainWrite(&oldDscp->rw);
+ if (code == 0) {
+ code = cm_MergeStatus( NULL, oldDscp, &updatedOldDirStatus, &volSync,
+ userp, reqp, CM_MERGEFLAG_DIROP);
+ if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (bTargetExists && oneDir) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, newNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&oldDirOp, cNewNamep);
+#endif
+ }
- if (code == 0 && cm_CheckDirOpForSingleChange(&oldDirOp)) {
#ifdef USE_BPLUS
- diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
- if (diropCode == CM_ERROR_INEXACT_MATCH)
- diropCode = 0;
- else if (diropCode == EINVAL)
+ diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
+ if (diropCode == CM_ERROR_INEXACT_MATCH)
+ diropCode = 0;
+ else if (diropCode == EINVAL)
#endif
- diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+ diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
- if (diropCode == 0) {
- if (oneDir) {
- diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+ if (diropCode == 0) {
+ if (oneDir) {
+ diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
#endif
- }
-
- if (diropCode == 0) {
- diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+ }
+
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
-#endif
+ cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+#endif
+ }
}
+ lock_ObtainWrite(&oldDscp->rw);
}
+ } else {
+ if (!rpc_skipped)
+ InterlockedDecrement(&oldDscp->activeRPCs);
}
+ cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&oldDscp->rw);
+
cm_EndDirOp(&oldDirOp);
/* and update it for the new one, too, if necessary */
newDirOp.lockType = CM_DIRLOCK_WRITE;
}
lock_ObtainWrite(&newDscp->rw);
- cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0)
- cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
- userp, reqp, CM_MERGEFLAG_DIROP);
- lock_ReleaseWrite(&newDscp->rw);
-
-#if 0
- /*
- * The following optimization does not work.
- * When the file server processed a RXAFS_Rename() request the
- * FID of the object being moved between directories is not
- * preserved. The client does not know the new FID nor the
- * version number of the target. Not only can we not create
- * the directory entry in the new directory, but we can't
- * preserve the cached data for the file. It must be re-read
- * from the file server. - jaltman, 2009/02/20
- */
if (code == 0) {
- /* we only make the local change if we successfully made
- the change in the old directory AND there was only one
- change in the new directory */
+ code = cm_MergeStatus( NULL, newDscp, &updatedNewDirStatus, &volSync,
+ userp, reqp, CM_MERGEFLAG_DIROP);
+
+ /*
+ * we only make the local change if we successfully made
+ * the change in the old directory AND there was only one
+ * change in the new directory
+ */
if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
+ lock_ReleaseWrite(&newDscp->rw);
+
+ if (bTargetExists && !oneDir) {
+ diropCode = cm_DirDeleteEntry(&newDirOp, newNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&newDirOp, cNewNamep);
+#endif
+ }
+
cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
#ifdef USE_BPLUS
cm_BPlusDirCreateEntry(&newDirOp, cNewNamep, &fileFid);
#endif
+ lock_ObtainWrite(&newDscp->rw);
}
+ } else {
+ if (!rpc_skipped)
+ InterlockedIncrement(&newDscp->activeRPCs);
}
-#endif /* 0 */
+ cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&newDscp->rw);
+
cm_EndDirOp(&newDirOp);
}
- /*
- * After the rename the file server has invalidated the callbacks
- * on the file that was moved nor do we have a directory reference
- * to it anymore.
- */
- lock_ObtainWrite(&oldScp->rw);
- cm_DiscardSCache(oldScp);
- lock_ReleaseWrite(&oldScp->rw);
+ if (code == 0) {
+ /*
+ * After the rename the file server has invalidated the callbacks
+ * on the file that was moved and destroyed any target file.
+ */
+ lock_ObtainWrite(&oldScp->rw);
+ cm_DiscardSCache(oldScp);
+ lock_ReleaseWrite(&oldScp->rw);
+
+ if (RDR_Initialized)
+ RDR_InvalidateObject(oldScp->fid.cell, oldScp->fid.volume, oldScp->fid.vnode, oldScp->fid.unique,
+ oldScp->fid.hash, oldScp->fileType, AFS_INVALIDATE_CALLBACK);
+
+ if (oldTargetScp) {
+ lock_ObtainWrite(&oldTargetScp->rw);
+ cm_DiscardSCache(oldTargetScp);
+ lock_ReleaseWrite(&oldTargetScp->rw);
+
+ if (RDR_Initialized)
+ RDR_InvalidateObject(oldTargetScp->fid.cell, oldTargetScp->fid.volume, oldTargetScp->fid.vnode, oldTargetScp->fid.unique,
+ oldTargetScp->fid.hash, oldTargetScp->fileType, AFS_INVALIDATE_CALLBACK);
+ }
+ }
done:
if (oldScp)
cm_ReleaseSCache(oldScp);
+ if (oldTargetScp)
+ cm_ReleaseSCache(oldTargetScp);
+
if (free_oldNamep)
free(oldNamep);
afs_int64 int_begin;
afs_int64 int_end;
- int_begin = MAX(pos->offset, neg->offset);
- int_end = MIN(pos->offset+pos->length, neg->offset+neg->length);
+ int_begin = max(pos->offset, neg->offset);
+ int_end = min(pos->offset+pos->length, neg->offset+neg->length);
if (int_begin < int_end) {
if (int_begin == pos->offset) {
/* 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,
- LARGE_INTEGER LOffset,
- LARGE_INTEGER LLength,
+long cm_LockCheckRead(cm_scache_t *scp,
+ LARGE_INTEGER LOffset,
+ LARGE_INTEGER LLength,
cm_key_t key)
{
#ifndef ADVISORY_LOCKS
lock_ObtainRead(&cm_scacheLock);
for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
- fileLock =
+ fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
if (INTERSECT_RANGE(range, fileLock->range)) {
lock_ObtainRead(&cm_scacheLock);
for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
- fileLock =
+ fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
if (INTERSECT_RANGE(range, fileLock->range)) {
AFSVolSync volSync;
afs_uint32 reqflags = reqp->flags;
+ osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
+
+#if 0
+ /*
+ * The file server prior to 1.6.2 does not report an accurate value
+ * and callbacks are not issued if the lock is dropped due to expiration.
+ */
+ if ((lockType != LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount != 0) ||
+ (lockType == LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount < 0))
+ {
+ code = CM_ERROR_LOCK_NOT_GRANTED;
+ osi_Log2(afsd_logp, "CALL SetLock FAILURE, fsLockCount %d code 0x%x", scp->fsLockCount, code);
+ return code;
+ }
+#endif
+
memset(&volSync, 0, sizeof(volSync));
tfid.Volume = scp->fid.volume;
tfid.Unique = scp->fid.unique;
cfid = scp->fid;
- osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
-
reqp->flags |= CM_REQ_NORETRY;
lock_ReleaseWrite(&scp->rw);
do {
code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
- if (code)
+ if (code)
break;
rxconnp = cm_GetRxConn(connp);
&volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ } while (cm_Analyze(connp, userp, reqp, &cfid, NULL, 1, NULL, &volSync,
NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
}
- lock_ObtainWrite(&scp->rw);
reqp->flags = reqflags;
+
+ lock_ObtainWrite(&scp->rw);
+ if (code == 0) {
+ /*
+ * The file server does not return a status structure so we must
+ * locally track the file server lock count to the best of our
+ * ability.
+ */
+ if (lockType == LockWrite)
+ scp->fsLockCount = -1;
+ else
+ scp->fsLockCount++;
+ }
return code;
}
struct rx_connection * rxconnp;
AFSVolSync volSync;
+ if (scp->flags & CM_SCACHEFLAG_DELETED) {
+ osi_Log1(afsd_logp, "CALL ReleaseLock on Deleted Vnode scp 0x%p", scp);
+ return 0;
+ }
+
memset(&volSync, 0, sizeof(volSync));
tfid.Volume = scp->fid.volume;
do {
code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
- if (code)
+ if (code)
break;
rxconnp = cm_GetRxConn(connp);
code = RXAFS_ReleaseLock(rxconnp, &tfid, &volSync);
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
+ } while (cm_Analyze(connp, userp, reqp, &cfid, NULL, 1, NULL, &volSync,
NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
if (code)
else
osi_Log0(afsd_logp,
"CALL ReleaseLock SUCCESS");
-
+
lock_ObtainWrite(&scp->rw);
+ if (code == 0) {
+ /*
+ * The file server does not return a status structure so we must
+ * locally track the file server lock count to the best of our
+ * ability.
+ */
+ scp->fsLockCount--;
+ if (scp->fsLockCount < 0)
+ scp->fsLockCount = 0;
+ }
- return code;
+ return (code != CM_ERROR_BADFD ? code : 0);
}
/* called with scp->rw held. May release it during processing, but
this should be sufficient for her to get a write-lock (but
not necessarily a read-lock). VICED_CAPABILITY_WRITELOCKACL
indicates whether a file server supports getting write
- locks when the user only has PRSFS_INSERT.
-
+ locks when the user only has PRSFS_INSERT.
+
If the file was not created by the user we skip the check
because the INSERT bit will not apply to this user even
if it is set.
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);
- osi_Log4(afsd_logp, "... allowWait %d key <0x%x, 0x%x, 0x%x>", allowWait,
+ osi_Log4(afsd_logp, "... allowWait %d key <0x%x, 0x%x, 0x%x>", allowWait,
key.process_id, key.session_id, key.file_id);
/*
int has_insert = 0;
/* we already have the lock we need */
- osi_Log3(afsd_logp, " we already have the correct lock. exclusives[%d], shared[%d], serverLock[%d]",
+ 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 = cm_LockCheckPerms(scp, Which, userp, reqp, &has_insert);
was valid) that we had a valid server lock. */
scp->lockDataVersion = scp->dataVersion;
check_data_version = TRUE;
-
+
code = cm_IntReleaseLock(scp, userp, reqp);
if (code) {
if (force_client_lock && code != CM_ERROR_WOULDBLOCK)
code = 0;
+ cm_HoldUser(userp);
+
lock_ObtainWrite(&cm_scacheLock);
fileLock = cm_GetFileLock();
- lock_ReleaseWrite(&cm_scacheLock);
#ifdef DEBUG
fileLock->fid = scp->fid;
#endif
fileLock->key = key;
fileLock->lockType = Which;
- cm_HoldUser(userp);
fileLock->userp = userp;
fileLock->range = range;
- fileLock->flags = (code == 0 ? 0 :
+ fileLock->flags = (code == 0 ? 0 :
((wait_unlock)?
CM_FILELOCK_FLAG_WAITUNLOCK :
CM_FILELOCK_FLAG_WAITLOCK));
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;
return code;
}
-/* Called with scp->rw held */
-long cm_UnlockByKey(cm_scache_t * scp,
- cm_key_t key,
- int flags,
- cm_user_t * userp,
- cm_req_t * reqp)
+static long
+cm_IntUnlock(cm_scache_t * scp,
+ cm_user_t * userp,
+ cm_req_t * reqp)
{
long code = 0;
- cm_file_lock_t *fileLock;
- osi_queue_t *q, *qn;
- int n_unlocks = 0;
-
- osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key <0x%x,0x%x,0x%x",
- scp, key.process_id, key.session_id, key.file_id);
- osi_Log1(afsd_logp, " flags=0x%x", flags);
- lock_ObtainWrite(&cm_scacheLock);
+ osi_assertx(scp->sharedLocks >= 0, "scp->sharedLocks < 0");
+ osi_assertx(scp->exclusiveLocks >= 0, "scp->exclusiveLocks < 0");
+ osi_assertx(scp->clientLocks >= 0, "scp->clientLocks < 0");
- for (q = scp->fileLocksH; q; q = qn) {
- qn = osi_QNext(q);
-
- fileLock = (cm_file_lock_t *)
- ((char *) q - offsetof(cm_file_lock_t, fileq));
-
-#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->lockType);
- osi_Log4(afsd_logp, " key<0x%x, 0x%x, 0x%x> flags[0x%x]",
- fileLock->key.process_id, fileLock->key.session_id, fileLock->key.file_id,
- fileLock->flags);
-
- 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,
- fileLock->fid.volume,
- fileLock->fid.vnode,
- fileLock->fid.unique);
- osi_Log4(afsd_logp, " scp->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
- fileLock->scp->fid.cell,
- fileLock->scp->fid.volume,
- fileLock->scp->fid.vnode,
- fileLock->scp->fid.unique);
- osi_assertx(FALSE, "invalid fid value");
- }
-#endif
-
- if (!IS_LOCK_DELETED(fileLock) &&
- cm_KeyEquals(&fileLock->key, &key, flags)) {
- osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
- fileLock->range.offset,
- fileLock->range.length,
- fileLock->lockType);
-
- if (scp->fileLocksT == q)
- scp->fileLocksT = osi_QPrev(q);
- osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
-
- if (IS_LOCK_CLIENTONLY(fileLock)) {
- scp->clientLocks--;
- } else if (IS_LOCK_ACCEPTED(fileLock)) {
- if (fileLock->lockType == LockRead)
- scp->sharedLocks--;
- else
- scp->exclusiveLocks--;
- }
-
- fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
-
- cm_ReleaseUser(fileLock->userp);
- cm_ReleaseSCacheNoLock(scp);
-
- fileLock->userp = NULL;
- fileLock->scp = NULL;
-
- n_unlocks++;
- }
- }
-
- lock_ReleaseWrite(&cm_scacheLock);
-
- 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);
-
- return 0;
- }
-
- osi_Log1(afsd_logp, "cm_UnlockByKey done with %d locks", n_unlocks);
-
- 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");
- goto done;
- }
+ if (!SERVERLOCKS_ENABLED(scp)) {
+ osi_Log0(afsd_logp, " Skipping server lock for scp");
+ goto done;
+ }
/* Ideally we would go through the rest of the locks to determine
* if one or more locks that were formerly in WAITUNLOCK can now
scp->lockDataVersion = scp->dataVersion;
osi_Log1(afsd_logp, " dataVersion on scp = %I64d", scp->dataVersion);
+ /* before we downgrade, make sure that we have enough
+ permissions to get the read lock. */
+ code = cm_LockCheckPerms(scp, LockRead, userp, reqp, NULL);
+ if (code != 0) {
+
+ osi_Log0(afsd_logp, " SKIPPING downgrade because user doesn't have perms to get downgraded lock");
+
+ code = 0;
+ goto done;
+ }
+
code = cm_IntReleaseLock(scp, userp, reqp);
if (code) {
osi_Log2(afsd_logp, " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
-
+
code = cm_IntReleaseLock(scp, userp, reqp);
code = CM_ERROR_INVAL;
cm_LockMarkSCacheLost(scp);
}
- /* failure here has no bearing on the return value of
- cm_Unlock() */
+ /* failure here has no bearing on the return value of cm_Unlock() */
code = 0;
} else if (scp->serverLock != (-1) &&
/* The serverLock should be released entirely */
if (scp->serverLock == LockWrite) {
+ osi_Log0(afsd_logp, " RELEASE LockWrite -> LockNone");
+
/* Make sure there are no dirty buffers left. */
code = cm_FSync(scp, userp, reqp, TRUE);
+ } else {
+ osi_Log0(afsd_logp, " RELEASE LockRead -> LockNone");
}
code = cm_IntReleaseLock(scp, userp, reqp);
scp->serverLock = (-1);
}
- done:
+ done:
+ return code;
+}
+/* Called with scp->rw held */
+long cm_UnlockByKey(cm_scache_t * scp,
+ cm_key_t key,
+ afs_uint32 flags,
+ cm_user_t * userp,
+ cm_req_t * reqp)
+{
+ long code = 0;
+ cm_file_lock_t *fileLock;
+ osi_queue_t *q, *qn;
+ int n_unlocks = 0;
+
+ osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key <0x%x,0x%x,0x%x",
+ scp, key.process_id, key.session_id, key.file_id);
+ osi_Log1(afsd_logp, " flags=0x%x", flags);
+ lock_ObtainWrite(&cm_scacheLock);
+
+ for (q = scp->fileLocksH; q; q = qn) {
+ qn = osi_QNext(q);
+
+ fileLock = (cm_file_lock_t *)
+ ((char *) q - offsetof(cm_file_lock_t, fileq));
+
+#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->lockType);
+ osi_Log4(afsd_logp, " key<0x%x, 0x%x, 0x%x> flags[0x%x]",
+ fileLock->key.process_id, fileLock->key.session_id, fileLock->key.file_id,
+ fileLock->flags);
+
+ 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,
+ fileLock->fid.volume,
+ fileLock->fid.vnode,
+ fileLock->fid.unique);
+ osi_Log4(afsd_logp, " scp->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
+ fileLock->scp->fid.cell,
+ fileLock->scp->fid.volume,
+ fileLock->scp->fid.vnode,
+ fileLock->scp->fid.unique);
+ osi_assertx(FALSE, "invalid fid value");
+ }
+#endif
+
+ if (!IS_LOCK_DELETED(fileLock) &&
+ cm_KeyEquals(&fileLock->key, &key, flags)) {
+ osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
+ fileLock->range.offset,
+ fileLock->range.length,
+ fileLock->lockType);
+
+ osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
+
+ if (IS_LOCK_CLIENTONLY(fileLock)) {
+ scp->clientLocks--;
+ } else if (IS_LOCK_ACCEPTED(fileLock)) {
+ if (fileLock->lockType == LockRead)
+ scp->sharedLocks--;
+ else
+ scp->exclusiveLocks--;
+ }
+
+ fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+
+ cm_ReleaseUser(fileLock->userp);
+ cm_ReleaseSCacheNoLock(scp);
+
+ fileLock->userp = NULL;
+ fileLock->scp = NULL;
+
+ n_unlocks++;
+ }
+ }
+
+ lock_ReleaseWrite(&cm_scacheLock);
+
+ 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);
+
+ return 0;
+ }
+
+ code = cm_IntUnlock(scp, userp, reqp);
osi_Log1(afsd_logp, "cm_UnlockByKey code 0x%x", code);
+
osi_Log4(afsd_logp, " Leaving scp with excl[%d], shared[%d], client[%d], serverLock[%d]",
scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
(int)(signed char) scp->serverLock);
return code;
}
-long cm_Unlock(cm_scache_t *scp,
+/* Called with scp->rw held */
+long cm_Unlock(cm_scache_t *scp,
unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
- cm_key_t key,
+ cm_key_t key,
afs_uint32 flags,
- cm_user_t *userp,
+ cm_user_t *userp,
cm_req_t *reqp)
{
long code = 0;
int lock_found = 0;
LARGE_INTEGER RangeEnd;
- osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
+ osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset 0x%x length 0x%x",
scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
osi_Log4(afsd_logp, "... key <0x%x,0x%x,0x%x> flags 0x%x",
key.process_id, key.session_id, key.file_id, flags);
goto done;
} else {
osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
-
+
/* The lock didn't exist anyway. *shrug* */
return CM_ERROR_RANGE_NOT_LOCKED;
}
/* discard lock record */
lock_ConvertRToW(&cm_scacheLock);
- if (scp->fileLocksT == q)
- scp->fileLocksT = osi_QPrev(q);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
/*
}
fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+
if (userp != NULL) {
cm_ReleaseUser(fileLock->userp);
} else {
userp = fileLock->userp;
release_userp = TRUE;
}
- fileLock->userp = NULL;
cm_ReleaseSCacheNoLock(scp);
+ fileLock->userp = NULL;
fileLock->scp = NULL;
lock_ReleaseWrite(&cm_scacheLock);
- if (!SERVERLOCKS_ENABLED(scp)) {
- osi_Log0(afsd_logp, " Skipping server locks for scp");
- goto done;
- }
-
- /* Ideally we would go through the rest of the locks to determine
- * if one or more locks that were formerly in WAITUNLOCK can now
- * be put to ACTIVE or WAITLOCK and update scp->exclusiveLocks and
- * scp->sharedLocks accordingly. However, the retrying of locks
- * in that manner is done cm_RetryLock() manually.
- */
-
- 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");
-
- /* Make sure there are no dirty buffers left. */
- code = cm_FSync(scp, userp, reqp, TRUE);
-
- /* 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 %I64d", scp->dataVersion);
-
- /* before we downgrade, make sure that we have enough
- permissions to get the read lock. */
- code = cm_LockCheckPerms(scp, LockRead, userp, reqp, NULL);
- if (code != 0) {
-
- osi_Log0(afsd_logp, " SKIPPING downgrade because user doesn't have perms to get downgraded lock");
-
- code = 0;
- goto done;
- }
-
- code = cm_IntReleaseLock(scp, userp, reqp);
-
- if (code) {
- /* so we couldn't release it. Just let the lock be for now */
- code = 0;
- goto done;
- } else {
- scp->serverLock = -1;
- }
-
- code = cm_IntSetLock(scp, userp, LockRead, reqp);
-
- 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=%I64d, after=%I64d",
- scp->lockDataVersion,
- scp->dataVersion);
-
- code = cm_IntReleaseLock(scp, userp, reqp);
-
- scp->serverLock = -1;
- code = CM_ERROR_INVAL;
- }
-
- 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) {
- /* The serverLock should be released entirely */
-
- if (scp->serverLock == LockWrite) {
- /* Make sure there are no dirty buffers left. */
- code = cm_FSync(scp, userp, reqp, TRUE);
- }
-
- code = cm_IntReleaseLock(scp, userp, reqp);
-
- if (code == 0) {
- scp->serverLock = (-1);
- }
- }
+ code = cm_IntUnlock(scp, userp, reqp);
if (release_userp) {
cm_ReleaseUser(userp);
release_userp = FALSE;
}
- if (!exact_match)
+ if (!exact_match) {
+ osi_Log1(afsd_logp, "cm_Unlock not exact match, searching for next lock, code 0x%x", code);
goto try_again; /* might be more than one lock in the range */
+ }
done:
lock_ObtainWrite(&cm_scacheLock);
for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
- fileLock =
+ fileLock =
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
if (IS_LOCK_ACTIVE(fileLock) &&
code = -1;
if (IS_LOCK_DELETED(fileLock)) {
+ cm_user_t *userp = fileLock->userp;
+ cm_scache_t *scp = fileLock->scp;
+ fileLock->userp = NULL;
+ fileLock->scp = NULL;
+ if (scp && userp) {
+ lock_ReleaseWrite(&cm_scacheLock);
+ lock_ObtainWrite(&scp->rw);
+ code = cm_IntUnlock(scp, userp, &req);
+ lock_ReleaseWrite(&scp->rw);
+
+ cm_ReleaseUser(userp);
+ lock_ObtainWrite(&cm_scacheLock);
+ cm_ReleaseSCacheNoLock(scp);
+ }
osi_QRemove(&cm_allFileLocks, q);
cm_PutFileLock(fileLock);
goto post_syncopdone;
code = cm_SyncOp(scp, NULL, fileLock->userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK
- | CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_LOCK);
+ CM_SCACHESYNC_LOCK);
if (code) {
osi_Log1(afsd_logp,
tfid.Unique = scp->fid.unique;
cfid = scp->fid;
userp = fileLock->userp;
-
- osi_Log3(afsd_logp, "CALL ExtendLock lock 0x%p for scp=0x%p with lock %d",
+
+ osi_Log3(afsd_logp, "CALL ExtendLock lock 0x%p for scp=0x%p with lock %d",
fileLock,
scp,
(int) scp->serverLock);
do {
code = cm_ConnFromFID(&cfid, userp,
&req, &connp);
- if (code)
+ if (code)
break;
rxconnp = cm_GetRxConn(connp);
osi_Log1(afsd_logp, " ExtendLock returns %d", code);
} while (cm_Analyze(connp, userp, &req,
- &cfid, &volSync, NULL, NULL,
+ &cfid, NULL, 1, NULL, &volSync, NULL, NULL,
code));
code = cm_MapRPCError(code, &req);
if (code) {
osi_Log1(afsd_logp, "CALL ExtendLock FAILURE, code 0x%x", code);
+ scp->fsLockCount = 0;
} else {
osi_Log0(afsd_logp, "CALL ExtendLock SUCCESS");
scp->lockDataVersion = scp->dataVersion;
if (code == 0) {
fileLock->lastUpdate = time(NULL);
}
-
+
if (scp_done)
scp->lastRefreshCycle = cm_lockRefreshCycle;
cm_user_t * userp;
code = cm_SyncOp(scp, NULL, oldFileLock->userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK
- | CM_SCACHESYNC_GETSTATUS
- | CM_SCACHESYNC_LOCK);
+ CM_SCACHESYNC_LOCK);
if (code) {
osi_Log1(afsd_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
lock_ReleaseWrite(&cm_scacheLock);
handleCode:
if (code != 0 && code != CM_ERROR_WOULDBLOCK) {
lock_ObtainWrite(&cm_scacheLock);
- if (scp->fileLocksT == &oldFileLock->fileq)
- scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
lock_ReleaseWrite(&cm_scacheLock);
}
return code;
}
-cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint64 file_id)
{
cm_key_t key;
int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
{
return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
- ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
+ ((flags & CM_UNLOCK_FLAG_BY_FID) || (k1->process_id == k2->process_id));
}
void cm_ReleaseAllLocks(void)