* directory or online at http://www.openafs.org/dl/license10.html
*/
+#include <afsconfig.h>
#include <afs/param.h>
+#include <roken.h>
+
#include <afs/stds.h>
#include <windows.h>
code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
if (code == 0) {
- cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
+ cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp);
} else {
/* In this case, we allow the file open to go through even
though we can't enforce mandatory locking on the
cm_lock_data_t **ldpp)
{
long rights;
- long code;
+ long code = 0;
osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
/* Always allow delete; the RPC will tell us if it's OK */
- if (desiredAccess == DELETE)
- return 0;
-
rights = 0;
+ if (desiredAccess == DELETE)
+ goto done_2;
+
if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
if (desiredAccess & AFS_ACCESS_WRITE)
rights |= PRSFS_WRITE;
+ if (desiredAccess & DELETE)
+ rights |= PRSFS_DELETE;
+
lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
_done:
lock_ReleaseWrite(&scp->rw);
+ done_2:
osi_Log3(afsd_logp,"cm_CheckNTOpen scp 0x%p ldp 0x%p code 0x%x", scp, *ldpp, code);
return code;
}
lock_ObtainWrite(&scp->rw);
if (*ldpp) {
cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
- (*ldpp)->key, userp, reqp);
+ (*ldpp)->key, 0, userp, reqp);
free(*ldpp);
*ldpp = NULL;
}
return code;
thyper.HighPart = 0; thyper.LowPart = 0;
- code = buf_Get(scp, &thyper, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, &bufferp);
if (code)
return code;
return 0;
}
sp->caseFold = casefold;
+ }
- /* see if we can find it using the directory hash tables.
- we can only do exact matches, since the hash is case
- sensitive. */
- {
- cm_dirOp_t dirop;
+ /*
+ * see if we can find it using the directory hash tables.
+ * we can only do exact matches, since the hash is case
+ * sensitive.
+ */
+ if (funcp != (cm_DirFuncp_t)cm_BPlusDirFoo)
+ {
+ cm_dirOp_t dirop;
#ifdef USE_BPLUS
- int usedBplus = 0;
+ int usedBplus = 0;
#endif
- code = ENOENT;
+ code = ENOENT;
- code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ, &dirop);
- if (code == 0) {
+ code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
+ if (code == 0) {
#ifdef USE_BPLUS
- code = cm_BPlusDirLookup(&dirop, sp->nsearchNamep, &sp->fid);
- if (code != EINVAL)
- usedBplus = 1;
- else
+ code = cm_BPlusDirLookup(&dirop, sp->nsearchNamep, &sp->fid);
+ if (code != EINVAL)
+ usedBplus = 1;
+ else
#endif
- code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
+ code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
- cm_EndDirOp(&dirop);
- }
+ cm_EndDirOp(&dirop);
+ }
- if (code == 0) {
+ if (code == 0) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = TRUE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+#ifdef USE_BPLUS
+ if (usedBplus) {
+ if (sp->caseFold && code == CM_ERROR_INEXACT_MATCH) {
/* found it */
sp->found = TRUE;
- sp->ExactFound = TRUE;
+ sp->ExactFound = FALSE;
*retscp = NULL; /* force caller to call cm_GetSCache() */
return 0;
}
-#ifdef USE_BPLUS
- if (usedBplus) {
- if (sp->caseFold && code == CM_ERROR_INEXACT_MATCH) {
- /* found it */
- sp->found = TRUE;
- sp->ExactFound = FALSE;
- *retscp = NULL; /* force caller to call cm_GetSCache() */
- return 0;
- }
-
- return CM_ERROR_BPLUS_NOMATCH;
- }
-#endif
+
+ return CM_ERROR_BPLUS_NOMATCH;
}
+#endif
}
}
bufferp = NULL;
}
- code = buf_Get(scp, &thyper, &bufferp);
+ code = buf_Get(scp, &thyper, reqp, &bufferp);
if (code) {
/* if buf_Get() fails we do not have a buffer object to lock */
bufferp = NULL;
tp = bufferp->datap + entryInBuffer;
dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
+ /*
+ * here are some consistency checks
+ */
+ if (dep->flag != CM_DIR_FFIRST ||
+ strlen(dep->name) > 256) {
+ code = CM_ERROR_INVAL;
+ osi_Log2(afsd_logp,
+ "cm_ApplyDir invalid directory entry for scp %p bufp %p",
+ scp, bufferp);
+ osi_Log4(afsd_logp,"... cell %u vol %u vnode %u uniq %u",
+ scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
+ bufferp->dataVersion = CM_BUF_VERSION_BAD;
+ break;
+ }
+
/* while we're here, compute the next entry's location, too,
* since we'll need it when writing out the cookie into the
* dir listing stream.
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;
if (scp->mountPointStringp[0])
return 0;
} else
#endif /* AFS_FREELANCE_CLIENT */
{
- /* otherwise, we have to read it in */
- lock_ReleaseWrite(&scp->rw);
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t thyper;
+ /* otherwise, we have to read it in */
thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(scp, &thyper, &bufp);
-
- lock_ObtainWrite(&scp->rw);
+ code = cm_GetData(scp, &thyper, temp, MOUNTPOINTLEN, 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;
-
- /* 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;
- goto done;
- }
-
- /* someone else did the work while we were out */
- if (scp->mountPointStringp[0]) {
- code = 0;
- goto done;
- }
-
- /* otherwise, copy out the link */
- memcpy(scp->mountPointStringp, bufp->datap, tlen);
-
- /* 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->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.
*/
- scp->mountPointStringp[tlen-1] = 0;
- code = 0;
+ if (scp->length.LowPart > MOUNTPOINTLEN - 1)
+ return CM_ERROR_TOOBIG;
+ if (scp->length.LowPart == 0)
+ return CM_ERROR_INVAL;
- done:
- if (bufp)
- buf_Release(bufp);
+ /* convert the terminating dot to a NUL */
+ temp[thyper.LowPart - 1] = 0;
+ memcpy(scp->mountPointStringp, temp, thyper.LowPart);
}
+
return code;
}
{
fschar_t *cellNamep = NULL;
fschar_t *volNamep = NULL;
- int tlen;
afs_uint32 code;
fschar_t *cp;
fschar_t *mpNamep;
mpNamep = scp->mountPointStringp;
if (!mpNamep[0])
return CM_ERROR_NOSUCHPATH;
- tlen = cm_FsStrLen(scp->mountPointStringp);
mtType = *scp->mountPointStringp;
cp = cm_FsStrChr(mpNamep, _FS(':'));
/* normal mt pt */
volNamep = cm_FsStrDup(mpNamep + 1);
- cellp = cm_FindCellByID(scp->fid.cell, 0);
+#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 */
+ cellp = cm_FindCellByID(scp->fid.cell, 0);
}
if (!cellp) {
int getroot;
normchar_t *nnamep = NULL;
fschar_t *fnamep = NULL;
+ size_t fnlen;
*outScpp = NULL;
goto done;
}
+retry_lookup:
if (flags & CM_FLAG_NOMOUNTCHASE) {
/* In this case, we should go and call cm_Dir* functions
directly since the following cm_ApplyDir() function will
int usedBplus = 0;
#endif
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
#ifdef USE_BPLUS
code = cm_BPlusDirLookup(&dirop, nnamep, &rock.fid);
goto haveFid;
}
- return CM_ERROR_BPLUS_NOMATCH;
+ code = CM_ERROR_BPLUS_NOMATCH;
+ goto notfound;
}
#endif
}
* 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) {
+ 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
* is to describe the final component not an intermediary
goto done;
}
+notfound:
getroot = (dscp==cm_data.rootSCachep) ;
if (!rock.found) {
if (!cm_freelanceEnabled || !getroot) {
/* 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_LogSaveClientString(afsd_logp,cnamep));
*/
code = -1;
+ fnlen = strlen(fnamep);
+ if ( fnamep[fnlen-1] == '.') {
+ fnamep[fnlen-1] = '\0';
+ fnlen--;
+ retry = 1;
+ }
+
if (cnamep[0] == '.') {
if (cm_GetCell_Gen(&fnamep[1], &fullname[1], CM_FLAG_CREATE)) {
found = 1;
- if (!cm_FreelanceMountPointExists(fullname, 0))
- code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.",
- 1, &rock.fid);
- if ( cm_FsStrCmpI(&fnamep[1], &fullname[1]) &&
- !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
- !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
- code = cm_FreelanceAddSymlink(fnamep, fullname, &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:
+ * . the cellname followed by a dot
+ * . the cellname minus a single character
+ * . a substring of the cellname that does not consist of full components
+ */
+ if ( cm_strnicmp_utf8(&fnamep[1], fullname, (int)fnlen-1) == 0 &&
+ (fnlen-1 == strlen(fullname)-1 || fullname[fnlen-1] != '.'))
+ {
+ /* do not add; substitute fullname for the search */
+ free(fnamep);
+ fnamep = malloc(strlen(fullname)+2);
+ fnamep[0] = '.';
+ strncpy(&fnamep[1], fullname, strlen(fullname)+1);
+ retry = 1;
+ } else {
+ code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
+ }
+ }
}
} else {
if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
found = 1;
- if (!cm_FreelanceMountPointExists(fullname, 0))
- code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
- if ( cm_FsStrCmpI(fnamep, fullname) &&
- !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
- !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
- code = cm_FreelanceAddSymlink(fnamep, fullname, &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:
+ * . the cellname followed by a dot
+ * . the cellname minus a single character
+ * . a substring of the cellname that does not consist of full components
+ */
+ if ( cm_strnicmp_utf8(fnamep, fullname, (int)fnlen-1) == 0 &&
+ (fnlen == strlen(fullname)-1 || fullname[fnlen] != '.'))
+ {
+ /* do not add; substitute fullname for the search */
+ free(fnamep);
+ fnamep = strdup(fullname);
+ code = 0;
+ retry = 1;
+ } else {
+ code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
+ }
+ }
}
}
- if (!found || code < 0) { /* add mount point failed, so give up */
+
+ if (retry) {
+ if (nnamep)
+ free(nnamep);
+ nnamep = cm_FsStringToNormStringAlloc(fnamep, -1, NULL);
+ goto retry_lookup;
+ }
+
+ if (!found || code) { /* add mount point failed, so give up */
if (flags & CM_FLAG_CHECKPATH)
code = CM_ERROR_NOSUCHPATH;
else
}
}
- haveFid:
+ haveFid:
if ( !tscp ) /* we did not find it in the dnlc */
{
dnlcHit = 0;
/* 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.
+ * 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)) {
+ 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)
cm_scache_t *scp = NULL;
int free_fnamep = FALSE;
+ memset(&volSync, 0, sizeof(volSync));
+
if (fnamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
if (code == 0)
#endif
code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+ if (code)
+ goto done;
+
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ goto done;
+ }
/* make sure we don't screw up the dir status during the merge */
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &dirop);
lock_ObtainWrite(&dscp->rw);
sflags = CM_SCACHESYNC_STOREDATA;
cm_dnlcRemove(dscp, cnamep);
cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ 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
cm_ReleaseSCache(scp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
- scp->flags |= CM_SCACHEFLAG_DELETED;
+ if (--scp->linkCount == 0)
+ scp->flags |= CM_SCACHEFLAG_DELETED;
+ cm_DiscardSCache(scp);
lock_ReleaseWrite(&scp->rw);
}
}
*/
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]) {
} else
#endif /* AFS_FREELANCE_CLIENT */
{
- /* read the link data from the file server*/
- lock_ReleaseWrite(&linkScp->rw);
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t thyper;
+
+ /* read the link data from the file server */
thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(linkScp, &thyper, &bufp);
- lock_ObtainWrite(&linkScp->rw);
- if (code)
+ code = cm_GetData(linkScp, &thyper, temp, MOUNTPOINTLEN, userp, reqp);
+ 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;
-
- code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
- if (code) {
- buf_Release(bufp);
- return code;
- }
- } /* while loop to get the data */
-
- /* 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);
+ /* convert the terminating dot to a NUL */
+ temp[thyper.LowPart - 1] = 0;
+ memcpy(linkScp->mountPointStringp, temp, thyper.LowPart);
}
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
*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;
StringCbCopyA((char *) tsp->data, sizeof(tsp->data), linkp+cm_mountRootLen+1);
else
tsp->data[0] = 0;
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *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 (*p == '\\')
*p = '/';
}
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *newRootScpp = cm_RootSCachep(userp, reqp);
+ cm_HoldSCache(*newRootScpp);
} else {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
* but this seems to create problems. instead, we will just
* reject the link */
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp+1);
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *newRootScpp = cm_RootSCachep(userp, reqp);
+ cm_HoldSCache(*newRootScpp);
#else
/* we still copy the link data into the response so that
* the user can see what the link points to
fid_count = i+1;
} else {
/* add the new fid to the list */
- for ( i=0; i<fid_count; i++) {
- if ( !cm_FidCmp(&nscp->fid, &fids[i]) ) {
- code = CM_ERROR_TOO_MANY_SYMLINKS;
- cm_ReleaseSCache(nscp);
- nscp = NULL;
- break;
- }
- }
- if (i == fid_count && fid_count < MAX_FID_COUNT) {
- fids[fid_count++] = nscp->fid;
- }
+ if (fid_count == MAX_FID_COUNT) {
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
+ cm_ReleaseSCache(nscp);
+ nscp = NULL;
+ break;
+ }
+ fids[fid_count++] = nscp->fid;
}
}
}
if (code == 0 && linkScp != NULL) {
- if (linkScp == cm_data.rootSCachep)
+ if (linkScp == cm_data.rootSCachep) {
fid_count = 0;
- else {
+ i = 0;
+ } else {
for ( i=0; i<fid_count; i++) {
if ( !cm_FidCmp(&linkScp->fid, &fids[i]) ) {
code = CM_ERROR_TOO_MANY_SYMLINKS;
cm_scache_t *scp;
cm_fid_t tfid;
struct rx_connection * rxconnp;
- int inlinebulk = 0; /* Did we use InlineBulkStatus RPC or not? */
-
+ int inlinebulk; /* Did we use InlineBulkStatus RPC or not? */
+
+ memset(&volSync, 0, sizeof(volSync));
+
/* otherwise, we may have one or more bulk stat's worth of stuff in bb;
* make the calls to create the entries. Handle AFSCBMAX files at a
* time.
callbackStruct.AFSCBs_val = &bbp->callbacks[filex];
cm_StartCallbackGrantingCall(NULL, &cbReq);
osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
+
+ /*
+ * Whenever cm_Analyze is called for a RXAFS_ RPC there must
+ * be a FID provided. However, the error code from RXAFS_BulkStatus
+ * or RXAFS_InlinkBulkStatus does not apply to any FID. Therefore,
+ * we generate an invalid FID to match with the RPC error.
+ */
+ cm_SetFid(&tfid, dscp->fid.cell, dscp->fid.volume, 0, 0);
+
do {
- code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
+ inlinebulk = 0;
+
+ code = cm_ConnFromFID(&tfid, userp, reqp, &connp);
if (code)
continue;
rxconnp = cm_GetRxConn(connp);
if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
code = RXAFS_InlineBulkStatus(rxconnp, &fidStruct,
- &statStruct, &callbackStruct, &volSync);
+ &statStruct, &callbackStruct, &volSync);
if (code == RXGEN_OPCODE) {
cm_SetServerNoInlineBulk(connp->serverp, 0);
} else {
}
rx_PutConnection(rxconnp);
- } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
- &volSync, NULL, &cbReq, code));
+ /*
+ * If InlineBulk RPC was called and it succeeded,
+ * then pull out the return code from the status info
+ * and use it for cm_Analyze so that we can failover to other
+ * .readonly volume instances. But only do it for errors that
+ * are volume global.
+ */
+ if (inlinebulk && code == 0 && (&bbp->stats[0])->errorCode) {
+ osi_Log1(afsd_logp, "cm_TryBulkStat inline-bulk stat error: %d",
+ (&bbp->stats[0])->errorCode);
+ switch ((&bbp->stats[0])->errorCode) {
+ case VBUSY:
+ case VRESTARTING:
+ case VNOVOL:
+ case VMOVED:
+ case VOFFLINE:
+ case VSALVAGE:
+ case VNOSERVICE:
+ case VIO:
+ code = (&bbp->stats[0])->errorCode;
+ break;
+ default:
+ /* Rx and Rxkad errors are volume global */
+ if ( (&bbp->stats[0])->errorCode >= -64 && (&bbp->stats[0])->errorCode < 0 ||
+ (&bbp->stats[0])->errorCode >= ERROR_TABLE_BASE_RXK && (&bbp->stats[0])->errorCode < ERROR_TABLE_BASE_RXK + 256)
+ code = (&bbp->stats[0])->errorCode;
+ }
+ }
+ } while (cm_Analyze(connp, userp, reqp, &tfid, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
- if (code)
- osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x",
- inlinebulk ? "Inline" : "", code);
- else
- osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
- /* may as well quit on an error, since we're not going to do
+ /*
+ * might as well quit on an error, since we're not going to do
* much better on the next immediate call, either.
*/
if (code) {
- cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x",
+ inlinebulk ? "Inline" : "", code);
+ cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
break;
}
- /* otherwise, we should do the merges */
+ /*
+ * The bulk RPC has succeeded or at least not failed with a
+ * volume global error result. For items that have inlineBulk
+ * errors we must call cm_Analyze in order to perform required
+ * logging of errors.
+ *
+ * If the RPC was not inline bulk or the entry either has no error
+ * the status must be merged.
+ */
+ osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
+
for (i = 0; i<filesThisCall; i++) {
j = filex + i;
cm_SetFid(&tfid, dscp->fid.cell, bbp->fids[j].Volume, bbp->fids[j].Vnode, bbp->fids[j].Unique);
- code = cm_GetSCache(&tfid, &scp, userp, reqp);
- if (code != 0)
- continue;
- /* otherwise, if this entry has no callback info,
- * merge in this.
- */
- lock_ObtainWrite(&scp->rw);
- /* now, we have to be extra paranoid on merging in this
- * information, since we didn't use cm_SyncOp before
- * starting the fetch to make sure that no bad races
- * were occurring. Specifically, we need to make sure
- * we don't obliterate any newer information in the
- * vnode than have here.
- *
- * Right now, be pretty conservative: if there's a
- * callback or a pending call, skip it.
- */
- if ((scp->cbServerp == NULL || (scp->flags & CM_SCACHEFLAG_EACCESS))
- && !(scp->flags &
- (CM_SCACHEFLAG_FETCHING
- | CM_SCACHEFLAG_STORING
- | CM_SCACHEFLAG_SIZESTORING))) {
- cm_EndCallbackGrantingCall(scp, &cbReq,
- &bbp->callbacks[j],
- CM_CALLBACK_MAINTAINCOUNT);
- cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, 0);
- }
- lock_ReleaseWrite(&scp->rw);
- cm_ReleaseSCache(scp);
+ if (inlinebulk && (&bbp->stats[j])->errorCode) {
+ cm_req_t treq = *reqp;
+ cm_Analyze(NULL, userp, &treq, &tfid, &volSync, NULL, &cbReq, (&bbp->stats[j])->errorCode);
+ } else {
+ code = cm_GetSCache(&tfid, &scp, userp, reqp);
+ if (code != 0)
+ continue;
+
+ /*
+ * otherwise, if this entry has no callback info,
+ * merge in this. If there is existing callback info
+ * we skip the merge because the existing data must be
+ * current (we have a callback) and the response from
+ * a non-inline bulk rpc might actually be wrong.
+ *
+ * now, we have to be extra paranoid on merging in this
+ * information, since we didn't use cm_SyncOp before
+ * starting the fetch to make sure that no bad races
+ * were occurring. Specifically, we need to make sure
+ * we don't obliterate any newer information in the
+ * vnode than have here.
+ *
+ * Right now, be pretty conservative: if there's a
+ * callback or a pending call, skip it.
+ * However, if the prior attempt to obtain status
+ * was refused access or the volume is .readonly,
+ * take the data in any case since we have nothing
+ * better for the in flight directory enumeration that
+ * resulted in this function being called.
+ */
+ lock_ObtainRead(&scp->rw);
+ 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))
+ {
+ 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);
+ lock_ReleaseWrite(&scp->rw);
+ } else {
+ lock_ReleaseRead(&scp->rw);
+ }
+ cm_ReleaseSCache(scp);
+ }
} /* all files in the response */
/* now tell it to drop the count,
* after doing the vnode processing above */
- cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
} /* while there are still more files to process */
- /* If we did the InlineBulk RPC pull out the return code and log it */
- if (inlinebulk) {
- if ((&bbp->stats[0])->errorCode) {
- osi_Log1(afsd_logp, "cm_TryBulkStat bulk stat error: %d",
- (&bbp->stats[0])->errorCode);
- code = (&bbp->stats[0])->errorCode;
- }
- }
-
return code;
}
AFSStoreStatus afsInStatus;
struct rx_connection * rxconnp;
+ memset(&volSync, 0, sizeof(volSync));
+
/* handle file length setting */
if (attrp->mask & CM_ATTRMASK_LENGTH)
return cm_SetLength(scp, &attrp->length, userp, reqp);
lock_ObtainWrite(&scp->rw);
+ /* Check for RO volume */
+ if (scp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ lock_ReleaseWrite(&scp->rw);
+ return code;
+ }
+
/* otherwise, we have to make an RPC to get the status */
code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
if (code) {
lock_ObtainWrite(&scp->rw);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
if (code == 0)
- cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp,
+ 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,
cm_dirOp_t dirop;
fschar_t * fnamep = NULL;
+ memset(&volSync, 0, sizeof(volSync));
+
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
}
#endif /* AFS_FREELANCE_CLIENT */
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
/* before starting the RPC, mark that we're changing the file data, so
* that someone who does a chmod will know to wait until our call
* completes.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&scp->rw);
scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
- cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
- userp, 0);
cm_EndCallbackGrantingCall(scp, &cbReq,
- &newFileCallback, 0);
+ &newFileCallback, &volSync, 0);
+ cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
/* make sure we end things properly */
if (!didEnd)
- cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, fnamep, &newFid);
return code;
}
-long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
+/*
+ * locked if TRUE means write-locked
+ * else the cm_scache_t rw must not be held
+ */
+long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked)
{
long code;
+ if (locked)
+ lock_ReleaseWrite(&scp->rw);
code = buf_CleanVnode(scp, userp, reqp);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
}
- lock_ReleaseWrite(&scp->rw);
+ if (!locked)
+ lock_ReleaseWrite(&scp->rw);
+ } else if (locked) {
+ lock_ObtainWrite(&scp->rw);
}
return code;
}
cm_dirOp_t dirop;
fschar_t * fnamep = NULL;
+ memset(&volSync, 0, sizeof(volSync));
+
/* can't create names with @sys in them; must expand it manually first.
* return "invalid request" if they try.
*/
}
#endif /* AFS_FREELANCE_CLIENT */
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
/* 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.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseWrite(&dscp->rw);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
- cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
- userp, 0);
cm_EndCallbackGrantingCall(scp, &cbReq,
- &newDirCallback, 0);
+ &newDirCallback, &volSync, 0);
+ cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
lock_ReleaseWrite(&scp->rw);
/* make sure we end things properly */
if (!didEnd)
- cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+ cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, fnamep, &newFid);
cm_dirOp_t dirop;
fschar_t * fnamep = NULL;
+ memset(&volSync, 0, sizeof(volSync));
+
if (dscp->fid.cell != sscp->fid.cell ||
dscp->fid.volume != sscp->fid.volume) {
return CM_ERROR_CROSSDEVLINK;
}
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseWrite(&dscp->rw);
}
cm_EndDirOp(&dirop);
+ /* Update the linked object status */
+ if (code == 0) {
+ lock_ObtainWrite(&sscp->rw);
+ cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
+ lock_ReleaseWrite(&sscp->rw);
+ }
+
free(fnamep);
return code;
cm_dirOp_t dirop;
fschar_t *fnamep = NULL;
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
+ memset(&volSync, 0, sizeof(volSync));
+
/* 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.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseWrite(&dscp->rw);
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
- userp, 0);
+ userp, reqp, 0);
}
lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
cm_scache_t *scp = NULL;
int free_fnamep = FALSE;
+ memset(&volSync, 0, sizeof(volSync));
+
if (fnamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
if (code == 0)
if (code)
goto done;
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ 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.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_dnlcRemove(dscp, cnamep);
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseWrite(&dscp->rw);
int free_oldNamep = FALSE;
cm_scache_t *oldScp = NULL, *newScp = NULL;
+ memset(&volSync, 0, sizeof(volSync));
+
if (cOldNamep == NULL || cNewNamep == NULL ||
cm_ClientStrLen(cOldNamep) == 0 ||
cm_ClientStrLen(cNewNamep) == 0)
} else {
code = 0;
}
+
+ /* Check for RO volume */
+ if (code == 0 &&
+ (oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
+ code = CM_ERROR_READONLY;
+ }
+
if (code)
goto done;
if (oldNamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ, &oldDirOp);
+ code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&oldDirOp, cOldNamep, &oldNamep);
if (code == 0)
}
oneDir = 1;
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
cm_dnlcRemove(oldDscp, cNewNamep);
}
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
if (code != 0)
cm_EndDirOp(&oldDirOp);
if (code == 0) {
- cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &newDirOp);
lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, cNewNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
}
else {
/* lock the new vnode entry first */
- cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &newDirOp);
lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, cNewNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
if (code != 0)
cm_EndDirOp(&newDirOp);
if (code == 0) {
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
- userp, CM_MERGEFLAG_DIROP);
+ userp, reqp, CM_MERGEFLAG_DIROP);
lock_ReleaseWrite(&oldDscp->rw);
if (code == 0 && cm_CheckDirOpForSingleChange(&oldDirOp)) {
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
- userp, CM_MERGEFLAG_DIROP);
+ userp, reqp, CM_MERGEFLAG_DIROP);
lock_ReleaseWrite(&newDscp->rw);
#if 0
AFSVolSync volSync;
afs_uint32 reqflags = reqp->flags;
+ memset(&volSync, 0, sizeof(volSync));
+
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
tfid.Unique = scp->fid.unique;
struct rx_connection * rxconnp;
AFSVolSync volSync;
+ memset(&volSync, 0, sizeof(volSync));
+
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
tfid.Unique = scp->fid.unique;
"cm_Lock Rejecting lock (code = 0x%x)", code);
}
+ /* Convert from would block to lock not granted */
+ if (code == CM_ERROR_WOULDBLOCK)
+ code = CM_ERROR_LOCK_NOT_GRANTED;
+
return code;
}
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 scp->serverLock looked sane, we are going to assume
that we have a valid server lock. */
scp->lockDataVersion = scp->dataVersion;
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)
unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
cm_key_t key,
+ afs_uint32 flags,
cm_user_t *userp,
cm_req_t *reqp)
{
cm_file_lock_t *fileLock;
osi_queue_t *q;
int release_userp = FALSE;
+ int exact_match = !(flags & CM_UNLOCK_FLAG_MATCH_RANGE);
+ int lock_found = 0;
+ LARGE_INTEGER RangeEnd;
osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
- osi_Log3(afsd_logp, "... key <0x%x,0x%x,0x%x>",
- key.process_id, key.session_id, key.file_id);
+ osi_Log4(afsd_logp, "... key <0x%x,0x%x,0x%x> flags 0x%x",
+ key.process_id, key.session_id, key.file_id, flags);
+ if (!exact_match)
+ RangeEnd.QuadPart = LOffset.QuadPart + LLength.QuadPart;
+
+ try_again:
lock_ObtainRead(&cm_scacheLock);
for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
osi_assertx(FALSE, "invalid fid value");
}
#endif
- if (!IS_LOCK_DELETED(fileLock) &&
- cm_KeyEquals(&fileLock->key, &key, 0) &&
- fileLock->range.offset == LOffset.QuadPart &&
- fileLock->range.length == LLength.QuadPart) {
- break;
+ if (exact_match) {
+ if (!IS_LOCK_DELETED(fileLock) &&
+ cm_KeyEquals(&fileLock->key, &key, 0) &&
+ fileLock->range.offset == LOffset.QuadPart &&
+ fileLock->range.length == LLength.QuadPart) {
+ lock_found = 1;
+ break;
+ }
+ } else {
+
+ if (!IS_LOCK_DELETED(fileLock) &&
+ cm_KeyEquals(&fileLock->key, &key, 0) &&
+ fileLock->range.offset >= LOffset.QuadPart &&
+ fileLock->range.offset < RangeEnd.QuadPart &&
+ (fileLock->range.offset + fileLock->range.length) <= RangeEnd.QuadPart) {
+ lock_found = 1;
+ break;
+ }
}
}
if (!q) {
- osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
-
lock_ReleaseRead(&cm_scacheLock);
- /* The lock didn't exist anyway. *shrug* */
- return CM_ERROR_RANGE_NOT_LOCKED;
+ if (lock_found && !exact_match) {
+ code = 0;
+ 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 */
/* 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;
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) {
}
}
- if (release_userp)
+ if (release_userp) {
cm_ReleaseUser(userp);
+ release_userp = FALSE;
+ }
+
+ if (!exact_match)
+ goto try_again; /* might be more than one lock in the range */
done:
}
scp->serverLock = -1;
- scp->lockDataVersion = -1;
+ scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
lock_ReleaseWrite(&cm_scacheLock);
}
struct rx_connection * rxconnp;
cm_scache_t * scp;
+ memset(&volSync, 0, sizeof(volSync));
+
cm_InitReq(&req);
lock_ObtainWrite(&cm_scacheLock);