#include <osi.h>
#include "afsd.h"
+#include "smb.h"
+#include "cm_btree.h"
+
+#include <strsafe.h>
#ifdef DEBUG
extern void afsi_log(char *pattern, ...);
int cm_enableServerLocks = 1;
+int cm_followBackupPath = 0;
+
/*
* Case-folding array. This was constructed by inspecting of SMBtrace output.
* I do not know anything more about it.
}
}
-/* characters that are legal in an 8.3 name */
-/*
- * We used to have 1's for all characters from 128 to 254. But
- * the NT client behaves better if we create an 8.3 name for any
- * name that has a character with the high bit on, and if we
- * delete those characters from 8.3 names. In particular, see
- * Sybase defect 10859.
- */
-char cm_LegalChars[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* return true iff component is a valid 8.3 name */
-int cm_Is8Dot3(char *namep)
-{
- int sawDot = 0;
- unsigned char tc;
- int charCount = 0;
-
- /*
- * can't have a leading dot;
- * special case for . and ..
- */
- if (namep[0] == '.') {
- if (namep[1] == 0)
- return 1;
- if (namep[1] == '.' && namep[2] == 0)
- return 1;
- return 0;
- }
- while (tc = *namep++) {
- if (tc == '.') {
- /* saw another dot */
- if (sawDot) return 0; /* second dot */
- sawDot = 1;
- charCount = 0;
- continue;
- }
- if (cm_LegalChars[tc] == 0)
- return 0;
- charCount++;
- if (!sawDot && charCount > 8)
- /* more than 8 chars in name */
- return 0;
- if (sawDot && charCount > 3)
- /* more than 3 chars in extension */
- return 0;
- }
- return 1;
-}
-
-/*
- * Number unparsing map for generating 8.3 names;
- * The version taken from DFS was on drugs.
- * You can't include '&' and '@' in a file name.
- */
-char cm_8Dot3Mapping[42] =
-{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
- 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
- 'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
-};
-int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
-void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
- char *shortName, char **shortNameEndp)
-{
- char number[12];
- int i, nsize = 0;
- int vnode = ntohl(pfid->vnode);
- char *lastDot;
- int validExtension = 0;
- char tc, *temp;
- const char *name;
-
- /* Unparse the file's vnode number to get a "uniquifier" */
- do {
- number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
- nsize++;
- vnode /= cm_8Dot3MapSize;
- } while (vnode);
-
- /*
- * Look for valid extension. There has to be a dot, and
- * at least one of the characters following has to be legal.
- */
- lastDot = strrchr(longname, '.');
- if (lastDot) {
- temp = lastDot; temp++;
- while (tc = *temp++)
- if (cm_LegalChars[tc])
- break;
- if (tc)
- validExtension = 1;
- }
-
- /* Copy name characters */
- for (i = 0, name = longname;
- i < (7 - nsize) && name != lastDot; ) {
- tc = *name++;
-
- if (tc == 0)
- break;
- if (!cm_LegalChars[tc])
- continue;
- i++;
- *shortName++ = toupper(tc);
- }
-
- /* tilde */
- *shortName++ = '~';
-
- /* Copy uniquifier characters */
- memcpy(shortName, number, nsize);
- shortName += nsize;
-
- if (validExtension) {
- /* Copy extension characters */
- *shortName++ = *lastDot++; /* copy dot */
- for (i = 0, tc = *lastDot++;
- i < 3 && tc;
- tc = *lastDot++) {
- if (cm_LegalChars[tc]) {
- i++;
- *shortName++ = toupper(tc);
- }
- }
- }
-
- /* Trailing null */
- *shortName = 0;
-
- if (shortNameEndp)
- *shortNameEndp = shortName;
-}
/* return success if we can open this file in this mode */
long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
if (openMode == 1 || openMode == 2 || trunc)
rights |= PRSFS_WRITE;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
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
_done:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
cm_lock_data_t **ldpp)
{
long rights;
- long code;
+ long code = 0;
- osi_assert(ldpp != NULL);
+ osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
/* Always allow delete; the RPC will tell us if it's OK */
- if (desiredAccess == DELETE)
- return 0;
-
rights = 0;
- if (desiredAccess & AFS_ACCESS_READ)
+ if (desiredAccess == DELETE)
+ goto done_2;
+
+ if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
/* We used to require PRSFS_WRITE if createDisp was 4
if (desiredAccess & AFS_ACCESS_WRITE)
rights |= PRSFS_WRITE;
- lock_ObtainMutex(&scp->mx);
+ if (desiredAccess & DELETE)
+ rights |= PRSFS_DELETE;
+
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
CM_SCACHESYNC_GETSTATUS
goto _done;
}
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
-
_done:
- lock_ReleaseMutex(&scp->mx);
+ 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;
}
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);
+ lock_ObtainWrite(&scp->rw);
if (*ldpp) {
- lock_ObtainMutex(&scp->mx);
cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
- (*ldpp)->key, userp, reqp);
- lock_ReleaseMutex(&scp->mx);
+ (*ldpp)->key, 0, userp, reqp);
free(*ldpp);
*ldpp = NULL;
}
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+ lock_ReleaseWrite(&scp->rw);
return 0;
}
/*
long code;
osi_hyper_t thyper;
cm_buf_t *bufferp;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
unsigned short *hashTable;
unsigned int i, idx;
int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
+ int releaseLock = 0;
/* First check permissions */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_DELETE,
CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- lock_ReleaseMutex(&scp->mx);
+ if (!code)
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&scp->rw);
if (code)
return code;
return code;
thyper.HighPart = 0; thyper.LowPart = 0;
- lock_ObtainRead(&scp->bufCreateLock);
- code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
+ code = buf_Get(scp, &thyper, reqp, &bufferp);
if (code)
return code;
lock_ObtainMutex(&bufferp->mx);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
+ releaseLock = 1;
while (1) {
code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_READ
| CM_SCACHESYNC_BUFLOCKED);
if (code)
- break;
+ goto done;
if (cm_HaveBuffer(scp, bufferp, 1))
break;
/* otherwise, load the buffer and try again */
lock_ReleaseMutex(&bufferp->mx);
code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainMutex(&bufferp->mx);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (code)
- break;
+ goto done;
}
+ lock_ReleaseWrite(&scp->rw);
+ releaseLock = 0;
+
/* We try to determine emptiness without looking beyond the first page,
* and without assuming "." and ".." are present and are on the first
* page (though these assumptions might, after all, be reasonable).
done:
lock_ReleaseMutex(&bufferp->mx);
buf_Release(bufferp);
- lock_ReleaseMutex(&scp->mx);
+ if (releaseLock)
+ lock_ReleaseWrite(&scp->rw);
return code;
}
* 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,
- cm_scache_t **retscp)
+ osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
+ cm_scache_t **retscp)
{
char *tp;
long code;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
cm_buf_t *bufferp;
long temp;
osi_hyper_t dirLength;
int numDirChunks; /* # of 32 byte dir chunks in this entry */
/* get the directory size */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ if (code)
return code;
- }
- if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
- lock_ReleaseMutex(&scp->mx);
+ if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
return CM_ERROR_NOTDIR;
- }
if (retscp) /* if this is a lookup call */
{
cm_lookupSearch_t* sp = parmp;
+ if (
#ifdef AFS_FREELANCE_CLIENT
/* Freelance entries never end up in the DNLC because they
* do not have an associated cm_server_t
*/
- if ( !(cm_freelanceEnabled &&
+ !(cm_freelanceEnabled &&
sp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
- sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) )
-#endif /* AFS_FREELANCE_CLIENT */
- {
- int casefold = sp->caseFold;
- sp->caseFold = 0; /* we have a strong preference for exact matches */
- if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
+ sp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+#else /* !AFS_FREELANCE_CLIENT */
+ TRUE
+#endif
+ )
{
+ int casefold = sp->caseFold;
+ sp->caseFold = 0; /* we have a strong preference for exact matches */
+ if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
+ {
+ sp->caseFold = casefold;
+ return 0;
+ }
sp->caseFold = casefold;
- lock_ReleaseMutex(&scp->mx);
- return 0;
}
- 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.
+ */
+ if (funcp != (cm_DirFuncp_t)cm_BPlusDirFoo)
+ {
+ cm_dirOp_t dirop;
+#ifdef USE_BPLUS
+ int usedBplus = 0;
+#endif
+
+ code = ENOENT;
+
+ 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
+#endif
+ code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
+
+ cm_EndDirOp(&dirop);
+ }
+
+ if (code == 0) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = TRUE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+#ifdef USE_BPLUS
+ if (usedBplus) {
+ if (sp->caseFold && code == CM_ERROR_INEXACT_MATCH) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = FALSE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+
+ return CM_ERROR_BPLUS_NOMATCH;
+ }
+#endif
+ }
}
/*
*/
dirLength = scp->length;
- lock_ReleaseMutex(&scp->mx);
-
bufferp = NULL;
bufferOffset.LowPart = bufferOffset.HighPart = 0;
if (startOffsetp)
bufferp = NULL;
}
- lock_ObtainRead(&scp->bufCreateLock);
- code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
+ code = buf_Get(scp, &thyper, reqp, &bufferp);
if (code) {
/* if buf_Get() fails we do not have a buffer object to lock */
bufferp = NULL;
break;
}
-#ifdef AFSIFS
- /* for the IFS version, we bulkstat the dirents because this
- routine is used in place of smb_ReceiveCoreSearchDir. our
- other option is to modify smb_ReceiveCoreSearchDir itself,
- but this seems to be the proper use for cm_ApplyDir. */
- lock_ObtainMutex(&scp->mx);
- if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
- && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
- {
- scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
- code = cm_TryBulkStat(scp, &thyper, userp, reqp);
- scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
- scp->bulkStatProgress = thyper;
- }
- lock_ReleaseMutex(&scp->mx);
-#endif
-
lock_ObtainMutex(&bufferp->mx);
bufferOffset = thyper;
/* now get the data in the cache */
while (1) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, bufferp, userp, reqp,
PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_READ
| CM_SCACHESYNC_BUFLOCKED);
if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
if (cm_HaveBuffer(scp, bufferp, 1)) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
lock_ReleaseMutex(&bufferp->mx);
code = cm_GetBuffer(scp, bufferp, NULL, userp,
reqp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainMutex(&bufferp->mx);
if (code)
break;
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;
+ 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.
return code;
}
-int cm_NoneUpper(char *s)
+int cm_NoneUpper(normchar_t *s)
{
- char c;
+ normchar_t c;
while (c = *s++)
if (c >= 'A' && c <= 'Z')
return 0;
return 1;
}
-int cm_NoneLower(char *s)
+int cm_NoneLower(normchar_t *s)
{
- char c;
+ normchar_t c;
while (c = *s++)
if (c >= 'a' && c <= 'z')
return 0;
}
long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
- osi_hyper_t *offp)
+ osi_hyper_t *offp)
{
cm_lookupSearch_t *sp;
int match;
- char shortName[13];
- char *matchName;
+ normchar_t matchName[MAX_PATH];
+ int looking_for_short_name = FALSE;
sp = (cm_lookupSearch_t *) rockp;
- matchName = dep->name;
+ if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+ /* Can't normalize FS string. */
+ return 0;
+ }
+
if (sp->caseFold)
- match = cm_stricmp(matchName, sp->searchNamep);
+ match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
else
- match = strcmp(matchName, sp->searchNamep);
+ match = cm_NormStrCmp(matchName, sp->nsearchNamep);
if (match != 0
- && sp->hasTilde
- && !cm_Is8Dot3(dep->name)) {
- matchName = shortName;
- cm_Gen8Dot3Name(dep, shortName, NULL);
+ && sp->hasTilde
+ && !cm_Is8Dot3(matchName)) {
+
+ cm_Gen8Dot3NameInt(dep->name, &dep->fid, matchName, NULL);
if (sp->caseFold)
- match = cm_stricmp(matchName, sp->searchNamep);
+ match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
else
- match = strcmp(matchName, sp->searchNamep);
+ match = cm_NormStrCmp(matchName, sp->nsearchNamep);
+ looking_for_short_name = TRUE;
}
if (match != 0)
if (!sp->caseFold)
sp->ExactFound = 1;
- if (!sp->caseFold || matchName == shortName) {
- sp->fid.vnode = ntohl(dep->fid.vnode);
- sp->fid.unique = ntohl(dep->fid.unique);
+ if (!sp->caseFold || looking_for_short_name) {
+ cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
return CM_ERROR_STOPNOW;
}
*/
/* Exact matches are the best. */
- match = strcmp(matchName, sp->searchNamep);
+ match = cm_NormStrCmp(matchName, sp->nsearchNamep);
if (match == 0) {
sp->ExactFound = 1;
- sp->fid.vnode = ntohl(dep->fid.vnode);
- sp->fid.unique = ntohl(dep->fid.unique);
+ cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
return CM_ERROR_STOPNOW;
}
sp->NCfound = 1;
inexact:
- sp->fid.vnode = ntohl(dep->fid.vnode);
- sp->fid.unique = ntohl(dep->fid.unique);
+ 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 locked scp, and returns with locked scp.
+ * called with write locked scp, and returns with locked scp.
*/
long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
{
long code;
- cm_buf_t *bufp;
+ cm_buf_t *bufp = NULL;
osi_hyper_t thyper;
int tlen;
if (scp->mountPointStringp[0])
return 0;
- /* otherwise, we have to read it in */
- lock_ReleaseMutex(&scp->mx);
-
- lock_ObtainRead(&scp->bufCreateLock);
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(scp, &thyper, &bufp);
- lock_ReleaseRead(&scp->bufCreateLock);
+#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 */
+ {
+ /* otherwise, we have to read it in */
+ lock_ReleaseWrite(&scp->rw);
- lock_ObtainMutex(&scp->mx);
- if (code)
- return code;
+ thyper.LowPart = thyper.HighPart = 0;
+ code = buf_Get(scp, &thyper, reqp, &bufp);
- while (1) {
- code = cm_SyncOp(scp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
+ lock_ObtainWrite(&scp->rw);
if (code)
- goto done;
+ return code;
- cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+ while (1) {
+ code = cm_SyncOp(scp, bufp, userp, reqp, 0,
+ CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code)
+ goto done;
- if (cm_HaveBuffer(scp, bufp, 0))
- break;
+ cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
- /* otherwise load buffer */
- code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
- if (code)
+ 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;
- }
- /* 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;
- }
+ /* 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);
+ /* 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->mountPointStringp[tlen-1] = 0;
- code = 0;
+ /* 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:
- if (bufp)
- buf_Release(bufp);
+ done:
+ if (bufp)
+ buf_Release(bufp);
+ }
return code;
}
/* called with a locked scp and chases the mount point, yielding outScpp.
- * scp remains locked, just for simplicity of describing the interface.
+ * scp remains write locked, just for simplicity of describing the interface.
*/
long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
cm_req_t *reqp, cm_scache_t **outScpp)
{
- char *cellNamep;
- char *volNamep;
- int tlen;
- long code;
- char *cp;
- char *mpNamep;
+ fschar_t *cellNamep = NULL;
+ fschar_t *volNamep = NULL;
+ afs_uint32 code;
+ fschar_t *cp;
+ fschar_t *mpNamep;
cm_volume_t *volp = NULL;
cm_cell_t *cellp;
- char mtType;
+ fschar_t mtType;
cm_fid_t tfid;
size_t vnLength;
- int type;
+ int targetType;
+
+ *outScpp = NULL;
if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
tfid = scp->mountRootFid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
code = cm_GetSCache(&tfid, outScpp, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
return code;
}
mpNamep = scp->mountPointStringp;
if (!mpNamep[0])
return CM_ERROR_NOSUCHPATH;
- tlen = (int)strlen(scp->mountPointStringp);
mtType = *scp->mountPointStringp;
- cellNamep = malloc(tlen);
- volNamep = malloc(tlen);
- cp = strrchr(mpNamep, ':');
+ cp = cm_FsStrChr(mpNamep, _FS(':'));
if (cp) {
/* cellular mount point */
- memset(cellNamep, 0, tlen);
- strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
- strcpy(volNamep, cp+1);
+ cellNamep = (fschar_t *)malloc((cp - mpNamep) * sizeof(fschar_t));
+ cm_FsStrCpyN(cellNamep, cp - mpNamep, mpNamep + 1, cp - mpNamep - 1);
+ volNamep = cm_FsStrDup(cp+1);
+
/* now look up the cell */
+ lock_ReleaseWrite(&scp->rw);
cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
- }
- else {
+ lock_ObtainWrite(&scp->rw);
+ } else {
/* normal mt pt */
- strcpy(volNamep, mpNamep+1);
+ volNamep = cm_FsStrDup(mpNamep + 1);
- cellp = cm_FindCellByID(scp->fid.cell);
+#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) {
goto done;
}
- vnLength = strlen(volNamep);
- if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
- type = BACKVOL;
+ vnLength = cm_FsStrLen(volNamep);
+ if (vnLength >= 8 && cm_FsStrCmp(volNamep + vnLength - 7, ".backup") == 0)
+ targetType = BACKVOL;
else if (vnLength >= 10
- && strcmp(volNamep + vnLength - 9, ".readonly") == 0)
- type = ROVOL;
+ && cm_FsStrCmp(volNamep + vnLength - 9, ".readonly") == 0)
+ targetType = ROVOL;
else
- type = RWVOL;
+ targetType = RWVOL;
/* check for backups within backups */
- if (type == BACKVOL
+ if (targetType == BACKVOL
&& (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
== CM_SCACHEFLAG_RO) {
code = CM_ERROR_NOSUCHVOLUME;
}
/* now we need to get the volume */
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
if (cm_VolNameIsID(volNamep)) {
- code = cm_GetVolumeByID(cellp, atoi(volNamep), userp, reqp,
+ code = cm_FindVolumeByID(cellp, atoi(volNamep), userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
} else {
- code = cm_GetVolumeByName(cellp, volNamep, userp, reqp,
+ code = cm_FindVolumeByName(cellp, volNamep, userp, reqp,
CM_GETVOL_FLAG_CREATE, &volp);
}
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (code == 0) {
- /* save the parent of the volume root for this is the
- * place where the volume is mounted and we must remember
- * this in the volume structure rather than just in the
- * scache entry lest the scache entry gets recycled
- * (defect 11489)
- */
- lock_ObtainMutex(&volp->mx);
- volp->dotdotFid = dscp->fid;
- lock_ReleaseMutex(&volp->mx);
+ afs_uint32 cell, volume;
+ cm_vol_state_t *statep;
- scp->mountRootFid.cell = cellp->cellID;
+ cell = cellp->cellID;
+
+ /* if the mt pt originates in a .backup volume (not a .readonly)
+ * and FollowBackupPath is active, and if there is a .backup
+ * volume for the target, then use the .backup of the target
+ * instead of the read-write.
+ */
+ if (cm_followBackupPath &&
+ volp->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 type '#' mount point, use
+ * target, and if this is a targetType '#' mount point, use
* the read-only, otherwise use the one specified.
*/
- if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
- && volp->ro.ID != 0 && type == RWVOL)
- type = ROVOL;
- if (type == ROVOL)
- scp->mountRootFid.volume = volp->ro.ID;
- else if (type == BACKVOL)
- scp->mountRootFid.volume = volp->bk.ID;
- else
- scp->mountRootFid.volume = volp->rw.ID;
+ else if (mtType == '#' && targetType == RWVOL &&
+ (scp->flags & CM_SCACHEFLAG_PURERO) &&
+ volp->vol[ROVOL].ID != 0) {
+ targetType = ROVOL;
+ }
+
+ lock_ObtainWrite(&volp->rw);
+ statep = cm_VolumeStateByType(volp, targetType);
+ volume = statep->ID;
+ statep->dotdotFid = dscp->fid;
+ lock_ReleaseWrite(&volp->rw);
/* the rest of the fid is a magic number */
- scp->mountRootFid.vnode = 1;
- scp->mountRootFid.unique = 1;
+ cm_SetFid(&scp->mountRootFid, cell, volume, 1, 1);
scp->mountRootGen = cm_data.mountRootGen;
tfid = scp->mountRootFid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
code = cm_GetSCache(&tfid, outScpp, userp, reqp);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
}
done:
if (volp)
cm_PutVolume(volp);
- free(cellNamep);
- free(volNamep);
+ if (cellNamep)
+ free(cellNamep);
+ if (volNamep)
+ free(volNamep);
return code;
}
-long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
- cm_req_t *reqp, cm_scache_t **outpScpp)
+long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
+ cm_req_t *reqp, cm_scache_t **outScpp)
{
long code;
int dnlcHit = 1; /* did we hit in the dnlc? yes, we did */
cm_scache_t *mountedScp;
cm_lookupSearch_t rock;
int getroot;
+ normchar_t *nnamep = NULL;
+ fschar_t *fnamep = NULL;
+ size_t fnlen;
+
+ *outScpp = NULL;
+
+ memset(&rock, 0, sizeof(rock));
if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
- && strcmp(namep, "..") == 0) {
+ && cm_ClientStrCmp(cnamep, _C("..")) == 0) {
if (dscp->dotdotFid.volume == 0)
return CM_ERROR_NOSUCHVOLUME;
rock.fid = dscp->dotdotFid;
goto haveFid;
- } else if (strcmp(namep, ".") == 0) {
+ } else if (cm_ClientStrCmp(cnamep, _C(".")) == 0) {
rock.fid = dscp->fid;
goto haveFid;
}
- memset(&rock, 0, sizeof(rock));
+ nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+ if (!nnamep) {
+ code = CM_ERROR_NOSUCHFILE;
+ goto done;
+ }
+ fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+ if (!fnamep) {
+ code = CM_ERROR_NOSUCHFILE;
+ 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
+ not. */
+
+ cm_dirOp_t dirop;
+#ifdef USE_BPLUS
+ int usedBplus = 0;
+#endif
+
+ 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);
+ if (code != EINVAL)
+ usedBplus = 1;
+ else
+#endif
+ code = cm_DirLookup(&dirop, fnamep, &rock.fid);
+
+ cm_EndDirOp(&dirop);
+ }
+
+ if (code == 0) {
+ /* found it */
+ rock.found = TRUE;
+ goto haveFid;
+ }
+#ifdef USE_BPLUS
+ if (usedBplus) {
+ if (code == CM_ERROR_INEXACT_MATCH && (flags & CM_FLAG_CASEFOLD)) {
+ /* found it */
+ code = 0;
+ rock.found = TRUE;
+ goto haveFid;
+ }
+
+ code = CM_ERROR_BPLUS_NOMATCH;
+ goto notfound;
+ }
+#endif
+ }
+
rock.fid.cell = dscp->fid.cell;
rock.fid.volume = dscp->fid.volume;
- rock.searchNamep = namep;
+ rock.searchNamep = fnamep;
+ rock.nsearchNamep = nnamep;
rock.caseFold = (flags & CM_FLAG_CASEFOLD);
- rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
+ rock.hasTilde = ((cm_ClientStrChr(cnamep, '~') != NULL) ? 1 : 0);
/* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
code = cm_ApplyDir(dscp, cm_LookupSearchProc, &rock, NULL, userp, reqp,
- (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
+ (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
/* code == 0 means we fell off the end of the dir, while stopnow means
* 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
*/
if (code == CM_ERROR_NOTDIR) {
if (flags & CM_FLAG_CHECKPATH)
- return CM_ERROR_NOSUCHPATH;
+ code = CM_ERROR_NOSUCHPATH;
else
- return CM_ERROR_NOSUCHFILE;
+ code = CM_ERROR_NOSUCHFILE;
}
- return code;
+ goto done;
}
+notfound:
getroot = (dscp==cm_data.rootSCachep) ;
if (!rock.found) {
if (!cm_freelanceEnabled || !getroot) {
if (flags & CM_FLAG_CHECKPATH)
- return CM_ERROR_NOSUCHPATH;
+ code = CM_ERROR_NOSUCHPATH;
else
- return CM_ERROR_NOSUCHFILE;
+ code = CM_ERROR_NOSUCHFILE;
+ goto done;
}
- else { /* nonexistent dir on freelance root, so add it */
- char fullname[200] = ".";
+ else if (!cm_ClientStrChr(cnamep, '#') &&
+ !cm_ClientStrChr(cnamep, '%') &&
+ cm_ClientStrCmpI(cnamep, _C("srvsvc")) &&
+ cm_ClientStrCmpI(cnamep, _C("wkssvc")) &&
+ 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_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
+ * new value automatically.
+ */
- osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s",
- osi_LogSaveString(afsd_logp,namep));
- if (namep[0] == '.') {
- if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
+ 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 ( stricmp(&namep[1], &fullname[1]) )
- code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, &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:
+ * . 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(namep, fullname, CM_FLAG_CREATE)) {
+ if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
found = 1;
- if ( stricmp(namep, fullname) )
- code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, 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:
+ * . 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)
- return CM_ERROR_NOSUCHPATH;
+ code = CM_ERROR_NOSUCHPATH;
else
- return CM_ERROR_NOSUCHFILE;
+ code = CM_ERROR_NOSUCHFILE;
+ goto done;
}
tscp = NULL; /* to force call of cm_GetSCache */
+ } else {
+ if (flags & CM_FLAG_CHECKPATH)
+ code = CM_ERROR_NOSUCHPATH;
+ else
+ code = CM_ERROR_NOSUCHFILE;
+ goto done;
}
}
- haveFid:
+ haveFid:
if ( !tscp ) /* we did not find it in the dnlc */
{
- dnlcHit = 0;
+ dnlcHit = 0;
code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
if (code)
- return code;
- }
+ goto done;
+ }
/* tscp is now held */
- lock_ObtainMutex(&tscp->mx);
+ lock_ObtainWrite(&tscp->rw);
code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
- return code;
+ goto done;
}
cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
/* tscp is now locked */
code = cm_ReadMountPoint(tscp, userp, reqp);
if (code == 0)
code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
- &mountedScp);
- lock_ReleaseMutex(&tscp->mx);
+ &mountedScp);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
- if (code) {
- return code;
- }
+ if (code)
+ goto done;
+
tscp = mountedScp;
}
else {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
}
/* copy back pointer */
- *outpScpp = tscp;
+ *outScpp = tscp;
/* insert scache in dnlc */
if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
/* lock the directory entry to prevent racing callback revokes */
- lock_ObtainMutex(&dscp->mx);
- if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
- cm_dnlcEnter(dscp, namep, tscp);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ObtainRead(&dscp->rw);
+ if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 ) {
+ /* TODO: reuse nnamep from above */
+ if (nnamep)
+ free(nnamep);
+ nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+ if (nnamep)
+ cm_dnlcEnter(dscp, nnamep, tscp);
+ }
+ lock_ReleaseRead(&dscp->rw);
}
/* and return */
- return 0;
+ done:
+ if (fnamep) {
+ free (fnamep);
+ fnamep = NULL;
+ }
+ if (nnamep) {
+ free (nnamep);
+ nnamep = NULL;
+ }
+
+ return code;
}
-int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
+int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
{
- char *tp;
+ clientchar_t *tp;
int prefixCount;
- tp = strrchr(inp, '@');
+ tp = cm_ClientStrRChr(inp, '@');
if (tp == NULL)
return 0; /* no @sys */
- if (strcmp(tp, "@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)
return 1;
- if (index >= MAXNUMSYSNAMES)
+ if (index >= cm_sysNameCount)
return -1;
/* otherwise generate the properly expanded @sys name */
prefixCount = (int)(tp - inp);
- strncpy(outp, inp, prefixCount); /* copy out "a." from "a.@sys" */
+ cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount); /* copy out "a." from "a.@sys" */
outp[prefixCount] = 0; /* null terminate the "a." */
- strcat(outp, cm_sysNameList[index]);/* append i386_nt40 */
+ cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
return 1;
}
+long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
+ cm_req_t *reqp, cm_scache_t ** outScpp)
+{
+ afs_uint32 code = 0;
+ fschar_t cellName[CELL_MAXNAMELEN];
+ fschar_t volumeName[VL_MAXNAMELEN];
+ size_t len;
+ fschar_t * cp;
+ fschar_t * tp;
+ fschar_t * fnamep = NULL;
+
+ cm_cell_t * cellp = NULL;
+ cm_volume_t * volp = NULL;
+ cm_fid_t fid;
+ afs_uint32 volume;
+ int volType;
+ int mountType = RWVOL;
+
+ osi_Log1(afsd_logp, "cm_EvaluateVolumeReference for string [%S]",
+ osi_LogSaveClientString(afsd_logp, namep));
+
+ if (cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) != 0) {
+ goto _exit_invalid_path;
+ }
+
+ /* namep is assumed to look like the following:
+
+ @vol:<cellname>%<volume>\0
+ or
+ @vol:<cellname>#<volume>\0
+
+ */
+
+ fnamep = cm_ClientStringToFsStringAlloc(namep, -1, NULL);
+ cp = fnamep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
+ tp = cm_FsStrChr(cp, '%');
+ if (tp == NULL)
+ tp = cm_FsStrChr(cp, '#');
+ if (tp == NULL ||
+ (len = tp - cp) == 0 ||
+ len > CELL_MAXNAMELEN)
+ goto _exit_invalid_path;
+ cm_FsStrCpyN(cellName, lengthof(cellName), cp, len);
+
+ if (*tp == '#')
+ mountType = ROVOL;
+
+ cp = tp+1; /* cp now points to volume, supposedly */
+ cm_FsStrCpy(volumeName, lengthof(volumeName), cp);
+
+ /* OK, now we have the cell and the volume */
+ osi_Log2(afsd_logp, " Found cell [%s] and volume [%s]",
+ osi_LogSaveFsString(afsd_logp, cellName),
+ osi_LogSaveFsString(afsd_logp, volumeName));
+
+ cellp = cm_GetCell(cellName, CM_FLAG_CREATE);
+ if (cellp == NULL) {
+ goto _exit_invalid_path;
+ }
+
+ len = cm_FsStrLen(volumeName);
+ if (len >= 8 && cm_FsStrCmp(volumeName + len - 7, ".backup") == 0)
+ volType = BACKVOL;
+ else if (len >= 10 &&
+ cm_FsStrCmp(volumeName + len - 9, ".readonly") == 0)
+ volType = ROVOL;
+ else
+ volType = RWVOL;
+
+ if (cm_VolNameIsID(volumeName)) {
+ code = cm_FindVolumeByID(cellp, atoi(volumeName), userp, reqp,
+ CM_GETVOL_FLAG_CREATE, &volp);
+ } else {
+ code = cm_FindVolumeByName(cellp, volumeName, userp, reqp,
+ CM_GETVOL_FLAG_CREATE, &volp);
+ }
+
+ if (code != 0)
+ goto _exit_cleanup;
+
+ if (volType == BACKVOL)
+ volume = volp->vol[BACKVOL].ID;
+ else if (volType == ROVOL ||
+ (volType == RWVOL && mountType == ROVOL && volp->vol[ROVOL].ID != 0))
+ volume = volp->vol[ROVOL].ID;
+ else
+ volume = volp->vol[RWVOL].ID;
+
+ cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
+
+ code = cm_GetSCache(&fid, outScpp, userp, reqp);
+
+ _exit_cleanup:
+ if (fnamep)
+ free(fnamep);
+
+ if (volp)
+ cm_PutVolume(volp);
+
+ if (code == 0)
+ return code;
+
+ _exit_invalid_path:
+ if (flags & CM_FLAG_CHECKPATH)
+ return CM_ERROR_NOSUCHPATH;
+ else
+ return CM_ERROR_NOSUCHFILE;
+}
+
#ifdef DEBUG_REFCOUNT
-long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
- cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
+long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
+ cm_req_t *reqp, cm_scache_t **outScpp, char * file, long line)
#else
-long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
- cm_req_t *reqp, cm_scache_t **outpScpp)
+long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
+ cm_req_t *reqp, cm_scache_t **outScpp)
#endif
{
long code;
- char tname[256];
+ clientchar_t tname[AFSPATHMAX];
int sysNameIndex = 0;
cm_scache_t *scp = NULL;
osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
#endif
- if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
+ if ( cm_ClientStrCmpI(namep,_C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ) {
if (flags & CM_FLAG_CHECKPATH)
return CM_ERROR_NOSUCHPATH;
else
return CM_ERROR_NOSUCHFILE;
}
- for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
- code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
- if (code > 0) {
- code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
+ if (dscp == cm_data.rootSCachep &&
+ cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
+ return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
+ }
+
+ if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
+ for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
+ code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
+ if (code > 0) {
+ code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
#ifdef DEBUG_REFCOUNT
- afsi_log("%s:%d cm_LookupInternal (1) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
- osi_Log3(afsd_logp, "cm_LookupInternal (1) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+ afsi_log("%s:%d cm_LookupInternal (1) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+ osi_Log3(afsd_logp, "cm_LookupInternal (1) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
#endif
- if (code == 0) {
- *outpScpp = scp;
- return 0;
- }
- if (scp) {
- cm_ReleaseSCache(scp);
- scp = NULL;
- }
- } else {
- code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
+ if (code == 0) {
+ *outScpp = scp;
+ return 0;
+ }
+ if (scp) {
+ cm_ReleaseSCache(scp);
+ scp = NULL;
+ }
+ } else {
+ code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
#ifdef DEBUG_REFCOUNT
- afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
- osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+ afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+ osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
#endif
- *outpScpp = scp;
- return code;
+ *outScpp = scp;
+ return code;
+ }
}
+ } else {
+ code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
+#ifdef DEBUG_REFCOUNT
+ afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+ osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+#endif
+ *outScpp = scp;
+ return code;
}
/* None of the possible sysName expansions could be found */
return CM_ERROR_NOSUCHFILE;
}
-long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
+/*! \brief Unlink a file name
+
+ Encapsulates a call to RXAFS_RemoveFile().
+
+ \param[in] dscp cm_scache_t pointing at the directory containing the
+ name to be unlinked.
+
+ \param[in] fnamep Original name to be unlinked. This is the
+ name that will be passed into the RXAFS_RemoveFile() call.
+ This parameter is optional. If not provided, the value will
+ be looked up.
+
+ \param[in] came Client name to be unlinked. This name will be used
+ to update the local directory caches.
+
+ \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)
{
long code;
cm_conn_t *connp;
int sflags;
AFSFetchStatus newDirStatus;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ cm_dirOp_t dirop;
+ 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,
+ CM_DIROP_FLAG_NONE, &dirop);
+ if (code == 0) {
+ code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+ if (code == 0)
+ free_fnamep = TRUE;
+ cm_EndDirOp(&dirop);
+ }
+#endif
+ if (code)
+ goto done;
+ }
#ifdef AFS_FREELANCE_CLIENT
if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
/* deleting a mount point from the root dir. */
- code = cm_FreelanceRemoveMount(namep);
- return code;
+ code = cm_FreelanceRemoveMount(fnamep);
+ goto done;
}
#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 */
- lock_ObtainMutex(&dscp->mx);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &dirop);
+
+ lock_ObtainWrite(&dscp->rw);
sflags = CM_SCACHESYNC_STOREDATA;
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
- lock_ReleaseMutex(&dscp->mx);
- if (code)
- return code;
+ lock_ReleaseWrite(&dscp->rw);
+ if (code) {
+ cm_EndDirOp(&dirop);
+ goto done;
+ }
/* make the RPC */
afsFid.Volume = dscp->fid.volume;
osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
- if (code)
+ if (code)
continue;
- callp = cm_GetRxConn(connp);
- code = RXAFS_RemoveFile(callp, &afsFid, namep,
- &newDirStatus, &volSync);
- rx_PutConnection(callp);
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_RemoveFile(rxconnp, &afsFid, fnamep,
+ &newDirStatus, &volSync);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
code = cm_MapRPCError(code, reqp);
else
osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
- lock_ObtainMutex(&dscp->mx);
- cm_dnlcRemove(dscp, namep);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
+ cm_dnlcRemove(dscp, cnamep);
cm_SyncOpDone(dscp, NULL, sflags);
- if (code == 0)
- cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
- else if (code == CM_ERROR_NOSUCHFILE) {
+ if (code == 0) {
+ cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 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_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
+ cm_DirDeleteEntry(&dirop, fnamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, cnamep);
+#endif
+ }
+ cm_EndDirOp(&dirop);
+
+ if (scp) {
+ cm_ReleaseSCache(scp);
+ if (code == 0) {
+ lock_ObtainWrite(&scp->rw);
+ if (--scp->linkCount == 0)
+ scp->flags |= CM_SCACHEFLAG_DELETED;
+ cm_DiscardSCache(scp);
+ lock_ReleaseWrite(&scp->rw);
+ }
+ }
+
+ done:
+ if (free_fnamep)
+ free(fnamep);
return code;
}
-/* called with a locked vnode, and fills in the link info.
- * returns this the vnode still locked.
+/* called with a write locked vnode, and fills in the link info.
+ * returns this the vnode still write locked.
*/
long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
{
long temp;
osi_hyper_t thyper;
- lock_AssertMutex(&linkScp->mx);
+ lock_AssertWrite(&linkScp->rw);
if (!linkScp->mountPointStringp[0]) {
- /* read the link data */
- lock_ReleaseMutex(&linkScp->mx);
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(linkScp, &thyper, &bufp);
- lock_ObtainMutex(&linkScp->mx);
- 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);
+
+#ifdef AFS_FREELANCE_CLIENT
+ /* File servers do not have data for freelance entries */
+ if (cm_freelanceEnabled &&
+ linkScp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ linkScp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ code = cm_FreelanceFetchMountPointString(linkScp);
+ } 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;
- }
- cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+ 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;
+ if (cm_HaveBuffer(linkScp, bufp, 0))
+ break;
- code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
- if (code) {
+ 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);
- return code;
+ return CM_ERROR_TOOBIG;
+ }
+
+ /* 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 */
}
- } /* 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);
- return CM_ERROR_TOOBIG;
}
+
+ if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
+ linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- /* 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);
} /* don't have sym link contents cached */
return 0;
* other than the directory containing the symbolic link, then the new root is
* returned in *newRootScpp, otherwise a null is returned there.
*/
-long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
- cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
- cm_user_t *userp, cm_req_t *reqp)
+long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
+ cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
+ cm_user_t *userp, cm_req_t *reqp)
{
long code = 0;
long len;
- char *linkp;
+ fschar_t *linkp;
cm_space_t *tsp;
- lock_ObtainMutex(&linkScp->mx);
+ *newRootScpp = NULL;
+ *newSpaceBufferp = NULL;
+
+ lock_ObtainWrite(&linkScp->rw);
code = cm_HandleLink(linkScp, userp, reqp);
- if (code)
+ if (code)
goto done;
/* if we may overflow the buffer, bail out; buffer is signficantly
* bigger than max path length, so we don't really have to worry about
* being a little conservative here.
*/
- if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
- >= CM_UTILS_SPACESIZE)
- return CM_ERROR_TOOBIG;
+ if (cm_FsStrLen(linkScp->mountPointStringp) + cm_FsStrLen(pathSuffixp) + 2
+ >= CM_UTILS_SPACESIZE) {
+ code = CM_ERROR_TOOBIG;
+ goto done;
+ }
tsp = cm_GetSpace();
linkp = linkScp->mountPointStringp;
if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
if (strlen(linkp) > cm_mountRootLen)
- strcpy(tsp->data, linkp+cm_mountRootLen+1);
+ 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 (strnicmp(p, "all", 3) == 0)
p += 4;
- strcpy(tsp->data, p);
+ StringCbCopyA(tsp->data, sizeof(tsp->data), p);
for (p = tsp->data; *p; p++) {
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;
- strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
+ StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
code = CM_ERROR_PATH_NOT_COVERED;
}
- } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
+ } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
+ !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
+ StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
code = CM_ERROR_PATH_NOT_COVERED;
} else if (*linkp == '\\' || *linkp == '/') {
#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 */
- strcpy(tsp->data, linkp+1);
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ StringCchCopyA(tsp->data,lengthof(tsp->data), linkp+1);
+ *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
*/
linkScp->fileType = CM_SCACHETYPE_INVALID;
- strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
+ StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
code = CM_ERROR_NOSUCHPATH;
#endif
} else {
/* a relative link */
- strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
+ StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
}
if (pathSuffixp[0] != 0) { /* if suffix string is non-null */
- strcat(tsp->data, "\\");
- strcat(tsp->data, pathSuffixp);
+ StringCchCatA(tsp->data,lengthof(tsp->data), "\\");
+ StringCchCatA(tsp->data,lengthof(tsp->data), pathSuffixp);
}
- *newSpaceBufferp = tsp;
- done:
- lock_ReleaseMutex(&linkScp->mx);
+ if (code == 0) {
+ clientchar_t * cpath = cm_FsStringToClientStringAlloc(tsp->data, -1, NULL);
+ if (cpath != NULL) {
+ cm_ClientStrCpy(tsp->wdata, lengthof(tsp->wdata), cpath);
+ free(cpath);
+ *newSpaceBufferp = tsp;
+ } else {
+ code = CM_ERROR_NOSUCHPATH;
+ }
+ }
+
+ if (code != 0) {
+ cm_FreeSpace(tsp);
+
+ if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp) {
+ cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+ }
+ }
+
+ done:
+ lock_ReleaseWrite(&linkScp->rw);
return code;
}
#ifdef DEBUG_REFCOUNT
-long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
- cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp,
- char * file, long line)
+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,
+ char * file, long line)
#else
-long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
- cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
+long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
+ cm_user_t *userp, clientchar_t *tidPathp,
+ cm_req_t *reqp, cm_scache_t **outScpp)
#endif
{
long code;
- char *tp; /* ptr moving through input buffer */
- char tc; /* temp char */
+ clientchar_t *tp; /* ptr moving through input buffer */
+ clientchar_t tc; /* temp char */
int haveComponent; /* has new component started? */
- char component[256]; /* this is the new component */
- char *cp; /* component name being assembled */
+ clientchar_t component[AFSPATHMAX]; /* this is the new component */
+ clientchar_t *cp; /* component name being assembled */
cm_scache_t *tscp; /* current location in the hierarchy */
cm_scache_t *nscp; /* next dude down */
cm_scache_t *dirScp; /* last dir we searched */
cm_space_t *psp; /* space for current path, if we've hit
* any symlinks */
cm_space_t *tempsp; /* temp vbl */
- char *restp; /* rest of the pathname to interpret */
+ clientchar_t *restp; /* rest of the pathname to interpret */
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;
+
+ *outScpp = NULL;
#ifdef DEBUG_REFCOUNT
afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
- osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
- rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>",
- flags);
+ 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>",
+ flags);
#endif
tp = tidPathp;
phase = 2;
}
if (tp == NULL) {
- tp = "";
+ tp = _C("");
}
haveComponent = 0;
psp = NULL;
if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
extraFlag = CM_FLAG_NOMOUNTCHASE;
code = cm_Lookup(tscp, component,
- flags | extraFlag,
- userp, reqp, &nscp);
- if (code) {
+ 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
+ * might have been symlinks or mount points or
+ * both that were crossed.
+ */
+ for ( i=fid_count-1; i>=0; i--) {
+ if (!cm_FidCmp(&nscp->fid, &fids[i]))
+ break;
+ }
+ fid_count = i+1;
+ } else {
+ /* add the new fid to the list */
+ 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) {
cm_ReleaseSCache(tscp);
if (dirScp)
cm_ReleaseSCache(dirScp);
if (psp)
cm_FreeSpace(psp);
- if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK) {
+ if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
+ tscp->fileType == CM_SCACHETYPE_SYMLINK) {
osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
return CM_ERROR_NOSUCHPATH;
} else {
osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
return code;
}
- }
+ }
+
haveComponent = 0; /* component done */
if (dirScp)
cm_ReleaseSCache(dirScp);
break;
}
- /* now, if tscp is a symlink, we should follow
- * it and assemble the path again.
+ /* now, if tscp is a symlink, we should follow it and
+ * assemble the path again.
*/
- lock_ObtainMutex(&tscp->mx);
+ lock_ObtainWrite(&tscp->rw);
code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
tscp = NULL;
if (dirScp) {
if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
/* this is a symlink; assemble a new buffer */
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
cm_ReleaseSCache(tscp);
tscp = NULL;
return CM_ERROR_TOO_MANY_SYMLINKS;
}
if (tc == 0)
- restp = "";
+ restp = _C("");
else
restp = tp;
- code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
+
+ {
+ fschar_t * frestp;
+
+ /* TODO: make this better */
+ frestp = cm_ClientStringToFsStringAlloc(restp, -1, NULL);
+ code = cm_AssembleLink(tscp, frestp, &linkScp, &tempsp, userp, reqp);
+ free(frestp);
+ }
+
+ if (code == 0 && linkScp != NULL) {
+ if (linkScp == cm_data.rootSCachep) {
+ fid_count = 0;
+ i = 0;
+ } else {
+ for ( i=0; i<fid_count; i++) {
+ if ( !cm_FidCmp(&linkScp->fid, &fids[i]) ) {
+ code = CM_ERROR_TOO_MANY_SYMLINKS;
+ cm_ReleaseSCache(linkScp);
+ nscp = NULL;
+ break;
+ }
+ }
+ }
+ if (i == fid_count && fid_count < MAX_FID_COUNT) {
+ fids[fid_count++] = linkScp->fid;
+ }
+ }
+
if (code) {
/* something went wrong */
cm_ReleaseSCache(tscp);
if (psp)
cm_FreeSpace(psp);
psp = tempsp;
- tp = psp->data;
+ tp = psp->wdata;
cm_ReleaseSCache(tscp);
tscp = linkScp;
linkScp = NULL;
}
} else {
/* not a symlink, we may be done */
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
if (tc == 0) {
if (phase == 1) {
phase = 2;
cm_ReleaseSCache(tscp);
#ifdef DEBUG_REFCOUNT
- afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
+ afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp) ? (*outScpp)->refCount : 0);
#endif
osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
return code;
cm_space_t *spacep;
cm_scache_t *newRootScp;
+ *outScpp = NULL;
+
osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
cm_HoldSCache(dscp);
}
- code = cm_NameI(newRootScp, spacep->data,
- CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
- userp, NULL, reqp, outScpp);
+ code = cm_NameI(newRootScp, spacep->wdata,
+ CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
+ userp, NULL, reqp, outScpp);
- if (code == CM_ERROR_NOSUCHFILE)
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
code = CM_ERROR_NOSUCHPATH;
/* this stuff is allocated no matter what happened on the namei call,
cm_FreeSpace(spacep);
cm_ReleaseSCache(newRootScp);
+ if (linkScp == *outScpp) {
+ cm_ReleaseSCache(*outScpp);
+ *outScpp = NULL;
+ code = CM_ERROR_NOSUCHPATH;
+ }
+
return code;
}
-/* make this big enough so that one buffer of dir pages won't overflow. We'll
- * check anyway, but we want to minimize the chance that we have to leave stuff
- * unstat'd.
- */
-#define CM_BULKMAX (3 * AFSCBMAX)
-
-/* rock for bulk stat calls */
-typedef struct cm_bulkStat {
- osi_hyper_t bufOffset; /* only do it for things in this buffer page */
-
- /* info for the actual call */
- int counter; /* next free slot */
- AFSFid fids[CM_BULKMAX];
- AFSFetchStatus stats[CM_BULKMAX];
- AFSCallBack callbacks[CM_BULKMAX];
-} cm_bulkStat_t;
-
/* for a given entry, make sure that it isn't in the stat cache, and then
* add it to the list of file IDs to be obtained.
*
if (strcmp(dep->name, ".") == 0 || strcmp(dep->name, "..") == 0)
return 0;
- tfid.cell = scp->fid.cell;
- tfid.volume = scp->fid.volume;
- tfid.vnode = ntohl(dep->fid.vnode);
- tfid.unique = ntohl(dep->fid.unique);
+ cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
tscp = cm_FindSCache(&tfid);
if (tscp) {
- if (lock_TryMutex(&tscp->mx)) {
+ if (lock_TryWrite(&tscp->rw)) {
/* we have an entry that we can look at */
if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
/* we have a callback on it. Don't bother
* fetching this stat entry, since we're happy
* with the info we have.
*/
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
return 0;
}
- lock_ReleaseMutex(&tscp->mx);
+ lock_ReleaseWrite(&tscp->rw);
} /* got lock */
cm_ReleaseSCache(tscp);
} /* found entry */
return 0;
}
-/* called with a locked scp and a pointer to a buffer. Make bulk stat
- * calls on all undeleted files in the page of the directory specified.
- */
afs_int32
-cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
- cm_req_t *reqp)
+cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_req_t *reqp)
{
- long code;
- cm_bulkStat_t bb; /* this is *BIG*, probably 16K or so;
- * watch for stack problems */
+ afs_int32 code = 0;
AFSCBFids fidStruct;
AFSBulkStats statStruct;
cm_conn_t *connp;
long j;
cm_scache_t *scp;
cm_fid_t tfid;
- struct rx_connection * callp;
- int inlinebulk = 0; /* Did we use InlineBulkStatus RPC or not? */
-
- osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
-
- /* should be on a buffer boundary */
- osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
-
- memset(&bb, 0, sizeof(bb));
- bb.bufOffset = *offsetp;
+ struct rx_connection * rxconnp;
+ int inlinebulk; /* Did we use InlineBulkStatus RPC or not? */
- lock_ReleaseMutex(&dscp->mx);
- /* first, assemble the file IDs we need to stat */
- code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp, reqp, NULL);
-
- /* if we failed, bail out early */
- if (code && code != CM_ERROR_STOPNOW) {
- lock_ObtainMutex(&dscp->mx);
- return code;
- }
+ 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.
*/
- filex = 0;
- while (filex < bb.counter) {
- filesThisCall = bb.counter - filex;
+ for (filex = 0; filex < bbp->counter; filex += filesThisCall) {
+ filesThisCall = bbp->counter - filex;
if (filesThisCall > AFSCBMAX)
filesThisCall = AFSCBMAX;
fidStruct.AFSCBFids_len = filesThisCall;
- fidStruct.AFSCBFids_val = &bb.fids[filex];
+ fidStruct.AFSCBFids_val = &bbp->fids[filex];
statStruct.AFSBulkStats_len = filesThisCall;
- statStruct.AFSBulkStats_val = &bb.stats[filex];
+ statStruct.AFSBulkStats_val = &bbp->stats[filex];
callbackStruct.AFSCBs_len = filesThisCall;
- callbackStruct.AFSCBs_val = &bb.callbacks[filex];
+ 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;
- callp = cm_GetRxConn(connp);
+ rxconnp = cm_GetRxConn(connp);
if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
- code = RXAFS_InlineBulkStatus(callp, &fidStruct,
- &statStruct, &callbackStruct, &volSync);
+ code = RXAFS_InlineBulkStatus(rxconnp, &fidStruct,
+ &statStruct, &callbackStruct, &volSync);
if (code == RXGEN_OPCODE) {
cm_SetServerNoInlineBulk(connp->serverp, 0);
} else {
}
}
if (!inlinebulk) {
- code = RXAFS_BulkStatus(callp, &fidStruct,
+ code = RXAFS_BulkStatus(rxconnp, &fidStruct,
&statStruct, &callbackStruct, &volSync);
}
- rx_PutConnection(callp);
-
- } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
- &volSync, NULL, &cbReq, code));
+ rx_PutConnection(rxconnp);
+
+ /*
+ * 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;
- tfid.cell = dscp->fid.cell;
- tfid.volume = bb.fids[j].Volume;
- tfid.vnode = bb.fids[j].Vnode;
- tfid.unique = bb.fids[j].Unique;
- code = cm_GetSCache(&tfid, &scp, userp, reqp);
- if (code != 0)
- continue;
+ cm_SetFid(&tfid, dscp->fid.cell, bbp->fids[j].Volume, bbp->fids[j].Vnode, bbp->fids[j].Unique);
- /* otherwise, if this entry has no callback info,
- * merge in this.
- */
- lock_ObtainMutex(&scp->mx);
- /* 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,
- &bb.callbacks[j],
- CM_CALLBACK_MAINTAINCOUNT);
- cm_MergeStatus(dscp, scp, &bb.stats[j], &volSync, userp, 0);
- }
- lock_ReleaseMutex(&scp->mx);
- 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);
-
- filex += filesThisCall;
+ cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
} /* while there are still more files to process */
- lock_ObtainMutex(&dscp->mx);
- /* If we did the InlineBulk RPC pull out the return code and log it */
- if (inlinebulk) {
- if ((&bb.stats[0])->errorCode) {
- osi_Log1(afsd_logp, "cm_TryBulkStat bulk stat error: %d",
- (&bb.stats[0])->errorCode);
- }
+ return code;
+}
+
+/* called with a write locked scp and a pointer to a buffer. Make bulk stat
+ * calls on all undeleted files in the page of the directory specified.
+ */
+afs_int32
+cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
+ cm_req_t *reqp)
+{
+ afs_int32 code;
+ cm_bulkStat_t *bbp;
+
+ osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
+
+ /* should be on a buffer boundary */
+ osi_assertx((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0, "invalid offset");
+
+ bbp = malloc(sizeof(cm_bulkStat_t));
+ memset(bbp, 0, sizeof(cm_bulkStat_t));
+ bbp->bufOffset = *offsetp;
+
+ lock_ReleaseWrite(&dscp->rw);
+ /* first, assemble the file IDs we need to stat */
+ code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) bbp, offsetp, userp, reqp, NULL);
+
+ /* if we failed, bail out early */
+ if (code && code != CM_ERROR_STOPNOW) {
+ free(bbp);
+ lock_ObtainWrite(&dscp->rw);
+ return code;
}
- osi_Log0(afsd_logp, "END cm_TryBulkStat");
+ code = cm_TryBulkStatRPC(dscp, bbp, userp, reqp);
+ osi_Log1(afsd_logp, "END cm_TryBulkStat code 0x%x", code);
+
+ lock_ObtainWrite(&dscp->rw);
+ free(bbp);
return 0;
}
lock_ObtainWrite(&scp->bufCreateLock);
/* verify that this is a file, not a dir or a symlink */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code)
else
shrinking = 0;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
- /* can't hold scp->mx lock here, since we may wait for a storeback to
+ /* can't hold scp->rw lock here, since we may wait for a storeback to
* finish if the buffer package is cleaning a buffer by storing it to
* the server.
*/
buf_Truncate(scp, userp, reqp, sizep);
/* now ensure that file length is short enough, and update truncPos */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* make sure we have a callback (so we have the right value for the
* length), and wait for it to be safe to do a truncate.
| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
done:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ReleaseWrite(&scp->bufCreateLock);
return code;
cm_conn_t *connp;
AFSFid tfid;
AFSStoreStatus afsInStatus;
- struct rx_connection * callp;
+ 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_ObtainMutex(&scp->mx);
+ 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_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
+ lock_ConvertWToR(&scp->rw);
/* make the attr structure */
cm_StatusFromAttr(&afsInStatus, scp, attrp);
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
tfid.Unique = scp->fid.unique;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseRead(&scp->rw);
/* now make the RPC */
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
if (code)
continue;
- callp = cm_GetRxConn(connp);
- code = RXAFS_StoreStatus(callp, &tfid,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_StoreStatus(rxconnp, &tfid,
&afsInStatus, &afsOutStatus, &volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
&scp->fid, &volSync, NULL, NULL, code));
else
osi_Log0(afsd_logp, "CALL StoreStatus SUCCESS");
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
if (code == 0)
- cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp,
+ 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,
*/
if (afsInStatus.Mask & AFS_SETMODE)
cm_FreeAllACLEnts(scp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
-long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
+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;
cm_callbackRequest_t cbReq;
AFSFid newAFSFid;
cm_fid_t newFid;
- cm_scache_t *scp;
+ cm_scache_t *scp = NULL;
int didEnd;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newFileStatus;
AFSCallBack newFileCallback;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ 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.
*/
- if (cm_ExpandSysName(namep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold files */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
+ /* 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ 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);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
+ } else {
+ cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
didEnd = 0;
+ fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
dirAFSFid.Vnode = dscp->fid.vnode;
dirAFSFid.Unique = dscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_CreateFile(connp->callp, &dirAFSFid, namep,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_CreateFile(connp->rxconnp, &dirAFSFid, fnamep,
&inStatus, &newAFSFid, &newFileStatus,
&updatedDirStatus, &newFileCallback,
&volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
&dscp->fid, &volSync, NULL, &cbReq, code));
else
osi_Log0(afsd_logp, "CALL CreateFile SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* now try to create the file's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
scp->creator = userp; /* remember who created it */
if (!cm_HaveCallback(scp)) {
- cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
- userp, 0);
cm_EndCallbackGrantingCall(scp, &cbReq,
- &newFileCallback, 0);
+ &newFileCallback, &volSync, 0);
+ cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
- lock_ReleaseMutex(&scp->mx);
- *scpp = scp;
+ 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);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ }
+ cm_EndDirOp(&dirop);
+ if (fnamep)
+ free(fnamep);
+
+ if (scp) {
+ if (scpp)
+ *scpp = scp;
+ else
+ cm_ReleaseSCache(scp);
+ }
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;
- lock_ObtainWrite(&scp->bufCreateLock);
+ if (locked)
+ lock_ReleaseWrite(&scp->rw);
code = buf_CleanVnode(scp, userp, reqp);
- lock_ReleaseWrite(&scp->bufCreateLock);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
| CM_SCACHEMASK_CLIENTMODTIME
scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
}
- lock_ReleaseMutex(&scp->mx);
+ if (!locked)
+ lock_ReleaseWrite(&scp->rw);
+ } else if (locked) {
+ lock_ObtainWrite(&scp->rw);
}
return code;
}
-long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
- cm_user_t *userp, cm_req_t *reqp)
+long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
+ cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp)
{
cm_conn_t *connp;
long code;
cm_callbackRequest_t cbReq;
AFSFid newAFSFid;
cm_fid_t newFid;
- cm_scache_t *scp;
+ cm_scache_t *scp = NULL;
int didEnd;
AFSStoreStatus inStatus;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newDirStatus;
AFSCallBack newDirCallback;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ 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.
*/
- if (cm_ExpandSysName(namep, NULL, 0, 0)) {
+ if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold subdirectories */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
+ /* 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ 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);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
+ } else {
+ cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
didEnd = 0;
+ fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
dirAFSFid.Vnode = dscp->fid.vnode;
dirAFSFid.Unique = dscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_MakeDir(connp->callp, &dirAFSFid, namep,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_MakeDir(connp->rxconnp, &dirAFSFid, fnamep,
&inStatus, &newAFSFid, &newDirStatus,
&updatedDirStatus, &newDirCallback,
&volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, &cbReq, code));
+ &dscp->fid, &volSync, NULL, &cbReq, code));
code = cm_MapRPCError(code, reqp);
if (code)
else
osi_Log0(afsd_logp, "CALL MakeDir SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* now try to create the new dir's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
- cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
- userp, 0);
cm_EndCallbackGrantingCall(scp, &cbReq,
- &newDirCallback, 0);
+ &newDirCallback, &volSync, 0);
+ cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
+ userp, reqp, 0);
didEnd = 1;
}
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
+ 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);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ }
+ cm_EndDirOp(&dirop);
+
+ free(fnamep);
+
+ if (scp) {
+ if (scpp)
+ *scpp = scp;
+ else
+ cm_ReleaseSCache(scp);
+ }
/* and return error code */
return code;
}
-long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
+long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long flags,
cm_user_t *userp, cm_req_t *reqp)
{
cm_conn_t *connp;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newLinkStatus;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ 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;
}
- lock_ObtainMutex(&dscp->mx);
+ /* 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_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&dirop);
if (code)
return code;
+ fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
/* try the RPC now */
osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
do {
existingAFSFid.Vnode = sscp->fid.vnode;
existingAFSFid.Unique = sscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_Link(rxconnp, &dirAFSFid, fnamep, &existingAFSFid,
&newLinkStatus, &updatedDirStatus, &volSync);
- rx_PutConnection(callp);
- osi_Log1(smb_logp," RXAFS_Link returns 0x%x", code);
+ 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));
else
osi_Log0(afsd_logp, "CALL Link SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ }
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirCreateEntry(&dirop, fnamep, &sscp->fid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &sscp->fid);
+#endif
+ }
+ }
+ 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);
}
- lock_ReleaseMutex(&dscp->mx);
+
+ free(fnamep);
return code;
}
-long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
+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_conn_t *connp;
AFSFetchStatus updatedDirStatus;
AFSFetchStatus newLinkStatus;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ 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.
*/
- lock_ObtainMutex(&dscp->mx);
+ 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_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&dirop);
if (code) {
return code;
}
+ fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
dirAFSFid.Vnode = dscp->fid.vnode;
dirAFSFid.Unique = dscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_Symlink(callp, &dirAFSFid, namep, contentsp,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_Symlink(rxconnp, &dirAFSFid, fnamep, contentsp,
&inStatus, &newAFSFid, &newLinkStatus,
&updatedDirStatus, &volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
&dscp->fid, &volSync, NULL, NULL, code));
else
osi_Log0(afsd_logp, "CALL Symlink SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
}
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
+
+ cm_DirCreateEntry(&dirop, fnamep, &newFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
+#endif
+ }
+ }
+ cm_EndDirOp(&dirop);
/* now try to create the new dir's entry, too, but be careful to
* make sure that we don't merge in old info. Since we weren't locking
* info.
*/
if (code == 0) {
- newFid.cell = dscp->fid.cell;
- newFid.volume = dscp->fid.volume;
- newFid.vnode = newAFSFid.Vnode;
- newFid.unique = newAFSFid.Unique;
+ cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
code = cm_GetSCache(&newFid, &scp, userp, reqp);
if (code == 0) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
- userp, 0);
+ userp, reqp, 0);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
}
}
+
+ free(fnamep);
/* and return error code */
return code;
}
-long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
- cm_req_t *reqp)
+/*! \brief Remove a directory
+
+ Encapsulates a call to RXAFS_RemoveDir().
+
+ \param[in] dscp cm_scache_t for the directory containing the
+ directory to be removed.
+
+ \param[in] fnamep This will be the original name of the directory
+ as known to the file server. It will be passed in to RXAFS_RemoveDir().
+ This parameter is optional. If it is not provided the value
+ will be looked up.
+
+ \param[in] cnamep Normalized name used to update the local
+ directory caches.
+
+ \param[in] userp cm_user_t for the request.
+
+ \param[in] reqp Request tracker.
+*/
+long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_user_t *userp, cm_req_t *reqp)
{
cm_conn_t *connp;
long code;
int didEnd;
AFSFetchStatus updatedDirStatus;
AFSVolSync volSync;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ cm_dirOp_t dirop;
+ 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,
+ CM_DIROP_FLAG_NONE, &dirop);
+ if (code == 0) {
+ code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+ if (code == 0)
+ free_fnamep = TRUE;
+ cm_EndDirOp(&dirop);
+ }
+#endif
+ if (code)
+ goto done;
+ }
+
+ 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;
+ }
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
- lock_ObtainMutex(&dscp->mx);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
+ lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
if (code) {
- return code;
+ cm_EndDirOp(&dirop);
+ goto done;
}
didEnd = 0;
dirAFSFid.Vnode = dscp->fid.vnode;
dirAFSFid.Unique = dscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_RemoveDir(callp, &dirAFSFid, namep,
- &updatedDirStatus, &volSync);
- rx_PutConnection(callp);
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_RemoveDir(rxconnp, &dirAFSFid, fnamep,
+ &updatedDirStatus, &volSync);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp,
- &dscp->fid, &volSync, NULL, NULL, code));
+ &dscp->fid, &volSync, NULL, NULL, code));
code = cm_MapRPCErrorRmdir(code, reqp);
if (code)
else
osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
- lock_ObtainMutex(&dscp->mx);
+ if (dirop.scp) {
+ lock_ObtainWrite(&dirop.scp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&dscp->rw);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_dnlcRemove(dscp, namep);
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_dnlcRemove(dscp, cnamep);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ }
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop) && cnamep != NULL) {
+ cm_DirDeleteEntry(&dirop, fnamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, cnamep);
+#endif
+ }
}
- lock_ReleaseMutex(&dscp->mx);
+ cm_EndDirOp(&dirop);
+
+ if (scp) {
+ cm_ReleaseSCache(scp);
+ if (code == 0) {
+ lock_ObtainWrite(&scp->rw);
+ scp->flags |= CM_SCACHEFLAG_DELETED;
+ lock_ReleaseWrite(&scp->rw);
+ }
+ }
+
+ done:
+ if (free_fnamep)
+ free(fnamep);
/* and return error code */
return code;
long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
{
/* grab mutex on contents */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* reset the prefetch info */
scp->prefetch.base.LowPart = 0; /* base */
scp->prefetch.end.HighPart = 0;
/* release mutex on contents */
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
/* we're done */
return 0;
}
-long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
- char *newNamep, cm_user_t *userp, cm_req_t *reqp)
+/*! \brief Rename a file or directory
+
+ Encapsulates a RXAFS_Rename() call.
+
+ \param[in] oldDscp cm_scache_t for the directory containing the old
+ name.
+
+ \param[in] oldNamep The original old name known to the file server.
+ This is the name that will be passed into the RXAFS_Rename().
+ If it is not provided, it will be looked up.
+
+ \param[in] normalizedOldNamep Normalized old name. This is used for
+ updating local directory caches.
+
+ \param[in] newDscp cm_scache_t for the directory containing the new
+ name.
+
+ \param[in] newNamep New name. Normalized.
+
+ \param[in] userp cm_user_t for the request.
+
+ \param[in,out] reqp Request tracker.
+
+*/
+long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep,
+ cm_scache_t *newDscp, clientchar_t *cNewNamep, cm_user_t *userp,
+ cm_req_t *reqp)
{
cm_conn_t *connp;
long code;
AFSFetchStatus updatedNewDirStatus;
AFSVolSync volSync;
int oneDir;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
+ cm_dirOp_t oldDirOp;
+ cm_fid_t fileFid;
+ int diropCode = -1;
+ cm_dirOp_t newDirOp;
+ fschar_t * newNamep = NULL;
+ 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)
+ 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 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,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
+ if (code == 0) {
+ code = cm_BPlusDirLookupOriginalName(&oldDirOp, cOldNamep, &oldNamep);
+ if (code == 0)
+ free_oldNamep = TRUE;
+ cm_EndDirOp(&oldDirOp);
+ }
+#endif
+ if (code) {
+ 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
*/
if (oldDscp == newDscp) {
/* check for identical names */
- if (strcmp(oldNamep, newNamep) == 0)
- return CM_ERROR_RENAME_IDENTICAL;
+ 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;
- lock_ObtainMutex(&oldDscp->mx);
- cm_dnlcRemove(oldDscp, oldNamep);
- cm_dnlcRemove(oldDscp, newNamep);
+ 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);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0) {
+ cm_EndDirOp(&oldDirOp);
+ }
}
else {
/* two distinct dir vnodes */
oneDir = 0;
if (oldDscp->fid.cell != newDscp->fid.cell ||
- oldDscp->fid.volume != newDscp->fid.volume)
- return CM_ERROR_CROSSDEVLINK;
+ oldDscp->fid.volume != newDscp->fid.volume) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_CROSSDEVLINK",
+ oldDscp, newDscp);
+ code = CM_ERROR_CROSSDEVLINK;
+ goto done;
+ }
/* shouldn't happen that we have distinct vnodes for two
* different files, but could due to deliberate attack, or
* stale info. Avoid deadlocks and quit now.
*/
- if (oldDscp->fid.vnode == newDscp->fid.vnode)
- return CM_ERROR_CROSSDEVLINK;
+ if (oldDscp->fid.vnode == newDscp->fid.vnode) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p vnode collision",
+ oldDscp, newDscp);
+ code = CM_ERROR_CROSSDEVLINK;
+ goto done;
+ }
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
- lock_ObtainMutex(&oldDscp->mx);
- cm_dnlcRemove(oldDscp, oldNamep);
+ 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,
- CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&oldDirOp);
if (code == 0) {
- lock_ObtainMutex(&newDscp->mx);
- cm_dnlcRemove(newDscp, newNamep);
+ 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,
- CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseWrite(&newDscp->rw);
if (code) {
+ cm_EndDirOp(&newDirOp);
+
/* cleanup first one */
- lock_ObtainMutex(&oldDscp->mx);
+ lock_ObtainWrite(&oldDscp->rw);
cm_SyncOpDone(oldDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ cm_EndDirOp(&oldDirOp);
}
}
}
else {
/* lock the new vnode entry first */
- lock_ObtainMutex(&newDscp->mx);
- cm_dnlcRemove(newDscp, newNamep);
+ 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,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ lock_ReleaseWrite(&newDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&newDirOp);
if (code == 0) {
- lock_ObtainMutex(&oldDscp->mx);
- cm_dnlcRemove(oldDscp, oldNamep);
+ 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,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&oldDscp->mx);
+ lock_ReleaseWrite(&oldDscp->rw);
+ if (code != 0)
+ cm_EndDirOp(&oldDirOp);
if (code) {
/* cleanup first one */
- lock_ObtainMutex(&newDscp->mx);
+ lock_ObtainWrite(&newDscp->rw);
cm_SyncOpDone(newDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- lock_ReleaseMutex(&newDscp->mx);
+ lock_ReleaseWrite(&newDscp->rw);
+ cm_EndDirOp(&newDirOp);
}
}
}
} /* two distinct vnodes */
- if (code) {
- return code;
- }
+ if (code)
+ goto done;
+
didEnd = 0;
+ newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
+
/* try the RPC now */
osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
oldDscp, newDscp);
newDirAFSFid.Vnode = newDscp->fid.vnode;
newDirAFSFid.Unique = newDscp->fid.unique;
- callp = cm_GetRxConn(connp);
- code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
- &newDirAFSFid, newNamep,
- &updatedOldDirStatus, &updatedNewDirStatus,
- &volSync);
- rx_PutConnection(callp);
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_Rename(rxconnp, &oldDirAFSFid, oldNamep,
+ &newDirAFSFid, newNamep,
+ &updatedOldDirStatus, &updatedNewDirStatus,
+ &volSync);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
&volSync, NULL, NULL, code));
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
/* update the individual stat cache entries for the directories */
- lock_ObtainMutex(&oldDscp->mx);
+ if (oldDirOp.scp) {
+ lock_ObtainWrite(&oldDirOp.scp->dirlock);
+ oldDirOp.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&oldDscp->rw);
cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0) {
+
+ if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
- userp, 0);
+ userp, reqp, CM_MERGEFLAG_DIROP);
+ lock_ReleaseWrite(&oldDscp->rw);
+
+ 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)
+#endif
+ diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+
+ if (diropCode == 0) {
+ if (oneDir) {
+ diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+#endif
+ }
+
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+#ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+#endif
+ }
+ }
}
- lock_ReleaseMutex(&oldDscp->mx);
+ cm_EndDirOp(&oldDirOp);
/* and update it for the new one, too, if necessary */
if (!oneDir) {
- lock_ObtainMutex(&newDscp->mx);
+ if (newDirOp.scp) {
+ lock_ObtainWrite(&newDirOp.scp->dirlock);
+ newDirOp.lockType = CM_DIRLOCK_WRITE;
+ }
+ lock_ObtainWrite(&newDscp->rw);
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
- if (code == 0) {
+ if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
- userp, 0);
+ userp, 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 */
+ if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
+ cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&newDirOp, cNewNamep, &fileFid);
+#endif
+ }
}
- lock_ReleaseMutex(&newDscp->mx);
+#endif /* 0 */
+ 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);
+
+ done:
+ if (oldScp)
+ cm_ReleaseSCache(oldScp);
+
+ if (free_oldNamep)
+ free(oldNamep);
+
+ free(newNamep);
+
/* and return error code */
return code;
}
}
}
-/* Called with scp->mx held. Returns 0 if all is clear to read the
+/* Called with scp->rw held. Returns 0 if all is clear to read the
specified range by the client identified by key.
*/
long cm_LockCheckRead(cm_scache_t *scp,
if (INTERSECT_RANGE(range, fileLock->range)) {
if (IS_LOCK_ACTIVE(fileLock)) {
- if (fileLock->key == key) {
+ if (cm_KeyEquals(&fileLock->key, &key, 0)) {
/* If there is an active lock for this client, it
is safe to substract ranges.*/
cm_LockRangeSubtract(&range, &fileLock->range);
}
} else if (IS_LOCK_LOST(fileLock) &&
- (fileLock->key == key || fileLock->lockType == LockWrite)) {
+ (cm_KeyEquals(&fileLock->key, &key, 0) || fileLock->lockType == LockWrite)) {
code = CM_ERROR_BADFD;
break;
}
#endif
}
-/* Called with scp->mx held. Returns 0 if all is clear to write the
+/* Called with scp->rw held. Returns 0 if all is clear to write the
specified range by the client identified by key.
*/
long cm_LockCheckWrite(cm_scache_t *scp,
if (INTERSECT_RANGE(range, fileLock->range)) {
if (IS_LOCK_ACTIVE(fileLock)) {
- if (fileLock->key == key) {
+ if (cm_KeyEquals(&fileLock->key, &key, 0)) {
if (fileLock->lockType == LockWrite) {
/* if there is an active lock for this client, it
#endif
}
-/* Forward dcl. */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp);
-
/* Called with cm_scacheLock write locked */
static cm_file_lock_t * cm_GetFileLock(void) {
cm_file_lock_t * l;
osi_QRemove(&cm_freeFileLocks, &l->q);
} else {
l = malloc(sizeof(cm_file_lock_t));
- osi_assert(l);
+ osi_assertx(l, "null cm_file_lock_t");
}
memset(l, 0, sizeof(cm_file_lock_t));
osi_QAdd(&cm_freeFileLocks, &l->q);
}
-/* called with scp->mx held. May release it during processing, but
+/* called with scp->rw held. May release it during processing, but
leaves it held on exit. */
long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
cm_req_t * reqp) {
AFSFid tfid;
cm_fid_t cfid;
cm_conn_t * connp;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
AFSVolSync volSync;
+ afs_uint32 reqflags = reqp->flags;
+
+ memset(&volSync, 0, sizeof(volSync));
tfid.Volume = scp->fid.volume;
tfid.Vnode = scp->fid.vnode;
osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
- lock_ReleaseMutex(&scp->mx);
+ reqp->flags |= CM_REQ_NORETRY;
+ lock_ReleaseWrite(&scp->rw);
do {
code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
if (code)
break;
- callp = cm_GetRxConn(connp);
- code = RXAFS_SetLock(callp, &tfid, lockType,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_SetLock(rxconnp, &tfid, lockType,
&volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
NULL, NULL, code));
osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
}
- lock_ObtainMutex(&scp->mx);
-
+ lock_ObtainWrite(&scp->rw);
+ reqp->flags = reqflags;
return code;
}
-/* called with scp->mx held. Releases it during processing */
+/* called with scp->rw held. Releases it during processing */
long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
cm_req_t * reqp) {
long code = 0;
AFSFid tfid;
cm_fid_t cfid;
cm_conn_t * connp;
- struct rx_connection * callp;
+ 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;
cfid = scp->fid;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
if (code)
break;
- callp = cm_GetRxConn(connp);
- code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
- rx_PutConnection(callp);
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_ReleaseLock(rxconnp, &tfid, &volSync);
+ rx_PutConnection(rxconnp);
} while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
NULL, NULL, code));
osi_Log0(afsd_logp,
"CALL ReleaseLock SUCCESS");
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
return code;
}
-/* called with scp->mx held. May release it during processing, but
+/* called with scp->rw held. May release it during processing, but
will exit with lock held.
This will return:
rights |= PRSFS_WRITE | PRSFS_LOCK;
else {
/* hmmkay */
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid lock type");
return 0;
}
return code;
}
-/* called with scp->mx held */
+/* called with scp->rw held */
long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
cm_key_t key,
osi_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_Log3(afsd_logp, "... allowWait %d key 0x%x:%x", allowWait,
- (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
+ osi_Log4(afsd_logp, "... allowWait %d key <0x%x, 0x%x, 0x%x>", allowWait,
+ key.process_id, key.session_id, key.file_id);
/*
A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
(cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
if (IS_LOCK_LOST(fileLock)) {
- if (fileLock->key == key) {
+ if (cm_KeyEquals(&fileLock->key, &key, 0)) {
code = CM_ERROR_BADFD;
break;
} else if (fileLock->lockType == LockWrite && INTERSECT_RANGE(range, fileLock->range)) {
osi_Log0(afsd_logp,
" attempting to UPGRADE from LockRead to LockWrite.");
osi_Log1(afsd_logp,
- " dataVersion on scp: %d", scp->dataVersion);
+ " dataVersion on scp: %I64d", scp->dataVersion);
/* we assume at this point (because scp->serverLock
was valid) that we had a valid server lock. */
newLock = Which;
/* am I sane? */
- osi_assert(newLock == LockRead);
+ osi_assertx(newLock == LockRead, "lock type not read");
code = cm_IntSetLock(scp, userp, newLock, reqp);
}
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
if (code != 0 &&
(scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
- scp->serverLock == -1) {
- /* Oops. We lost the lock. */
- cm_LockMarkSCacheLost(scp);
- }
+ scp->serverLock == -1) {
+ /* Oops. We lost the lock. */
+ cm_LockMarkSCacheLost(scp);
}
+ }
} else if (code == 0) { /* server locks not enabled */
osi_Log0(afsd_logp,
" Skipping server lock for scp");
"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;
}
-static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags);
-
-/* Called with scp->mx held */
+/* Called with scp->rw held */
long cm_UnlockByKey(cm_scache_t * scp,
cm_key_t key,
int flags,
osi_queue_t *q, *qn;
int n_unlocks = 0;
- osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
- scp,
- (unsigned long)(key >> 32),
- (unsigned long)(key & 0xffffffff),
- flags);
+ 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);
(unsigned long) fileLock->range.offset,
(unsigned long) fileLock->range.length,
fileLock->lockType);
- osi_Log3(afsd_logp, " key[0x%x:%x] flags[0x%x]",
- (unsigned long)(fileLock->key >> 32),
- (unsigned long)(fileLock->key & 0xffffffff),
+ 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)) {
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
if (!IS_LOCK_DELETED(fileLock) &&
- cm_KeyEquals(fileLock->key, key, flags)) {
+ cm_KeyEquals(&fileLock->key, &key, flags)) {
osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
fileLock->range.offset,
fileLock->range.length,
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;
- osi_Log1(afsd_logp, " dataVersion on scp = %d", scp->dataVersion);
+ osi_Log1(afsd_logp, " dataVersion on scp = %I64d", scp->dataVersion);
code = cm_IntReleaseLock(scp, userp, reqp);
we have lost the lock we had during the transition. */
osi_Log0(afsd_logp, "Data version mismatch during lock downgrade");
- osi_Log2(afsd_logp, " Data versions before=%d, after=%d",
+ osi_Log2(afsd_logp, " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
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_Log2(afsd_logp, "... key 0x%x:%x",
- (unsigned long) (key >> 32), (unsigned long) (key & 0xffffffff));
+ 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)) {
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
- if (!IS_LOCK_DELETED(fileLock) &&
- fileLock->key == key &&
- 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 0;
+ 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;
+ }
}
- lock_ReleaseRead(&cm_scacheLock);
-
/* discard lock record */
- lock_ObtainWrite(&cm_scacheLock);
+ lock_ConvertRToW(&cm_scacheLock);
if (scp->fileLocksT == q)
scp->fileLocksT = osi_QPrev(q);
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
/* 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 %d", scp->dataVersion);
+ osi_Log1(afsd_logp, " dataVersion on scp is %I64d", scp->dataVersion);
/* before we downgrade, make sure that we have enough
permissions to get the read lock. */
osi_Log0(afsd_logp,
"Data version mismatch while downgrading lock");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
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:
return code;
}
-/* called with scp->mx held */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp)
+/* called with scp->rw held */
+void cm_LockMarkSCacheLost(cm_scache_t * scp)
{
cm_file_lock_t *fileLock;
osi_queue_t *q;
osi_Log1(afsd_logp, "cm_LockMarkSCacheLost scp 0x%x", scp);
-#ifdef DEBUG
- /* With the current code, we can't lose a lock on a RO scp */
- osi_assert(!(scp->flags & CM_SCACHEFLAG_RO));
-#endif
-
/* cm_scacheLock needed because we are modifying fileLock->flags */
lock_ObtainWrite(&cm_scacheLock);
}
scp->serverLock = -1;
- scp->lockDataVersion = -1;
+ scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
lock_ReleaseWrite(&cm_scacheLock);
}
AFSVolSync volSync;
cm_conn_t *connp;
long code;
- struct rx_connection * callp;
+ struct rx_connection * rxconnp;
cm_scache_t * scp;
+ memset(&volSync, 0, sizeof(volSync));
+
cm_InitReq(&req);
lock_ObtainWrite(&cm_scacheLock);
/* Server locks must have been enabled for us to have
received an active non-client-only lock. */
- osi_assert(cm_enableServerLocks);
+ osi_assertx(cm_enableServerLocks, "!cm_enableServerLocks");
scp = fileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
cm_HoldSCacheNoLock(scp);
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid");
}
#endif
/* Server locks are extended once per scp per refresh
osi_Log1(afsd_logp, "cm_CheckLocks Updating scp 0x%x", scp);
lock_ReleaseWrite(&cm_scacheLock);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
/* did the lock change while we weren't holding the lock? */
if (!IS_LOCK_ACTIVE(fileLock))
| CM_SCACHESYNC_LOCK);
if (code) {
- osi_Log1(smb_logp,
+ osi_Log1(afsd_logp,
"cm_CheckLocks SyncOp failure code 0x%x", code);
goto post_syncopdone;
}
- /* cm_SyncOp releases scp->mx during which the lock
+ /* cm_SyncOp releases scp->rw during which the lock
may get released. */
if (!IS_LOCK_ACTIVE(fileLock))
goto pre_syncopdone;
- if (scp->serverLock != -1) {
+ if (scp->serverLock != -1 && !(scp->flags & CM_SCACHEFLAG_DELETED)) {
cm_fid_t cfid;
cm_user_t * userp;
scp,
(int) scp->serverLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
do {
code = cm_ConnFromFID(&cfid, userp,
if (code)
break;
- callp = cm_GetRxConn(connp);
- code = RXAFS_ExtendLock(callp, &tfid,
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_ExtendLock(rxconnp, &tfid,
&volSync);
- rx_PutConnection(callp);
+ rx_PutConnection(rxconnp);
osi_Log1(afsd_logp, " ExtendLock returns %d", code);
code = cm_MapRPCError(code, &req);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
if (code) {
osi_Log1(afsd_logp, "CALL ExtendLock FAILURE, code 0x%x", code);
"Data version mismatch on scp 0x%p",
scp);
osi_Log2(afsd_logp,
- " Data versions: before=%d, after=%d",
+ " Data versions: before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
}
}
- if (code == EINVAL || code == CM_ERROR_INVAL) {
+ if (code == EINVAL || code == CM_ERROR_INVAL ||
+ code == CM_ERROR_BADFD) {
cm_LockMarkSCacheLost(scp);
}
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
post_syncopdone:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
lock_ObtainWrite(&cm_scacheLock);
osi_Log1(afsd_logp, "cm_CheckLocks completes lock check cycle %d", cm_lockRefreshCycle);
}
-/* NOT called with scp->mx held. */
+/* NOT called with scp->rw held. */
long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
{
long code = 0;
(unsigned)(oldFileLock->range.offset & 0xffffffff),
(unsigned)(oldFileLock->range.length >> 32),
(unsigned)(oldFileLock->range.length & 0xffffffff));
- osi_Log3(afsd_logp, " key(%x:%x) flags=%x",
- (unsigned)(oldFileLock->key >> 32),
- (unsigned)(oldFileLock->key & 0xffffffff),
+ osi_Log4(afsd_logp, " key<0x%x,0x%x,0x%x> flags=%x",
+ oldFileLock->key.process_id, oldFileLock->key.session_id, oldFileLock->key.file_id,
(unsigned)(oldFileLock->flags));
/* if the lock has already been granted, then we have nothing to do */
scp = oldFileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
lock_ReleaseRead(&cm_scacheLock);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_LockCheckPerms(scp, oldFileLock->lockType,
oldFileLock->userp,
}
code = 0;
} else if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return code;
}
}
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return 0;
}
((char *) q - offsetof(cm_file_lock_t, fileq));
if (IS_LOCK_LOST(fileLock)) {
- if (fileLock->key == oldFileLock->key) {
+ if (cm_KeyEquals(&fileLock->key, &oldFileLock->key, 0)) {
code = CM_ERROR_BADFD;
oldFileLock->flags |= CM_FILELOCK_FLAG_LOST;
osi_Log1(afsd_logp, " found lost lock %p for same key. Marking lock as lost",
if (code != 0) {
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
goto handleCode;
}
oldFileLock->flags |= CM_FILELOCK_FLAG_WAITLOCK;
}
- osi_assert(IS_LOCK_WAITLOCK(oldFileLock));
+ osi_assertx(IS_LOCK_WAITLOCK(oldFileLock), "!IS_LOCK_WAITLOCK");
if (force_client_lock ||
!SERVERLOCKS_ENABLED(scp) ||
}
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
return 0;
| CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_LOCK);
if (code) {
- osi_Log1(smb_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
+ osi_Log1(afsd_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
lock_ReleaseWrite(&cm_scacheLock);
goto post_syncopdone;
}
if (scp->serverLock == LockRead) {
- osi_assert(newLock == LockWrite);
+ osi_assertx(newLock == LockWrite, "!LockWrite");
osi_Log0(afsd_logp, " Attempting to UPGRADE from LockRead to LockWrite");
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
lock_ReleaseWrite(&cm_scacheLock);
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
updateLock:
lock_ObtainWrite(&cm_scacheLock);
return code;
}
-cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
{
-#ifdef DEBUG
- osi_assert((process_id & 0xffffffff) == process_id);
- osi_assert((session_id & 0xffff) == session_id);
- osi_assert((file_id & 0xffff) == file_id);
-#endif
+ cm_key_t key;
+
+ key.process_id = process_id;
+ key.session_id = session_id;
+ key.file_id = file_id;
- return
- (((cm_key_t) (process_id & 0xffffffff)) << 32) |
- (((cm_key_t) (session_id & 0xffff)) << 16) |
- (((cm_key_t) (file_id & 0xffff)));
+ return key;
}
-static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags)
+int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
{
- if (flags & CM_UNLOCK_BY_FID) {
- return ((k1 & 0xffffffff) == (k2 & 0xffffffff));
- } else {
- return (k1 == k2);
- }
+ return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
+ ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
}
void cm_ReleaseAllLocks(void)
{
for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
while (scp->fileLocksH != NULL) {
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
lock_ObtainWrite(&cm_scacheLock);
if (!scp->fileLocksH) {
lock_ReleaseWrite(&cm_scacheLock);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
break;
}
fileLock = (cm_file_lock_t *)((char *) scp->fileLocksH - offsetof(cm_file_lock_t, fileq));
cm_UnlockByKey(scp, key, 0, userp, &req);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
}
}
}