osi_Log0(afsd_logp, "Loading Root Volume from cell");
do {
code = cm_GetVolumeByName(cm_data.rootCellp, cm_rootVolumeName, cm_rootUserp,
- &req, CM_FLAG_CREATE, &cm_data.rootVolumep);
+ &req, CM_GETVOL_FLAG_CREATE, &cm_data.rootVolumep);
afsi_log("cm_GetVolumeByName code %x root vol %x", code,
(code ? (cm_volume_t *)-1 : cm_data.rootVolumep));
} while (code && --attempts);
#define CM_ERROR_TOOFEWBUFS (CM_ERROR_BASE+50)
#define CM_ERROR_TOOMANYBUFS (CM_ERROR_BASE+51)
#define CM_ERROR_BAD_LEVEL (CM_ERROR_BASE+52)
+
+/* Used by cm_FollowMountPoint and cm_GetVolumeByName */
+#define RWVOL 0
+#define ROVOL 1
+#define BACKVOL 2
#endif /* __CM_H_ENV__ */
cm_data.buf_hashSize = osi_PrimeLessThan((afs_uint32)(cm_data.buf_nbuffers/7 + 1));
/* create hash table */
- memset((void *)cm_data.buf_hashTablepp, 0, cm_data.buf_hashSize * sizeof(cm_buf_t *));
+ memset((void *)cm_data.buf_scacheHashTablepp, 0, cm_data.buf_hashSize * sizeof(cm_buf_t *));
/* another hash table */
memset((void *)cm_data.buf_fileHashTablepp, 0, cm_data.buf_hashSize * sizeof(cm_buf_t *));
cm_buf_t *bp;
i = BUF_HASH(&scp->fid, offsetp);
- for(bp = cm_data.buf_hashTablepp[i]; bp; bp=bp->hashp) {
+ for(bp = cm_data.buf_scacheHashTablepp[i]; bp; bp=bp->hashp) {
if (cm_FidCmp(&scp->fid, &bp->fid) == 0
&& offsetp->LowPart == bp->offset.LowPart
&& offsetp->HighPart == bp->offset.HighPart) {
/* Remove from hash */
i = BUF_HASH(&bp->fid, &bp->offset);
- lbpp = &(cm_data.buf_hashTablepp[i]);
+ lbpp = &(cm_data.buf_scacheHashTablepp[i]);
for(tbp = *lbpp; tbp; lbpp = &tbp->hashp, tbp = *lbpp) {
if (tbp == bp) break;
}
#endif
bp->offset = *offsetp;
i = BUF_HASH(&scp->fid, offsetp);
- bp->hashp = cm_data.buf_hashTablepp[i];
- cm_data.buf_hashTablepp[i] = bp;
+ bp->hashp = cm_data.buf_scacheHashTablepp[i];
+ cm_data.buf_scacheHashTablepp[i] = bp;
i = BUF_FILEHASH(&scp->fid);
nextBp = cm_data.buf_fileHashTablepp[i];
bp->fileHashp = nextBp;
lock_ObtainWrite(&buf_globalLock);
for(i=0; i<cm_data.buf_hashSize; i++) {
- for(bp = cm_data.buf_hashTablepp[i]; bp; bp = bp->hashp) {
+ for(bp = cm_data.buf_scacheHashTablepp[i]; bp; bp = bp->hashp) {
if ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) {
buf_HoldLocked(bp);
lock_ReleaseWrite(&buf_globalLock);
}
#endif /* TESTING */
-/* dump the contents of the buf_hashTablepp. */
+/* dump the contents of the buf_scacheHashTablepp. */
int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
{
int zilch;
char output[1024];
afs_uint32 i;
- if (cm_data.buf_hashTablepp == NULL)
+ if (cm_data.buf_scacheHashTablepp == NULL)
return -1;
if (lock)
for (i = 0; i < cm_data.buf_hashSize; i++)
{
- for (bp = cm_data.buf_hashTablepp[i]; bp; bp=bp->hashp)
+ for (bp = cm_data.buf_scacheHashTablepp[i]; bp; bp=bp->hashp)
{
StringCbPrintfA(output, sizeof(output),
"%s bp=0x%08X, hash=%d, fid (cell=%d, volume=%d, "
/* do all in the hash bucket, since we don't know how many we'll find with
* varying cells.
*/
- for (scp = cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp = cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (scp->fid.volume == tfid.volume &&
scp->fid.vnode == tfid.vnode &&
scp->fid.unique == tfid.unique &&
lock_ObtainWrite(&cm_scacheLock);
- for (hash = 0; hash < cm_data.hashTableSize; hash++) {
- for(scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (hash = 0; hash < cm_data.scacheHashTableSize; hash++) {
+ for(scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (scp->fid.volume == fidp->Volume &&
scp->cbExpires > 0 &&
scp->cbServerp != NULL) {
* are "rare," hopefully this won't be a problem.
*/
lock_ObtainWrite(&cm_scacheLock);
- for (hash = 0; hash < cm_data.hashTableSize; hash++) {
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (hash = 0; hash < cm_data.scacheHashTableSize; hash++) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
cm_HoldSCacheNoLock(scp);
lock_ReleaseWrite(&cm_scacheLock);
lock_ObtainMutex(&scp->mx);
ntohl(host), ntohs(port));
lock_ObtainRead(&cm_scacheLock);
- for (i = 0; i < cm_data.hashTableSize; i++) {
- for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
+ for (i = 0; i < cm_data.scacheHashTableSize; i++) {
+ for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
if (index == 0)
goto searchDone;
index--;
ntohl(host), ntohs(port));
lock_ObtainRead(&cm_scacheLock);
- for (i = 0; i < cm_data.hashTableSize; i++) {
- for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
+ for (i = 0; i < cm_data.scacheHashTableSize; i++) {
+ for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
if (index == 0)
goto searchDone;
index--;
osi_Log4(afsd_logp, "CALL FetchStatus scp 0x%p vol %u vn %u uniq %u",
scp, sfid.volume, sfid.vnode, sfid.unique);
do {
- code = cm_Conn(&sfid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&sfid, userp, reqp, &connp);
if (code)
continue;
now = osi_Time();
lock_ObtainWrite(&cm_scacheLock);
- for (i=0; i<cm_data.hashTableSize; i++) {
- for (scp = cm_data.hashTablep[i]; scp; scp=scp->nextp) {
+ for (i=0; i<cm_data.scacheHashTableSize; i++) {
+ for (scp = cm_data.scacheHashTablep[i]; scp; scp=scp->nextp) {
cm_HoldSCacheNoLock(scp);
if (scp->cbExpires > 0 && (scp->cbServerp == NULL || now > scp->cbExpires)) {
lock_ReleaseWrite(&cm_scacheLock);
tsp = cm_NewServer(addrp, CM_SERVER_VLDB, cellp);
/* Insert the vlserver into a sorted list, sorted by server rank */
- tsrp = cm_NewServerRef(tsp);
+ tsrp = cm_NewServerRef(tsp, 0);
cm_InsertServerList(&cellp->vlServersp, tsrp);
/* drop the allocation reference */
lock_ObtainWrite(&cm_serverLock);
) {
/* must empty cp->vlServersp */
if (cp->vlServersp) {
- cm_FreeServerList(&cp->vlServersp);
+ cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
cp->vlServersp = NULL;
}
}
cellp = cm_FindCellByID(fidp->cell);
- if (!cellp) return CM_ERROR_NOSUCHCELL;
+ if (!cellp)
+ return CM_ERROR_NOSUCHCELL;
- code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
- if (code) return code;
+ code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &volp);
+ if (code)
+ return code;
*serversppp = cm_GetVolServers(volp, fidp->volume);
* and if we're going to retry, determine whether failover is appropriate,
* and whether timed backoff is appropriate.
*
- * If the error code is from cm_Conn() or friends, it will be a CM_ERROR code.
+ * If the error code is from cm_ConnFromFID() or friends, it will be a CM_ERROR code.
* Otherwise it will be an RPC code. This may be a UNIX code (e.g. EDQUOT), or
* it may be an RX code, or it may be a special code (e.g. VNOVOL), or it may
* be a security code (e.g. RXKADEXPIRED).
*
- * If the error code is from cm_Conn() or friends, connp will be NULL.
+ * If the error code is from cm_ConnFromFID() or friends, connp will be NULL.
*
* For VLDB calls, fidp will be NULL.
*
}
else if (errorCode == CM_ERROR_ALLOFFLINE) {
+ osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_ALLOFFLINE.");
+ /* Volume instances marked offline will be restored by the
+ * background daemon thread as they become available
+ */
+#if 0
if (timeLeft > 7) {
- osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_ALLOFFLINE.");
thrd_Sleep(5000);
-
+
if (fidp) { /* Not a VLDB call */
if (!serversp) {
code = cm_GetServerList(fidp, userp, reqp, &serverspp);
}
if (serversp) {
lock_ObtainWrite(&cm_serverLock);
- for (tsrp = serversp; tsrp; tsrp=tsrp->next)
- tsrp->status = not_busy;
+ for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+ /* REDIRECT */
+ tsrp->status = srv_not_busy;
+ }
lock_ReleaseWrite(&cm_serverLock);
if (free_svr_list) {
- cm_FreeServerList(&serversp);
+ cm_FreeServerList(&serversp, 0);
*serverspp = serversp;
}
retry = 1;
} else { /* VLDB call */
if (serversp) {
lock_ObtainWrite(&cm_serverLock);
- for (tsrp = serversp; tsrp; tsrp=tsrp->next)
- tsrp->status = not_busy;
+ for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+ /* REDIRECT */
+ tsrp->status = srv_not_busy;
+ }
lock_ReleaseWrite(&cm_serverLock);
if (free_svr_list) {
- cm_FreeServerList(&serversp);
+ cm_FreeServerList(&serversp, 0);
*serverspp = serversp;
}
}
}
}
+#endif
}
-
- /* if all servers are busy, mark them non-busy and start over */
else if (errorCode == CM_ERROR_ALLBUSY) {
+ /* Volume instances marked busy will be restored by the
+ * background daemon thread as they become available.
+ */
osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_ALLBUSY.");
+#if 0
if (timeLeft > 7) {
thrd_Sleep(5000);
if (!serversp) {
}
lock_ObtainWrite(&cm_serverLock);
for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
- if (tsrp->status == busy)
- tsrp->status = not_busy;
+ if (tsrp->status == srv_busy) {
+ /* REDIRECT */
+ tsrp->status = srv_not_busy;
+ }
}
lock_ReleaseWrite(&cm_serverLock);
if (free_svr_list) {
- cm_FreeServerList(&serversp);
+ cm_FreeServerList(&serversp, 0);
*serverspp = serversp;
}
retry = 1;
}
+#endif
}
/* special codes: VBUSY and VRESTARTING */
}
lock_ObtainWrite(&cm_serverLock);
for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
- if (tsrp->server == serverp
- && tsrp->status == not_busy) {
- tsrp->status = busy;
+ if (tsrp->server == serverp && tsrp->status == srv_not_busy) {
+ /* REDIRECT */
+ tsrp->status = srv_busy;
break;
}
}
lock_ReleaseWrite(&cm_serverLock);
if (free_svr_list) {
- cm_FreeServerList(&serversp);
+ cm_FreeServerList(&serversp, 0);
*serverspp = serversp;
}
retry = 1;
}
}
for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
- if (tsrp->server == serverp)
- tsrp->status = offline;
+ if (tsrp->server == serverp) {
+ /* REDIRECT */
+ if (errorCode == VNOVOL || errorCode == VMOVED) {
+ tsrp->status = srv_deleted;
+ if (fidp) {
+ cm_ForceUpdateVolume(fidp, userp, reqp);
+ }
+ } else
+ tsrp->status = srv_offline;
+ }
}
if (free_svr_list) {
- cm_FreeServerList(&serversp);
+ cm_FreeServerList(&serversp, 0);
*serverspp = serversp;
}
if ( timeLeft > 2 )
lock_ReleaseWrite(&cm_serverLock);
if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
allDown = 0;
- if (tsrp->status == busy) {
+ if (tsrp->status == srv_deleted) {
+ /* skip this entry. no longer valid. */;
+ } else if (tsrp->status == srv_busy) {
allOffline = 0;
someBusy = 1;
- } else if (tsrp->status == offline) {
+ } else if (tsrp->status == srv_offline) {
allBusy = 0;
someOffline = 1;
} else {
cm_GetServerNoLock(tsp);
if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
allDown = 0;
- if (tsrp->status == busy) {
+ if (tsrp->status == srv_busy) {
allOffline = 0;
someBusy = 1;
- } else if (tsrp->status == offline) {
+ } else if (tsrp->status == srv_offline) {
allBusy = 0;
someOffline = 1;
} else {
cm_PutServerNoLock(tsp);
}
lock_ReleaseWrite(&cm_serverLock);
- cm_FreeServerList(serverspp);
+ cm_FreeServerList(serverspp, 0);
if (allDown)
return 0;
return 1;
}
-long cm_Conn(struct cm_fid *fidp, struct cm_user *userp, cm_req_t *reqp,
- cm_conn_t **connpp)
+/*
+ * The returned cm_conn_t ** object is released in the subsequent call
+ * to cm_Analyze().
+ */
+long cm_ConnFromFID(struct cm_fid *fidp, struct cm_user *userp, cm_req_t *reqp,
+ cm_conn_t **connpp)
{
long code;
cm_serverRef_t **serverspp;
}
code = cm_ConnByMServers(*serverspp, userp, reqp, connpp);
- cm_FreeServerList(serverspp);
+ cm_FreeServerList(serverspp, 0);
+ return code;
+}
+
+
+long cm_ConnFromVolume(struct cm_volume *volp, unsigned long volid, struct cm_user *userp, cm_req_t *reqp,
+ cm_conn_t **connpp)
+{
+ long code;
+ cm_serverRef_t **serverspp;
+
+ serverspp = cm_GetVolServers(volp, volid);
+
+ code = cm_ConnByMServers(*serverspp, userp, reqp, connpp);
+ cm_FreeServerList(serverspp, 0);
return code;
}
-extern struct rx_connection *
+
+extern struct rx_connection *
cm_GetRxConn(cm_conn_t *connp)
{
struct rx_connection * rxconn;
extern long cm_ConnByServer(struct cm_server *, struct cm_user *, cm_conn_t **);
-extern long cm_Conn(struct cm_fid *, struct cm_user *, struct cm_req *,
+extern long cm_ConnFromFID(struct cm_fid *, struct cm_user *, struct cm_req *,
cm_conn_t **);
+extern long cm_ConnFromVolume(struct cm_volume *volp, unsigned long volid,
+ struct cm_user *userp, cm_req_t *reqp,
+ cm_conn_t **connpp);
+
extern void cm_PutConn(cm_conn_t *connp);
extern void cm_GCConnections(cm_server_t *serverp);
long cm_daemonCheckCBInterval = 60;
long cm_daemonCheckLockInterval = 60;
long cm_daemonTokenCheckInterval = 180;
+long cm_daemonCheckBusyVolInterval = 600;
osi_rwlock_t cm_daemonLock;
if (code == ERROR_SUCCESS)
cm_daemonTokenCheckInterval = dummy;
+ dummyLen = sizeof(DWORD);
+ code = RegQueryValueEx(parmKey, "BusyVolumeCheckInterval", NULL, NULL,
+ (BYTE *) &dummy, &dummyLen);
+ if (code == ERROR_SUCCESS)
+ cm_daemonCheckBusyVolInterval = dummy;
+
RegCloseKey(parmKey);
}
time_t lastDownServerCheck;
time_t lastUpServerCheck;
time_t lastTokenCacheCheck;
+ time_t lastBusyVolCheck;
char thostName[200];
unsigned long code;
struct hostent *thp;
lastDownServerCheck = now - cm_daemonCheckDownInterval/2 + (rand() % cm_daemonCheckDownInterval);
lastUpServerCheck = now - cm_daemonCheckUpInterval/2 + (rand() % cm_daemonCheckUpInterval);
lastTokenCacheCheck = now - cm_daemonTokenCheckInterval/2 + (rand() % cm_daemonTokenCheckInterval);
+ lastBusyVolCheck = now - cm_daemonCheckBusyVolInterval/2 * (rand() % cm_daemonCheckBusyVolInterval);
while (daemon_ShutdownFlag == 0) {
/* check to see if the listener threads halted due to network
now = osi_Time();
}
+ if (now > lastBusyVolCheck + cm_daemonCheckBusyVolInterval) {
+ lastVolCheck = now;
+ cm_CheckBusyVolumes();
+ now = osi_Time();
+ }
+
if (now > lastCBExpirationCheck + cm_daemonCheckCBInterval) {
lastCBExpirationCheck = now;
cm_CheckCBExpiration();
/* now we're ready to do the store operation */
do {
- code = cm_Conn(&scp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
if (code)
continue;
/* now we're ready to do the store operation */
do {
- code = cm_Conn(&scp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
if (code)
continue;
/* now make the call */
do {
- code = cm_Conn(&scp->fid, up, reqp, &connp);
+ code = cm_ConnFromFID(&scp->fid, up, reqp, &connp);
if (code)
continue;
cm_data.fakeDirVersion = cm_data.rootSCachep->dataVersion;
// yj: first we make a call to cm_initLocalMountPoints
- // to read all the local mount points from an ini file
+ // to read all the local mount points from the registry
cm_InitLocalMountPoints();
// then we make a call to InitFakeRootDir to create
int cm_FakeRootFid(cm_fid_t *fidp)
{
fidp->cell = AFS_FAKE_ROOT_CELL_ID; /* root cell */
- fidp->volume = AFS_FAKE_ROOT_VOL_ID; /* root.afs ? */
+ fidp->volume = AFS_FAKE_ROOT_VOL_ID; /* root.afs ? */
fidp->vnode = 0x1;
fidp->unique = 0x1;
return 0;
lock_ObtainMutex(&cm_Freelance_Lock); /* always scache then freelance lock */
for (i=0; i<cm_noLocalMountPoints; i++) {
hash = CM_SCACHE_HASH(&aFid);
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (scp->fid.volume == aFid.volume &&
scp->fid.vnode == aFid.vnode &&
scp->fid.unique == aFid.unique
cm_ReleaseSCacheNoLock(scp);
// take the scp out of the hash
- for (lscpp = &cm_data.hashTablep[hash], tscp = cm_data.hashTablep[hash];
+ for (lscpp = &cm_data.scacheHashTablep[hash], tscp = cm_data.scacheHashTablep[hash];
tscp;
lscpp = &tscp->nextp, tscp = tscp->nextp) {
if (tscp == scp) {
}
-// yj: open up the ini file and read all the local mount
+// yj: open up the registry and read all the local mount
// points that are stored there. Part of the initialization
// process for the freelance client.
/* to be called while holding freelance lock unless during init. */
if (code == 0) {
cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
- dwMountPoints = 2;
+ cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
+ dwMountPoints = 3;
}
}
if (code == 0) {
cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
+ cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
}
return 0;
}
#endif
lock_ObtainWrite(&cm_scacheLock);
- for (i=0; i<cm_data.hashTableSize; i++) {
- for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
+ for (i=0; i<cm_data.scacheHashTableSize; i++) {
+ for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
if (scp->fid.volume == volume && scp->fid.cell == cell) {
cm_HoldSCacheNoLock(scp);
lock_ReleaseWrite(&cm_scacheLock);
int hash;
lock_ObtainWrite(&cm_scacheLock);
- for (hash=0; hash < cm_data.hashTableSize; hash++) {
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
cm_HoldSCacheNoLock(scp);
lock_ReleaseWrite(&cm_scacheLock);
lock_ObtainMutex(&scp->mx);
do {
acl.AFSOpaque_val = ioctlp->outDatap;
acl.AFSOpaque_len = 0;
- code = cm_Conn(&scp->fid, userp, &req, &connp);
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
if (code) continue;
callp = cm_GetRxConn(connp);
do {
acl.AFSOpaque_val = ioctlp->inDatap;
acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
- code = cm_Conn(&scp->fid, userp, &req, &connp);
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
if (code) continue;
callp = cm_GetRxConn(connp);
cm_InitReq(&req);
lock_ObtainWrite(&cm_scacheLock);
- for (i=0; i<cm_data.hashTableSize; i++) {
- for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
+ for (i=0; i<cm_data.scacheHashTableSize; i++) {
+ for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
cm_HoldSCacheNoLock(scp);
lock_ReleaseWrite(&cm_scacheLock);
return CM_ERROR_READONLY;
}
- code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, &tvp);
+ code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req,
+ CM_GETVOL_FLAG_CREATE, &tvp);
if (code) {
cm_ReleaseSCache(scp);
return code;
}
do {
- code = cm_Conn(&scp->fid, userp, &req, &tcp);
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
if (code) continue;
callp = cm_GetRxConn(tcp);
cm_scache_t *scp;
char offLineMsg[256];
char motd[256];
- cm_conn_t *tcp;
+ cm_conn_t *connp;
register long code;
AFSFetchVolumeStatus volStat;
register char *cp;
OfflineMsg = offLineMsg;
MOTD = motd;
do {
- code = cm_Conn(&scp->fid, userp, &req, &tcp);
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
if (code) continue;
- callp = cm_GetRxConn(tcp);
+ callp = cm_GetRxConn(connp);
code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
&volStat, &Name, &OfflineMsg, &MOTD);
rx_PutConnection(callp);
- } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
+ } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
code = cm_MapRPCError(code, &req);
cm_ReleaseSCache(scp);
if (!cellp)
return CM_ERROR_NOSUCHCELL;
- code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
+ code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
if (code) return code;
cp = ioctlp->outDatap;
cp += sizeof(long);
}
lock_ReleaseRead(&cm_serverLock);
- cm_FreeServerList(tsrpp);
+ cm_FreeServerList(tsrpp, 0);
lock_ReleaseMutex(&tvp->mx);
/* still room for terminating NULL, add it on */
long code;
lock_ObtainMutex(&cp->mx);
/* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
- cm_FreeServerList(&cp->vlServersp);
+ cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
cp->vlServersp = NULL;
code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
#ifdef AFS_AFSDB_ENV
lock_ReleaseRead(&cm_serverLock);
if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
allDown = 0;
- if (tsrp->status == busy) {
+ if (tsrp->status == srv_busy) {
allOffline = 0;
someBusy = 1;
- } else if (tsrp->status == offline) {
+ } else if (tsrp->status == srv_offline) {
allBusy = 0;
someOffline = 1;
} else {
if (!cellp)
return CM_ERROR_NOSUCHCELL;
- code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
+ code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
if (code)
return code;
lock_ObtainMutex(&tvp->mx);
tsrpp = cm_GetVolServers(tvp, volume);
code = cm_CheckServersStatus(*tsrpp);
- cm_FreeServerList(tsrpp);
+ cm_FreeServerList(tsrpp, 0);
lock_ReleaseMutex(&tvp->mx);
cm_PutVolume(tvp);
return 0;
}
afs_uint64
+ComputeSizeOfVolumeHT(DWORD maxvols)
+{
+ afs_uint64 size;
+ size = osi_PrimeLessThan((afs_uint32)(maxvols/7 + 1)) * sizeof(cm_volume_t *);
+ return size;
+}
+
+afs_uint64
ComputeSizeOfCells(DWORD maxcells)
{
afs_uint64 size;
ComputeSizeOfSCacheHT(DWORD stats)
{
afs_uint64 size;
- size = (stats + 10) / 2 * sizeof(cm_scache_t *);;
+ size = osi_PrimeLessThan(stats / 2 + 1) * sizeof(cm_scache_t *);;
return size;
}
size = ComputeSizeOfConfigData()
+ ComputeSizeOfVolumes(maxVols)
+ + 4 * ComputeSizeOfVolumeHT(maxVols)
+ ComputeSizeOfCells(maxCells)
+ ComputeSizeOfACLCache(stats)
+ ComputeSizeOfSCache(stats)
afsi_log(" blockSize = %d", cm_data.blockSize);
afsi_log(" bufferSize = %d", cm_data.bufferSize);
afsi_log(" cacheType = %d", cm_data.cacheType);
+ afsi_log(" volumeHashTableSize = %d", cm_data.volumeHashTableSize);
afsi_log(" currentVolumes = %d", cm_data.currentVolumes);
afsi_log(" maxVolumes = %d", cm_data.maxVolumes);
afsi_log(" currentCells = %d", cm_data.currentCells);
afsi_log(" maxCells = %d", cm_data.maxCells);
- afsi_log(" hashTableSize = %d", cm_data.hashTableSize);
+ afsi_log(" scacheHashTableSize = %d", cm_data.scacheHashTableSize);
afsi_log(" currentSCaches = %d", cm_data.currentSCaches);
afsi_log(" maxSCaches = %d", cm_data.maxSCaches);
fprintf(stderr," blockSize = %d\n", config_data_p->blockSize);
fprintf(stderr," bufferSize = %d\n", config_data_p->bufferSize);
fprintf(stderr," cacheType = %d\n", config_data_p->cacheType);
+ fprintf(stderr," volumeHashTableSize = %d", config_data_p->volumeHashTableSize);
fprintf(stderr," currentVolumes = %d\n", config_data_p->currentVolumes);
fprintf(stderr," maxVolumes = %d\n", config_data_p->maxVolumes);
fprintf(stderr," currentCells = %d\n", config_data_p->currentCells);
fprintf(stderr," maxCells = %d\n", config_data_p->maxCells);
- fprintf(stderr," hashTableSize = %d\n", config_data_p->hashTableSize);
+ fprintf(stderr," scacheHashTableSize = %d\n", config_data_p->scacheHashTableSize);
fprintf(stderr," currentSCaches = %d\n", config_data_p->currentSCaches);
fprintf(stderr," maxSCaches = %d\n", config_data_p->maxSCaches);
cm_data = *config_data_p;
afsi_log(" blockSize = %d", config_data_p->blockSize);
afsi_log(" bufferSize = %d", config_data_p->bufferSize);
afsi_log(" cacheType = %d", config_data_p->cacheType);
+ afsi_log(" volumeHashTableSize = %d", config_data_p->volumeHashTableSize);
afsi_log(" currentVolumes = %d", config_data_p->currentVolumes);
afsi_log(" maxVolumes = %d", config_data_p->maxVolumes);
afsi_log(" currentCells = %d", config_data_p->currentCells);
afsi_log(" maxCells = %d", config_data_p->maxCells);
- afsi_log(" hashTableSize = %d", config_data_p->hashTableSize);
+ afsi_log(" scacheHashTableSize = %d", config_data_p->scacheHashTableSize);
afsi_log(" currentSCaches = %d", config_data_p->currentSCaches);
afsi_log(" maxSCaches = %d", config_data_p->maxSCaches);
cm_data.chunkSize = chunkSize;
cm_data.blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
cm_data.bufferSize = mappingSize;
- cm_data.hashTableSize = osi_PrimeLessThan(stats / 2 + 1);
+ cm_data.scacheHashTableSize = osi_PrimeLessThan(stats / 2 + 1);
+ cm_data.volumeHashTableSize = osi_PrimeLessThan((afs_uint32)(maxVols/7 + 1));
if (virtualCache) {
cm_data.cacheType = CM_BUF_CACHETYPE_VIRTUAL;
} else {
baseAddress += ComputeSizeOfConfigData();
cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
baseAddress += ComputeSizeOfVolumes(maxVols);
+ cm_data.volumeNameHashTablep = (cm_volume_t **)baseAddress;
+ baseAddress += ComputeSizeOfVolumeHT(maxVols);
+ cm_data.volumeRWIDHashTablep = (cm_volume_t **)baseAddress;
+ baseAddress += ComputeSizeOfVolumeHT(maxVols);
+ cm_data.volumeROIDHashTablep = (cm_volume_t **)baseAddress;
+ baseAddress += ComputeSizeOfVolumeHT(maxVols);
+ cm_data.volumeBKIDHashTablep = (cm_volume_t **)baseAddress;
+ baseAddress += ComputeSizeOfVolumeHT(maxVols);
cm_data.cellBaseAddress = (cm_cell_t *) baseAddress;
baseAddress += ComputeSizeOfCells(maxCells);
cm_data.aclBaseAddress = (cm_aclent_t *) baseAddress;
baseAddress += ComputeSizeOfACLCache(stats);
cm_data.scacheBaseAddress = (cm_scache_t *) baseAddress;
baseAddress += ComputeSizeOfSCache(stats);
- cm_data.hashTablep = (cm_scache_t **) baseAddress;
+ cm_data.scacheHashTablep = (cm_scache_t **) baseAddress;
baseAddress += ComputeSizeOfSCacheHT(stats);
cm_data.dnlcBaseAddress = (cm_nc_t *) baseAddress;
baseAddress += ComputeSizeOfDNLCache();
- cm_data.buf_hashTablepp = (cm_buf_t **) baseAddress;
+ cm_data.buf_scacheHashTablepp = (cm_buf_t **) baseAddress;
baseAddress += ComputeSizeOfDataHT(cacheBlocks);
cm_data.buf_fileHashTablepp = (cm_buf_t **) baseAddress;
baseAddress += ComputeSizeOfDataHT(cacheBlocks);
cm_aclent_t * aclLRUp;
cm_aclent_t * aclLRUEndp;
- cm_scache_t ** hashTablep;
- afs_uint32 hashTableSize;
+ cm_scache_t ** scacheHashTablep;
+ afs_uint32 scacheHashTableSize;
+ cm_scache_t * allSCachesp;
afs_uint32 currentSCaches;
afs_uint32 maxSCaches;
cm_scache_t * scacheLRUFirstp;
cm_scache_t * scacheLRULastp;
+ cm_volume_t ** volumeNameHashTablep;
+ cm_volume_t ** volumeRWIDHashTablep;
+ cm_volume_t ** volumeROIDHashTablep;
+ cm_volume_t ** volumeBKIDHashTablep;
+ afs_uint32 volumeHashTableSize;
+ cm_volume_t * volumeLRUFirstp;
+ cm_volume_t * volumeLRULastp;
+
cm_nc_t * ncfreelist;
cm_nc_t * nameCache;
cm_nc_t ** nameHash;
cm_buf_t * buf_freeListEndp;
cm_buf_t * buf_dirtyListp;
cm_buf_t * buf_dirtyListEndp;
- cm_buf_t ** buf_hashTablepp;
+ cm_buf_t ** buf_scacheHashTablepp;
cm_buf_t ** buf_fileHashTablepp;
cm_buf_t * buf_allp;
afs_uint64 buf_nbuffers;
#endif
/* must be called with cm_scacheLock write-locked! */
-void cm_AdjustLRU(cm_scache_t *scp)
+void cm_AdjustScacheLRU(cm_scache_t *scp)
{
if (scp == cm_data.scacheLRULastp)
cm_data.scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
if (scp->flags & CM_SCACHEFLAG_INHASH) {
/* hash it out first */
i = CM_SCACHE_HASH(&scp->fid);
- for (lscpp = &cm_data.hashTablep[i], tscp = cm_data.hashTablep[i];
+ for (lscpp = &cm_data.scacheHashTablep[i], tscp = cm_data.scacheHashTablep[i];
tscp;
lscpp = &tscp->nextp, tscp = tscp->nextp) {
if (tscp == scp) {
scp;
scp = (cm_scache_t *) osi_QPrev(&scp->q))
{
- osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
+ osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.scacheHashTablep);
if (scp->refCount == 0) {
if (scp->flags & CM_SCACHEFLAG_DELETED) {
/* now remove from the LRU queue and put it back at the
* head of the LRU queue.
*/
- cm_AdjustLRU(scp);
+ cm_AdjustScacheLRU(scp);
/* and we're done */
return scp;
/* now remove from the LRU queue and put it back at the
* head of the LRU queue.
*/
- cm_AdjustLRU(scp);
+ cm_AdjustScacheLRU(scp);
/* and we're done */
return scp;
/* There were no deleted scache objects that we could use. Try to find
* one that simply hasn't been used in a while.
*/
- for ( scp = cm_data.scacheLRULastp;
- scp;
- scp = (cm_scache_t *) osi_QPrev(&scp->q))
- {
- /* It is possible for the refCount to be zero and for there still
- * to be outstanding dirty buffers. If there are dirty buffers,
- * we must not recycle the scp. */
- if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
- if (!buf_DirtyBuffersExist(&scp->fid)) {
- if (!cm_RecycleSCache(scp, 0)) {
- /* we found an entry, so return it */
- /* now remove from the LRU queue and put it back at the
- * head of the LRU queue.
- */
- cm_AdjustLRU(scp);
-
- /* and we're done */
- return scp;
- }
- } else {
- osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
- }
- }
- }
- osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
-
- return NULL;
+ for ( scp = cm_data.scacheLRULastp;
+ scp;
+ scp = (cm_scache_t *) osi_QPrev(&scp->q))
+ {
+ /* It is possible for the refCount to be zero and for there still
+ * to be outstanding dirty buffers. If there are dirty buffers,
+ * we must not recycle the scp. */
+ if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
+ if (!buf_DirtyBuffersExist(&scp->fid)) {
+ if (!cm_RecycleSCache(scp, 0)) {
+ /* we found an entry, so return it */
+ /* now remove from the LRU queue and put it back at the
+ * head of the LRU queue.
+ */
+ cm_AdjustScacheLRU(scp);
+
+ /* and we're done */
+ return scp;
+ }
+ } else {
+ osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
+ }
+ }
+ }
+ osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
+
+ return NULL;
}
/* if we get here, we should allocate a new scache entry. We either are below
* quota or we have a leak and need to allocate a new one to avoid panicing.
*/
scp = cm_data.scacheBaseAddress + cm_data.currentSCaches;
- osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
+ osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.scacheHashTablep);
memset(scp, 0, sizeof(cm_scache_t));
scp->magic = CM_SCACHE_MAGIC;
lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
cm_data.currentSCaches++;
cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
cm_dnlcPurgevp(scp);
+ scp->allNextp = cm_data.allSCachesp;
+ cm_data.allSCachesp = scp;
return scp;
}
}
}
- for ( i=0; i < cm_data.hashTableSize; i++ ) {
- for ( scp = cm_data.hashTablep[i]; scp; scp = scp->nextp ) {
+ for ( i=0; i < cm_data.scacheHashTableSize; i++ ) {
+ for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
if (scp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
{
cm_scache_t * scp;
- for ( scp = cm_data.scacheLRULastp; scp;
- scp = (cm_scache_t *) osi_QPrev(&scp->q) ) {
+ for ( scp = cm_data.allSCachesp; scp;
+ scp = scp->allNextp ) {
if (scp->randomACLp) {
lock_ObtainMutex(&scp->mx);
cm_FreeAllACLEnts(scp);
if (osi_Once(&once)) {
lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock");
if ( newFile ) {
- memset(cm_data.hashTablep, 0, sizeof(cm_scache_t *) * cm_data.hashTableSize);
+ memset(cm_data.scacheHashTablep, 0, sizeof(cm_scache_t *) * cm_data.scacheHashTableSize);
+ cm_data.allSCachesp = NULL;
cm_data.currentSCaches = 0;
cm_data.maxSCaches = maxSCaches;
cm_data.scacheLRUFirstp = cm_data.scacheLRULastp = NULL;
} else {
cm_scache_t * scp;
- for ( scp = cm_data.scacheLRULastp; scp;
- scp = (cm_scache_t *) osi_QPrev(&scp->q) ) {
+ for ( scp = cm_data.allSCachesp; scp;
+ scp = scp->allNextp ) {
lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
}
lock_ObtainWrite(&cm_scacheLock);
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (cm_FidCmp(fidp, &scp->fid) == 0) {
cm_HoldSCacheNoLock(scp);
- cm_AdjustLRU(scp);
+ cm_AdjustScacheLRU(scp);
lock_ReleaseWrite(&cm_scacheLock);
return scp;
}
// yj: check if we have the scp, if so, we don't need
// to do anything else
lock_ObtainWrite(&cm_scacheLock);
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (cm_FidCmp(fidp, &scp->fid) == 0) {
#ifdef DEBUG_REFCOUNT
afsi_log("%s:%d cm_GetSCache (1) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
#endif
cm_HoldSCacheNoLock(scp);
*outScpp = scp;
- cm_AdjustLRU(scp);
+ cm_AdjustScacheLRU(scp);
lock_ReleaseWrite(&cm_scacheLock);
return 0;
}
scp->dotdotFid.unique=1;
scp->dotdotFid.vnode=1;
scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
- scp->nextp=cm_data.hashTablep[hash];
- cm_data.hashTablep[hash]=scp;
+ scp->nextp=cm_data.scacheHashTablep[hash];
+ cm_data.scacheHashTablep[hash]=scp;
scp->flags |= CM_SCACHEFLAG_INHASH;
scp->refCount = 1;
osi_Log1(afsd_logp,"cm_GetSCache (freelance) sets refCount to 1 scp 0x%x", scp);
if (!cellp)
return CM_ERROR_NOSUCHCELL;
- code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
+ code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &volp);
if (code)
return code;
lock_ObtainWrite(&cm_scacheLock);
/* otherwise, we have the volume, now reverify that the scp doesn't
* exist, and proceed.
*/
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (cm_FidCmp(fidp, &scp->fid) == 0) {
#ifdef DEBUG_REFCOUNT
afsi_log("%s:%d cm_GetSCache (3) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
#endif
cm_HoldSCacheNoLock(scp);
osi_assert(scp->volp == volp);
- cm_AdjustLRU(scp);
+ cm_AdjustScacheLRU(scp);
lock_ReleaseWrite(&cm_scacheLock);
if (volp)
cm_PutVolume(volp);
scp->dotdotFid = volp->dotdotFid;
}
- if (volp->roID == fidp->volume)
+ if (volp->ro.ID == fidp->volume)
scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
- else if (volp->bkID == fidp->volume)
+ else if (volp->bk.ID == fidp->volume)
scp->flags |= CM_SCACHEFLAG_RO;
}
- scp->nextp = cm_data.hashTablep[hash];
- cm_data.hashTablep[hash] = scp;
+ scp->nextp = cm_data.scacheHashTablep[hash];
+ cm_data.scacheHashTablep[hash] = scp;
scp->flags |= CM_SCACHEFLAG_INHASH;
scp->refCount = 1;
osi_Log1(afsd_logp,"cm_GetSCache sets refCount to 1 scp 0x%x", scp);
if (cm_FidCmp(&scp->fid, &parent_fid)) {
i = CM_SCACHE_HASH(&parent_fid);
- for (pscp = cm_data.hashTablep[i]; pscp; pscp = pscp->nextp) {
+ for (pscp = cm_data.scacheHashTablep[i]; pscp; pscp = pscp->nextp) {
if (!cm_FidCmp(&pscp->fid, &parent_fid)) {
cm_HoldSCacheNoLock(pscp);
break;
struct cm_volume *volp = NULL;
cm_GetVolumeByID(cellp, scp->fid.volume, userp,
- (cm_req_t *) NULL, &volp);
+ (cm_req_t *) NULL, CM_GETVOL_FLAG_CREATE, &volp);
osi_Log2(afsd_logp, "old data from server %x volume %s",
scp->cbServerp->addr.sin_addr.s_addr,
volp ? volp->namep : "(unknown)");
osi_assert(fidp->cell != 0);
lock_ObtainWrite(&cm_scacheLock);
- for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
+ for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
if (cm_FidCmp(fidp, &scp->fid) == 0) {
lock_ReleaseWrite(&cm_scacheLock);
return scp->fileType;
sprintf(output, "%s - dumping scache - cm_data.currentSCaches=%d, cm_data.maxSCaches=%d\r\n", cookie, cm_data.currentSCaches, cm_data.maxSCaches);
WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
- for (scp = cm_data.scacheLRULastp; scp; scp = (cm_scache_t *) osi_QPrev(&scp->q))
+ for (scp = cm_data.allSCachesp; scp; scp = scp->allNextp)
{
if (scp->refCount != 0)
{
}
}
- sprintf(output, "%s - dumping cm_data.hashTable - cm_data.hashTableSize=%d\r\n", cookie, cm_data.hashTableSize);
+ sprintf(output, "%s - dumping cm_data.hashTable - cm_data.scacheHashTableSize=%d\r\n", cookie, cm_data.scacheHashTableSize);
WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
- for (i = 0; i < cm_data.hashTableSize; i++)
+ for (i = 0; i < cm_data.scacheHashTableSize; i++)
{
- for(scp = cm_data.hashTablep[i]; scp; scp=scp->nextp)
+ for(scp = cm_data.scacheHashTablep[i]; scp; scp=scp->nextp)
{
if (scp->refCount != 0)
{
osi_queue_t q; /* lru queue; cm_scacheLock */
afs_uint32 magic;
struct cm_scache *nextp; /* next in hash; cm_scacheLock */
+ struct cm_scache *allNextp; /* next in all scache list; cm_scacheLock */
cm_fid_t fid;
afs_uint32 flags; /* flags; locked by mx */
((fidp)->volume + \
(fidp)->vnode + \
(fidp)->unique)) \
- % cm_data.hashTableSize)
+ % cm_data.scacheHashTableSize)
#include "cm_conn.h"
#include "cm_buf.h"
long usecs;
Capabilities caps = {0, 0};
char hoststr[16];
+ cm_req_t req;
lock_ObtainMutex(&tsp->mx);
if (tsp->flags & CM_SERVERFLAG_PINGING) {
osi_LogSaveString(afsd_logp, hoststr),
tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
tsp->capabilities);
+
+ /* Now update the volume status if necessary */
+ if (wasDown) {
+ cm_server_vols_t * tsrvp;
+ cm_volume_t * volp;
+ int i;
+
+ for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
+ for (i=0; i<NUM_SERVER_VOLS; i++) {
+ if (tsrvp->ids[i] != 0) {
+ cm_InitReq(&req);
+
+ code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
+ &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
+ if (code == 0) {
+ cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
+ cm_PutVolume(volp);
+ }
+ }
+ }
+ }
+ }
} else {
/* mark server as down */
tsp->flags |= CM_SERVERFLAG_DOWN;
osi_LogSaveString(afsd_logp, hoststr),
tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
tsp->capabilities);
+
+ /* Now update the volume status if necessary */
+ if (!wasDown) {
+ cm_server_vols_t * tsrvp;
+ cm_volume_t * volp;
+ int i;
+
+ for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
+ for (i=0; i<NUM_SERVER_VOLS; i++) {
+ if (tsrvp->ids[i] != 0) {
+ cm_InitReq(&req);
+
+ code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
+ &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
+ if (code == 0) {
+ cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
+ cm_PutVolume(volp);
+ }
+ }
+ }
+ }
+ }
}
if (tsp->waitCount == 0)
osi_assert(socketp->sin_family == AF_INET);
tsp = malloc(sizeof(*tsp));
- memset(tsp, 0, sizeof(*tsp));
- tsp->type = type;
- tsp->cellp = cellp;
- tsp->refCount = 1;
- lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
- tsp->addr = *socketp;
- tsp->flags = CM_SERVERFLAG_DOWN; /* assume down; ping will mark up if available */
-
- cm_SetServerPrefs(tsp);
-
- lock_ObtainWrite(&cm_serverLock); /* get server lock */
- tsp->allNextp = cm_allServersp;
- cm_allServersp = tsp;
- lock_ReleaseWrite(&cm_serverLock); /* release server lock */
-
- cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
+ if (tsp) {
+ memset(tsp, 0, sizeof(*tsp));
+ tsp->type = type;
+ tsp->cellp = cellp;
+ tsp->refCount = 1;
+ lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
+ tsp->addr = *socketp;
+ tsp->flags = CM_SERVERFLAG_DOWN; /* assume down; ping will mark up if available */
+
+ cm_SetServerPrefs(tsp);
+
+ lock_ObtainWrite(&cm_serverLock); /* get server lock */
+ tsp->allNextp = cm_allServersp;
+ cm_allServersp = tsp;
+ lock_ReleaseWrite(&cm_serverLock); /* release server lock */
+
+ cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
+ }
return tsp;
}
return tsp;
}
-cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp)
+cm_server_vols_t *cm_NewServerVols(void) {
+ cm_server_vols_t *tsvp;
+
+ tsvp = malloc(sizeof(*tsvp));
+ if (tsvp)
+ memset(tsvp, 0, sizeof(*tsvp));
+
+ return tsvp;
+}
+
+cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
{
cm_serverRef_t *tsrp;
+ cm_server_vols_t **tsrvpp = NULL;
+ afs_uint32 *slotp = NULL;
+ int found = 0;
cm_GetServer(serverp);
tsrp = malloc(sizeof(*tsrp));
tsrp->server = serverp;
- tsrp->status = not_busy;
+ tsrp->status = srv_not_busy;
tsrp->next = NULL;
+ tsrp->volID = volID;
tsrp->refCount = 1;
+ /* if we have a non-zero volID, we need to add it to the list
+ * of volumes maintained by the server. There are two phases:
+ * (1) see if the volID is already in the list and (2) insert
+ * it into the first empty slot if it is not.
+ */
+ if (volID) {
+ lock_ObtainMutex(&serverp->mx);
+
+ tsrvpp = &serverp->vols;
+ while (*tsrvpp) {
+ int i;
+
+ for (i=0; i<NUM_SERVER_VOLS; i++) {
+ if ((*tsrvpp)->ids[i] == volID) {
+ found = 1;
+ break;
+ } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
+ slotp = &(*tsrvpp)->ids[i];
+ }
+ }
+
+ if (found)
+ break;
+
+ tsrvpp = &(*tsrvpp)->nextp;
+ }
+
+ if (!found) {
+ if (slotp) {
+ *slotp = volID;
+ } else {
+ /* if we didn't find an empty slot in a current
+ * page we must need a new page */
+ *tsrvpp = cm_NewServerVols();
+ if (*tsrvpp)
+ (*tsrvpp)->ids[0] = volID;
+ }
+ }
+
+ lock_ReleaseMutex(&serverp->mx);
+ }
+
return tsrp;
}
/* call cm_FreeServer while holding a write lock on cm_serverLock */
void cm_FreeServer(cm_server_t* serverp)
{
+ cm_server_vols_t * tsrvp, *nextp;
+
cm_PutServerNoLock(serverp);
if (serverp->refCount == 0)
{
}
}
}
+
+ /* free the volid list */
+ for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
+ nextp = tsrvp->nextp;
+ free(tsrvp);
+ }
+
free(serverp);
}
}
}
-void cm_FreeServerList(cm_serverRef_t** list)
+void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
+{
+ cm_server_vols_t * tsrvp;
+ int i;
+
+ if (volID == 0)
+ return;
+
+ for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
+ for (i=0; i<NUM_SERVER_VOLS; i++) {
+ if (tsrvp->ids[i] == volID) {
+ tsrvp->ids[i] = 0;;
+ break;
+ }
+ }
+ }
+}
+
+void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
{
cm_serverRef_t **current = list;
cm_serverRef_t **nextp = 0;
nextp = &(*current)->next;
if (--((*current)->refCount) == 0) {
next = *nextp;
+
+ if ((*current)->volID)
+ cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
cm_FreeServer((*current)->server);
free(*current);
*current = next;
} else {
- current = nextp;
+ if (flags & CM_FREESERVERLIST_DELETE) {
+ (*current)->status = srv_deleted;
+ if ((*current)->volID)
+ cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
+ }
+ current = nextp;
}
}
#include <winsock2.h>
#include <osi.h>
+/* this value is set to 1022 in order to */
+#define NUM_SERVER_VOLS (32 - sizeof(void *) / 4)
+typedef struct cm_server_vols {
+ afs_uint32 ids[NUM_SERVER_VOLS];
+ struct cm_server_vols *nextp;
+} cm_server_vols_t;
+
/* pointed to by volumes and cells without holds; cm_serverLock is obtained
* at the appropriate times to change the pointers to these servers.
*/
unsigned long refCount; /* locked by cm_serverLock */
osi_mutex_t mx;
unsigned short ipRank; /* server priority */
+ cm_server_vols_t * vols; /* by mx */
} cm_server_t;
-enum repstate {not_busy, busy, offline};
+enum repstate {srv_not_busy, srv_busy, srv_offline, srv_deleted};
typedef struct cm_serverRef {
struct cm_serverRef *next; /* locked by cm_serverLock */
struct cm_server *server; /* locked by cm_serverLock */
enum repstate status; /* locked by cm_serverLock */
unsigned long refCount; /* locked by cm_serverLock */
+ afs_uint32 volID; /* locked by cm_serverLock */
} cm_serverRef_t;
/* types */
extern cm_server_t *cm_NewServer(struct sockaddr_in *addrp, int type,
struct cm_cell *cellp);
-extern cm_serverRef_t *cm_NewServerRef(struct cm_server *serverp);
+extern cm_serverRef_t *cm_NewServerRef(struct cm_server *serverp, afs_uint32 volID);
extern LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp);
extern void cm_FreeServer(cm_server_t* server);
-extern void cm_FreeServerList(cm_serverRef_t** list);
+#define CM_FREESERVERLIST_DELETE 1
+
+extern void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags);
extern void cm_ForceNewConnectionsAllServers(void);
#include "afsd.h"
-/* Used by cm_FollowMountPoint */
-#define RWVOL 0
-#define ROVOL 1
-#define BACKVOL 2
-
#ifdef DEBUG
extern void afsi_log(char *pattern, ...);
#endif
return code;
}
+
/* called with a locked scp and chases the mount point, yielding outScpp.
* scp remains locked, just for simplicity of describing the interface.
*/
/* now we need to get the volume */
lock_ReleaseMutex(&scp->mx);
- code = cm_GetVolumeByName(cellp, volNamep, userp, reqp, 0, &volp);
+ if (cm_VolNameIsID(volNamep)) {
+ code = cm_GetVolumeByID(cellp, atoi(volNamep), userp, reqp,
+ CM_GETVOL_FLAG_CREATE, &volp);
+ } else {
+ code = cm_GetVolumeByName(cellp, volNamep, userp, reqp,
+ CM_GETVOL_FLAG_CREATE, &volp);
+ }
lock_ObtainMutex(&scp->mx);
if (code == 0) {
* the read-only, otherwise use the one specified.
*/
if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
- && volp->roID != 0 && type == RWVOL)
+ && volp->ro.ID != 0 && type == RWVOL)
type = ROVOL;
if (type == ROVOL)
- scp->mountRootFid.volume = volp->roID;
+ scp->mountRootFid.volume = volp->ro.ID;
else if (type == BACKVOL)
- scp->mountRootFid.volume = volp->bkID;
+ scp->mountRootFid.volume = volp->bk.ID;
else
- scp->mountRootFid.volume = volp->rwID;
+ scp->mountRootFid.volume = volp->rw.ID;
/* the rest of the fid is a magic number */
scp->mountRootFid.vnode = 1;
osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
cm_StartCallbackGrantingCall(NULL, &cbReq);
osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
/* now make the RPC */
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
do {
- code = cm_Conn(&scp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
if (code)
continue;
/* try the RPC now */
osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
/* try the RPC now */
osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
/* try the RPC now */
osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code) continue;
dirAFSFid.Volume = dscp->fid.volume;
/* try the RPC now */
osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
/* try the RPC now */
osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
do {
- code = cm_Conn(&dscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code)
continue;
osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
oldDscp, newDscp);
do {
- code = cm_Conn(&oldDscp->fid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&oldDscp->fid, userp, reqp, &connp);
if (code)
continue;
lock_ReleaseMutex(&scp->mx);
do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
if (code)
break;
osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
do {
- code = cm_Conn(&cfid, userp, reqp, &connp);
+ code = cm_ConnFromFID(&cfid, userp, reqp, &connp);
if (code)
break;
lock_ReleaseMutex(&scp->mx);
do {
- code = cm_Conn(&cfid, userp,
+ code = cm_ConnFromFID(&cfid, userp,
&req, &connp);
if (code)
break;
cm_file_lock_t *fileLock;
unsigned int i;
- for (i = 0; i < cm_data.hashTableSize; i++)
+ for (i = 0; i < cm_data.scacheHashTableSize; i++)
{
- for ( scp = cm_data.hashTablep[i]; scp; scp = scp->nextp ) {
+ for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
while (scp->fileLocksH != NULL) {
lock_ObtainMutex(&scp->mx);
lock_ObtainWrite(&cm_scacheLock);
cm_volume_t * volp;
afs_uint32 count;
- for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->nextp, count++) {
+ for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->allNextp, count++) {
if ( volp->magic != CM_VOLUME_MAGIC ) {
afsi_log("cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC");
fprintf(stderr, "cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC\n");
fprintf(stderr, "cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC\n");
return -2;
}
- if ( volp->nextp && volp->nextp->magic != CM_VOLUME_MAGIC ) {
- afsi_log("cm_ValidateVolume failure: volp->nextp->magic != CM_VOLUME_MAGIC");
- fprintf(stderr, "cm_ValidateVolume failure: volp->nextp->magic != CM_VOLUME_MAGIC\n");
+ if ( volp->allNextp && volp->allNextp->magic != CM_VOLUME_MAGIC ) {
+ afsi_log("cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC");
+ fprintf(stderr, "cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC\n");
return -3;
}
if ( count != 0 && volp == cm_data.allVolumesp ||
{
cm_volume_t * volp;
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp)
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
+
+ if (volp->rw.ID)
+ cm_VolumeStatusNotification(volp, volp->rw.ID, volp->rw.state, vl_alldown);
+ if (volp->ro.ID)
+ cm_VolumeStatusNotification(volp, volp->ro.ID, volp->ro.state, vl_alldown);
+ if (volp->bk.ID)
+ cm_VolumeStatusNotification(volp, volp->bk.ID, volp->bk.state, vl_alldown);
+
lock_FinalizeMutex(&volp->mx);
+ }
return 0;
}
cm_data.allVolumesp = NULL;
cm_data.currentVolumes = 0;
cm_data.maxVolumes = maxVols;
+ memset(cm_data.volumeNameHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
+ memset(cm_data.volumeRWIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
+ memset(cm_data.volumeROIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
+ memset(cm_data.volumeBKIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
+ cm_data.volumeLRUFirstp = cm_data.volumeLRULastp = NULL;
} else {
cm_volume_t * volp;
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
volp->flags |= CM_VOLUMEFLAG_RESET;
- volp->rwServersp = NULL;
- volp->roServersp = NULL;
- volp->bkServersp = NULL;
+ volp->rw.state = vl_unknown;
+ volp->rw.serversp = NULL;
+ volp->ro.state = vl_unknown;
+ volp->ro.serversp = NULL;
+ volp->bk.state = vl_unknown;
+ volp->bk.serversp = NULL;
+ if (volp->rw.ID)
+ cm_VolumeStatusNotification(volp, volp->rw.ID, vl_alldown, volp->rw.state);
+ if (volp->ro.ID)
+ cm_VolumeStatusNotification(volp, volp->ro.ID, vl_alldown, volp->ro.state);
+ if (volp->bk.ID)
+ cm_VolumeStatusNotification(volp, volp->bk.ID, vl_alldown, volp->bk.state);
}
}
osi_EndOnce(&once);
}
}
+
+/* returns true if the id is a decimal integer, in which case we interpret it
+ * as an id. make the cache manager much simpler.
+ * Stolen from src/volser/vlprocs.c */
+int
+cm_VolNameIsID(char *aname)
+{
+ int tc;
+ while (tc = *aname++) {
+ if (tc > '9' || tc < '0')
+ return 0;
+ }
+ return 1;
+}
+
+
/*
* Update a volume. Caller holds volume's lock (volp->mx).
*
#ifdef MULTIHOMED
struct uvldbentry uvldbEntry;
#endif
- int type = -1;
+ int method = -1;
int ROcount = 0;
long code;
+ enum volstatus rwNewstate = vl_online;
+ enum volstatus roNewstate = vl_online;
+ enum volstatus bkNewstate = vl_online;
/* clear out old bindings */
- if (volp->rwServersp)
- cm_FreeServerList(&volp->rwServersp);
- if (volp->roServersp)
- cm_FreeServerList(&volp->roServersp);
- if (volp->bkServersp)
- cm_FreeServerList(&volp->bkServersp);
+ if (volp->rw.serversp)
+ cm_FreeServerList(&volp->rw.serversp, CM_FREESERVERLIST_DELETE);
+ if (volp->ro.serversp)
+ cm_FreeServerList(&volp->ro.serversp, CM_FREESERVERLIST_DELETE);
+ if (volp->bk.serversp)
+ cm_FreeServerList(&volp->bk.serversp, CM_FREESERVERLIST_DELETE);
#ifdef AFS_FREELANCE_CLIENT
if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && atoi(volp->namep)==AFS_FAKE_ROOT_VOL_ID )
vldbEntry.flags |= VLF_RWEXISTS;
vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
code = 0;
- type = 0;
+ method = 0;
} else
#endif
{
continue;
#ifdef MULTIHOMED
code = VL_GetEntryByNameU(connp->callp, volp->namep, &uvldbEntry);
- type = 2;
+ method = 2;
if ( code == RXGEN_OPCODE )
#endif
{
code = VL_GetEntryByNameN(connp->callp, volp->namep, &nvldbEntry);
- type = 1;
+ method = 1;
}
if ( code == RXGEN_OPCODE ) {
code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
- type = 0;
+ method = 0;
}
} while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
code = cm_MapVLRPCError(code, reqp);
osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
volp->cellp->name, volp->namep);
}
+
+ /* We can end up here with code == CM_ERROR_NOSUCHVOLUME if the base volume name
+ * does not exist but there might exist a .readonly volume. If the base name
+ * doesn't exist we will not care about the .backup that might be left behind
+ * since there should be no method to access it.
+ */
+ if (code == CM_ERROR_NOSUCHVOLUME && volp->rw.ID == 0 && strlen(volp->namep) < (VL_MAXNAMELEN - 9)) {
+ char name[VL_MAXNAMELEN];
+
+ snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
+
+ /* now we have volume structure locked and held; make RPC to fill it */
+ osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, name);
+ do {
+ code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
+ if (code)
+ continue;
+#ifdef MULTIHOMED
+ code = VL_GetEntryByNameU(connp->callp, name, &uvldbEntry);
+ method = 2;
+ if ( code == RXGEN_OPCODE )
+#endif
+ {
+ code = VL_GetEntryByNameN(connp->callp, name, &nvldbEntry);
+ method = 1;
+ }
+ if ( code == RXGEN_OPCODE ) {
+ code = VL_GetEntryByNameO(connp->callp, name, &vldbEntry);
+ method = 0;
+ }
+ } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
+ code = cm_MapVLRPCError(code, reqp);
+ if ( code )
+ osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
+ volp->cellp->name, name, code);
+ else
+ osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
+ volp->cellp->name, name);
+ }
+
if (code == 0) {
afs_int32 flags;
afs_int32 nServers;
afs_int32 bkID;
afs_int32 serverNumber[NMAXNSERVERS];
afs_int32 serverFlags[NMAXNSERVERS];
+ afs_int32 rwServers_alldown = 1;
+ afs_int32 roServers_alldown = 1;
+ afs_int32 bkServers_alldown = 1;
+ char name[VL_MAXNAMELEN];
- switch ( type ) {
+ switch ( method ) {
case 0:
flags = vldbEntry.flags;
nServers = vldbEntry.nServers;
serverFlags[i] = vldbEntry.serverFlags[i];
serverNumber[i] = vldbEntry.serverNumber[i];
}
+ strncpy(name, vldbEntry.name, VL_MAXNAMELEN);
+ name[VL_MAXNAMELEN - 1] = '\0';
break;
case 1:
flags = nvldbEntry.flags;
serverFlags[i] = nvldbEntry.serverFlags[i];
serverNumber[i] = nvldbEntry.serverNumber[i];
}
+ strncpy(name, nvldbEntry.name, VL_MAXNAMELEN);
+ name[VL_MAXNAMELEN - 1] = '\0';
break;
#ifdef MULTIHOMED
case 2:
}
}
nServers = j; /* update the server count */
+ strncpy(name, uvldbEntry.name, VL_MAXNAMELEN);
+ name[VL_MAXNAMELEN - 1] = '\0';
break;
#endif
}
/* decode the response */
lock_ObtainWrite(&cm_volumeLock);
- if (flags & VLF_RWEXISTS)
- volp->rwID = rwID;
- else
- volp->rwID = 0;
- if (flags & VLF_ROEXISTS)
- volp->roID = roID;
- else
- volp->roID = 0;
- if (flags & VLF_BACKEXISTS)
- volp->bkID = bkID;
- else
- volp->bkID = 0;
+ if (cm_VolNameIsID(volp->namep)) {
+ size_t len;
+
+ len = strlen(name);
+
+ if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
+ name[len - 7] = '\0';
+ } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
+ name[len - 9] = '\0';
+ }
+
+ osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s", volp->namep, name);
+
+ if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromNameHashTable(volp);
+
+ strcpy(volp->namep, name);
+
+ cm_AddVolumeToNameHashTable(volp);
+ }
+
+ if (flags & VLF_RWEXISTS) {
+ if (volp->rw.ID != rwID) {
+ if (volp->rw.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
+ volp->rw.ID = rwID;
+ cm_AddVolumeToIDHashTable(volp, RWVOL);
+ }
+ } else {
+ if (volp->rw.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
+ volp->rw.ID = 0;
+ }
+ if (flags & VLF_ROEXISTS) {
+ if (volp->ro.ID != roID) {
+ if (volp->ro.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
+ volp->ro.ID = roID;
+ cm_AddVolumeToIDHashTable(volp, ROVOL);
+ }
+ } else {
+ if (volp->ro.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
+ volp->ro.ID = 0;
+ }
+ if (flags & VLF_BACKEXISTS) {
+ if (volp->bk.ID != bkID) {
+ if (volp->bk.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
+ volp->bk.ID = bkID;
+ cm_AddVolumeToIDHashTable(volp, BACKVOL);
+ }
+ } else {
+ if (volp->bk.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
+ volp->bk.ID = 0;
+ }
lock_ReleaseWrite(&cm_volumeLock);
for (i=0; i<nServers; i++) {
/* create a server entry */
* earlier in this function.
*/
if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
- tsrp = cm_NewServerRef(tsp);
- cm_InsertServerList(&volp->rwServersp, tsrp);
+ tsrp = cm_NewServerRef(tsp, rwID);
+ cm_InsertServerList(&volp->rw.serversp, tsrp);
+
lock_ObtainWrite(&cm_serverLock);
tsrp->refCount--; /* drop allocation reference */
lock_ReleaseWrite(&cm_serverLock);
+
+ if (!(tsp->flags & CM_SERVERFLAG_DOWN))
+ rwServers_alldown = 0;
}
if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS)) {
- tsrp = cm_NewServerRef(tsp);
- cm_InsertServerList(&volp->roServersp, tsrp);
+ tsrp = cm_NewServerRef(tsp, roID);
+ cm_InsertServerList(&volp->ro.serversp, tsrp);
lock_ObtainWrite(&cm_serverLock);
tsrp->refCount--; /* drop allocation reference */
lock_ReleaseWrite(&cm_serverLock);
ROcount++;
+
+ if (!(tsp->flags & CM_SERVERFLAG_DOWN))
+ roServers_alldown = 0;
}
/* We don't use VLSF_BACKVOL !?! */
+ /* Because only the backup on the server holding the RW
+ * volume can be valid. This check prevents errors if a
+ * RW is moved but the old backup is not removed.
+ */
if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
- tsrp = cm_NewServerRef(tsp);
- cm_InsertServerList(&volp->bkServersp, tsrp);
+ tsrp = cm_NewServerRef(tsp, bkID);
+ cm_InsertServerList(&volp->bk.serversp, tsrp);
lock_ObtainWrite(&cm_serverLock);
tsrp->refCount--; /* drop allocation reference */
lock_ReleaseWrite(&cm_serverLock);
+
+ if (!(tsp->flags & CM_SERVERFLAG_DOWN))
+ bkServers_alldown = 0;
}
/* Drop the reference obtained by cm_FindServer() */
cm_PutServer(tsp);
* lists are length 1.
*/
if (ROcount > 1) {
- cm_RandomizeServer(&volp->roServersp);
+ cm_RandomizeServer(&volp->ro.serversp);
}
+
+ rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
+ roNewstate = roServers_alldown ? vl_alldown : vl_online;
+ bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
+ } else {
+ rwNewstate = roNewstate = bkNewstate = vl_alldown;
+ }
+
+ if (volp->rw.state != rwNewstate) {
+ if (volp->rw.ID)
+ cm_VolumeStatusNotification(volp, volp->rw.ID, volp->rw.state, rwNewstate);
+ volp->rw.state = rwNewstate;
+ }
+ if (volp->ro.state != roNewstate) {
+ if (volp->ro.ID)
+ cm_VolumeStatusNotification(volp, volp->ro.ID, volp->ro.state, roNewstate);
+ volp->ro.state = roNewstate;
}
+ if (volp->bk.state != bkNewstate) {
+ if (volp->bk.ID)
+ cm_VolumeStatusNotification(volp, volp->bk.ID, volp->bk.state, bkNewstate);
+ volp->bk.state = bkNewstate;
+ }
+
return code;
}
}
}
-long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
- cm_req_t *reqp, cm_volume_t **outVolpp)
+
+long cm_GetVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
+ cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
{
cm_volume_t *volp;
- char volNameString[100];
+#ifdef SEARCH_ALL_VOLUMES
+ cm_volume_t *volp2;
+#endif
+ char volNameString[VL_MAXNAMELEN];
+ afs_uint32 hash;
long code = 0;
- lock_ObtainWrite(&cm_volumeLock);
- for(volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
+ lock_ObtainRead(&cm_volumeLock);
+#ifdef SEARCH_ALL_VOLUMES
+ for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
if (cellp == volp->cellp &&
- ((unsigned) volumeID == volp->rwID ||
- (unsigned) volumeID == volp->roID ||
- (unsigned) volumeID == volp->bkID))
+ ((unsigned) volumeID == volp->rw.ID ||
+ (unsigned) volumeID == volp->ro.ID ||
+ (unsigned) volumeID == volp->bk.ID))
break;
}
+ volp2 = volp;
+#endif /* SEARCH_ALL_VOLUMES */
+
+ hash = CM_VOLUME_ID_HASH(volumeID);
+ /* The volumeID can be any one of the three types. So we must
+ * search the hash table for all three types until we find it.
+ * We will search in the order of RO, RW, BK.
+ */
+ for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->ro.nextp) {
+ if ( cellp == volp->cellp && volumeID == volp->ro.ID )
+ break;
+ }
+ if (!volp) {
+ /* try RW volumes */
+ for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->rw.nextp) {
+ if ( cellp == volp->cellp && volumeID == volp->rw.ID )
+ break;
+ }
+ }
+ if (!volp) {
+ /* try BK volumes */
+ for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->bk.nextp) {
+ if ( cellp == volp->cellp && volumeID == volp->bk.ID )
+ break;
+ }
+ }
+
+#ifdef SEARCH_ALL_VOLUMES
+ assert(volp == volp2);
+#endif
+
+ lock_ReleaseRead(&cm_volumeLock);
+
/* hold the volume if we found it */
if (volp)
- volp->refCount++;
- lock_ReleaseWrite(&cm_volumeLock);
+ cm_GetVolume(volp);
/* return it held */
if (volp) {
volp->flags &= ~CM_VOLUMEFLAG_RESET;
}
lock_ReleaseMutex(&volp->mx);
- if (code == 0)
+ if (code == 0) {
*outVolpp = volp;
- else
+
+ lock_ObtainWrite(&cm_volumeLock);
+ cm_AdjustVolumeLRU(volp);
+ lock_ReleaseWrite(&cm_volumeLock);
+ } else
cm_PutVolume(volp);
return code;
/* otherwise, we didn't find it so consult the VLDB */
sprintf(volNameString, "%u", volumeID);
code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
- 0, outVolpp);
+ flags, outVolpp);
return code;
}
+
long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
- struct cm_user *userp, struct cm_req *reqp,
- long flags, cm_volume_t **outVolpp)
+ struct cm_user *userp, struct cm_req *reqp,
+ afs_uint32 flags, cm_volume_t **outVolpp)
{
cm_volume_t *volp;
- long code = 0;
-
- lock_ObtainWrite(&cm_volumeLock);
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
- if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
+#ifdef SEARCH_ALL_VOLUMES
+ cm_volume_t *volp2;
+#endif
+ long code = 0;
+ char name[VL_MAXNAMELEN];
+ size_t len;
+ int type;
+ afs_uint32 hash;
+
+ strncpy(name, volumeNamep, VL_MAXNAMELEN);
+ name[VL_MAXNAMELEN-1] = '\0';
+ len = strlen(name);
+
+ if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
+ type = BACKVOL;
+ name[len - 7] = '\0';
+ } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
+ type = ROVOL;
+ name[len - 9] = '\0';
+ } else {
+ type = RWVOL;
+ }
+
+ lock_ObtainRead(&cm_volumeLock);
+#ifdef SEARCH_ALL_VOLUMES
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
+ if (cellp == volp->cellp && strcmp(name, volp->namep) == 0) {
break;
}
}
-
- /* otherwise, get from VLDB */
- if (!volp) {
+ volp2 = volp;
+#endif /* SEARCH_ALL_VOLUMES */
+
+ hash = CM_VOLUME_NAME_HASH(name);
+ for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
+ if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
+ break;
+ }
+
+#ifdef SEARCH_ALL_VOLUMES
+ assert(volp2 == volp);
+#endif
+
+ if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
+ /* otherwise, get from VLDB */
+
if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
+
+#ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
if ( volp->refCount == 0 ) {
/* There is one we can re-use */
break;
}
}
+#else
+ for ( volp = cm_data.volumeLRULastp;
+ volp;
+ volp = (cm_volume_t *) osi_QPrev(&volp->q))
+ {
+ if ( volp->refCount == 0 ) {
+ /* There is one we can re-use */
+ break;
+ }
+ }
+#endif
if (!volp)
osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
- }
- if (volp) {
- volp->rwID = volp->roID = volp->bkID = 0;
+ lock_ReleaseRead(&cm_volumeLock);
+ lock_ObtainMutex(&volp->mx);
+ lock_ObtainWrite(&cm_volumeLock);
+
+ osi_Log2(afsd_logp, "Recycling Volume %s:%s",
+ volp->cellp->name, volp->namep);
+
+ if (volp->flags & CM_VOLUMEFLAG_IN_LRU_QUEUE)
+ cm_RemoveVolumeFromLRU(volp);
+ if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromNameHashTable(volp);
+ if (volp->rw.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
+ if (volp->ro.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
+ if (volp->bk.flags & CM_VOLUMEFLAG_IN_HASH)
+ cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
+
+ if (volp->rw.ID)
+ cm_VolumeStatusNotification(volp, volp->rw.ID, volp->rw.state, vl_unknown);
+ if (volp->ro.ID)
+ cm_VolumeStatusNotification(volp, volp->ro.ID, volp->ro.state, vl_unknown);
+ if (volp->bk.ID)
+ cm_VolumeStatusNotification(volp, volp->bk.ID, volp->bk.state, vl_unknown);
+
+ volp->rw.ID = volp->ro.ID = volp->bk.ID = 0;
volp->dotdotFid.cell = 0;
volp->dotdotFid.volume = 0;
volp->dotdotFid.unique = 0;
volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
memset(volp, 0, sizeof(cm_volume_t));
volp->magic = CM_VOLUME_MAGIC;
- volp->nextp = cm_data.allVolumesp;
+ volp->allNextp = cm_data.allVolumesp;
cm_data.allVolumesp = volp;
lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
- }
+ lock_ReleaseRead(&cm_volumeLock);
+ lock_ObtainMutex(&volp->mx);
+ lock_ObtainWrite(&cm_volumeLock);
+ }
volp->cellp = cellp;
- strncpy(volp->namep, volumeNamep, VL_MAXNAMELEN);
+ strncpy(volp->namep, name, VL_MAXNAMELEN);
volp->namep[VL_MAXNAMELEN-1] = '\0';
- volp->refCount = 1; /* starts off held */
+ volp->refCount = 1; /* starts off held */
volp->flags = CM_VOLUMEFLAG_RESET;
+ volp->rw.state = volp->ro.state = volp->bk.state = vl_unknown;
+ volp->rw.nextp = volp->ro.nextp = volp->bk.nextp = NULL;
+ volp->rw.flags = volp->ro.flags = volp->bk.flags = 0;
+ cm_AddVolumeToNameHashTable(volp);
+ lock_ReleaseWrite(&cm_volumeLock);
}
- else {
- volp->refCount++;
+ else if (volp) {
+ lock_ReleaseRead(&cm_volumeLock);
+ cm_GetVolume(volp);
+ lock_ObtainMutex(&volp->mx);
}
- /* next should work since no one could have gotten ptr to this structure yet */
- lock_ReleaseWrite(&cm_volumeLock);
- lock_ObtainMutex(&volp->mx);
+ /* if we don't have a volp structure return no such volume */
+ if (!volp)
+ return CM_ERROR_NOSUCHVOLUME;
+ /* if we get here we are holding the mutex */
if (volp->flags & CM_VOLUMEFLAG_RESET) {
code = cm_UpdateVolume(cellp, userp, reqp, volp);
if (code == 0)
volp->flags &= ~CM_VOLUMEFLAG_RESET;
}
+ lock_ReleaseMutex(&volp->mx);
- if (code == 0)
+ if (code == 0 && (type == BACKVOL && volp->bk.ID == 0 ||
+ type == ROVOL && volp->ro.ID == 0))
+ code = CM_ERROR_NOSUCHVOLUME;
+
+ if (code == 0) {
*outVolpp = volp;
- else
+
+ lock_ObtainWrite(&cm_volumeLock);
+ cm_AdjustVolumeLRU(volp);
+ lock_ReleaseWrite(&cm_volumeLock);
+ } else
cm_PutVolume(volp);
- lock_ReleaseMutex(&volp->mx);
return code;
}
{
cm_cell_t *cellp;
cm_volume_t *volp;
+#ifdef SEARCH_ALL_VOLUMES
+ cm_volume_t *volp2;
+#endif
+ afs_uint32 hash;
if (!fidp) return;
if (!cellp) return;
/* search for the volume */
- lock_ObtainWrite(&cm_volumeLock);
- for(volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
+ lock_ObtainRead(&cm_volumeLock);
+#ifdef SEARCH_ALL_VOLUMES
+ for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
if (cellp == volp->cellp &&
- (fidp->volume == volp->rwID ||
- fidp->volume == volp->roID ||
- fidp->volume == volp->bkID))
+ (fidp->volume == volp->rw.ID ||
+ fidp->volume == volp->ro.ID ||
+ fidp->volume == volp->bk.ID))
break;
}
+#endif /* SEARCH_ALL_VOLUMES */
+
+ hash = CM_VOLUME_ID_HASH(fidp->volume);
+ /* The volumeID can be any one of the three types. So we must
+ * search the hash table for all three types until we find it.
+ * We will search in the order of RO, RW, BK.
+ */
+ for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->ro.nextp) {
+ if ( cellp == volp->cellp && fidp->volume == volp->ro.ID )
+ break;
+ }
+ if (!volp) {
+ /* try RW volumes */
+ for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->rw.nextp) {
+ if ( cellp == volp->cellp && fidp->volume == volp->rw.ID )
+ break;
+ }
+ }
+ if (!volp) {
+ /* try BK volumes */
+ for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->bk.nextp) {
+ if ( cellp == volp->cellp && fidp->volume == volp->bk.ID )
+ break;
+ }
+ }
+
+#ifdef SEARCH_ALL_VOLUMES
+ assert(volp == volp2);
+#endif
+
+ lock_ReleaseRead(&cm_volumeLock);
/* hold the volume if we found it */
if (volp)
- volp->refCount++;
- lock_ReleaseWrite(&cm_volumeLock);
+ cm_GetVolume(volp);
/* update it */
cm_data.mountRootGen = time(NULL);
}
/* find the appropriate servers from a volume */
-cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
+cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume)
{
cm_serverRef_t **serverspp;
cm_serverRef_t *current;;
lock_ObtainWrite(&cm_serverLock);
- if (volume == volp->rwID)
- serverspp = &volp->rwServersp;
- else if (volume == volp->roID)
- serverspp = &volp->roServersp;
- else if (volume == volp->bkID)
- serverspp = &volp->bkServersp;
+ if (volume == volp->rw.ID)
+ serverspp = &volp->rw.serversp;
+ else if (volume == volp->ro.ID)
+ serverspp = &volp->ro.serversp;
+ else if (volume == volp->bk.ID)
+ serverspp = &volp->bk.serversp;
else
osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
long id;
lock_ObtainMutex(&volp->mx);
- if (volp->roID && volp->roServersp)
- id = volp->roID;
+ if (volp->ro.ID && volp->ro.serversp)
+ id = volp->ro.ID;
else
- id = volp->rwID;
+ id = volp->rw.ID;
lock_ReleaseMutex(&volp->mx);
return id;
/* force a re-loading of volume data from the vldb */
lock_ObtainWrite(&cm_volumeLock);
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
volp->refCount++;
lock_ReleaseWrite(&cm_volumeLock);
- lock_ObtainMutex(&volp->mx);
+ lock_ObtainMutex(&volp->mx);
volp->flags |= CM_VOLUMEFLAG_RESET;
-
lock_ReleaseMutex(&volp->mx);
- lock_ObtainWrite(&cm_volumeLock);
+
+ lock_ObtainWrite(&cm_volumeLock);
osi_assert(volp->refCount-- > 0);
}
lock_ReleaseWrite(&cm_volumeLock);
}
+/* called from the Daemon thread */
+void cm_CheckBusyVolumes(void)
+{
+ cm_volume_t *volp;
+ cm_conn_t *connp;
+ register long code;
+ AFSFetchVolumeStatus volStat;
+ char *Name;
+ char *OfflineMsg;
+ char *MOTD;
+ cm_req_t req;
+ struct rx_connection * callp;
+ char volName[32];
+ char offLineMsg[256];
+ char motd[256];
+
+ Name = volName;
+ OfflineMsg = offLineMsg;
+ MOTD = motd;
+
+ lock_ObtainWrite(&cm_volumeLock);
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
+ volp->refCount++;
+ lock_ReleaseWrite(&cm_volumeLock);
+ lock_ObtainMutex(&volp->mx);
+
+ if (volp->rw.ID != 0 && (volp->rw.state == vl_busy || volp->rw.state == vl_offline)) {
+ cm_InitReq(&req);
+
+ do {
+ code = cm_ConnFromVolume(volp, volp->rw.ID, cm_rootUserp, &req, &connp);
+ if (code)
+ continue;
+
+ callp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(callp, volp->rw.ID,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(callp);
+
+ } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, &req);
+
+ if (code == 0 && volStat.Online) {
+ cm_VolumeStatusNotification(volp, volp->rw.ID, volp->rw.state, vl_online);
+ volp->rw.state = vl_online;
+ }
+ }
+
+ if (volp->ro.ID != 0 && (volp->ro.state == vl_busy || volp->ro.state == vl_offline)) {
+ cm_InitReq(&req);
+
+ do {
+ code = cm_ConnFromVolume(volp, volp->ro.ID, cm_rootUserp, &req, &connp);
+ if (code)
+ continue;
+
+ callp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(callp, volp->ro.ID,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(callp);
+
+ } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, &req);
+
+ if (code == 0 && volStat.Online) {
+ cm_VolumeStatusNotification(volp, volp->ro.ID, volp->ro.state, vl_online);
+ volp->ro.state = vl_online;
+ }
+ }
+
+ if (volp->bk.ID != 0 && (volp->bk.state == vl_busy || volp->bk.state == vl_offline)) {
+ cm_InitReq(&req);
+
+ do {
+ code = cm_ConnFromVolume(volp, volp->bk.ID, cm_rootUserp, &req, &connp);
+ if (code)
+ continue;
+
+ callp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(callp, volp->bk.ID,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(callp);
+
+ } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, &req);
+
+ if (code == 0 && volStat.Online) {
+ cm_VolumeStatusNotification(volp, volp->bk.ID, volp->bk.state, vl_online);
+ volp->bk.state = vl_online;
+ }
+ }
+
+ lock_ReleaseMutex(&volp->mx);
+ lock_ObtainWrite(&cm_volumeLock);
+ osi_assert(volp->refCount-- > 0);
+ }
+ lock_ReleaseWrite(&cm_volumeLock);
+}
+
+void
+cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
+{
+ struct cm_vol_state * statep = NULL;
+ enum volstatus newStatus;
+ cm_serverRef_t *tsrp;
+ cm_server_t *tsp;
+ int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
+
+ if (volp->rw.ID == volID) {
+ statep = &volp->rw;
+ } else if (volp->ro.ID == volID) {
+ statep = &volp->ro;
+ } else if (volp->bk.ID == volID) {
+ statep = &volp->bk;
+ }
+
+ if (!statep) {
+#ifdef DEBUG
+ DebugBreak();
+#endif
+ return;
+ }
+
+ lock_ObtainWrite(&cm_serverLock);
+ for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
+ tsp = tsrp->server;
+ cm_GetServerNoLock(tsp);
+ if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
+ allDown = 0;
+ if (tsrp->status == srv_busy) {
+ allOffline = 0;
+ someBusy = 1;
+ } else if (tsrp->status == srv_offline) {
+ allBusy = 0;
+ someOffline = 1;
+ } else {
+ allOffline = 0;
+ allBusy = 0;
+ }
+ }
+ cm_PutServerNoLock(tsp);
+ }
+ lock_ReleaseWrite(&cm_serverLock);
+
+ if (allDown)
+ newStatus = vl_alldown;
+ else if (allBusy || (someBusy && someOffline))
+ newStatus = vl_busy;
+ else if (allOffline)
+ newStatus = vl_offline;
+ else
+ newStatus = vl_online;
+
+
+ if (statep->ID && statep->state != newStatus)
+ cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
+
+ statep->state = newStatus;
+}
+
/*
** Finds all volumes that reside on this server and reorders their
** RO list according to the changed rank of server.
/* find volumes which might have RO copy on server*/
lock_ObtainWrite(&cm_volumeLock);
- for(volp = cm_data.allVolumesp; volp; volp=volp->nextp)
+ for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
{
code = 1 ; /* assume that list is unchanged */
volp->refCount++;
lock_ReleaseWrite(&cm_volumeLock);
lock_ObtainMutex(&volp->mx);
- if ((tsp->cellp==volp->cellp) && (volp->roServersp))
- code =cm_ChangeRankServer(&volp->roServersp, tsp);
+ if ((tsp->cellp==volp->cellp) && (volp->ro.serversp))
+ code =cm_ChangeRankServer(&volp->ro.serversp, tsp);
/* this volume list was changed */
if ( !code )
- cm_RandomizeServer(&volp->roServersp);
+ cm_RandomizeServer(&volp->ro.serversp);
lock_ReleaseMutex(&volp->mx);
lock_ObtainWrite(&cm_volumeLock);
lock_ReleaseWrite(&cm_volumeLock);
}
-/* dump all scp's that have reference count > 0 to a file.
+/* dump all volumes that have reference count > 0 to a file.
* cookie is used to identify this batch for easy parsing,
* and it a string provided by a caller
*/
sprintf(output, "%s - dumping volumes - cm_data.currentVolumes=%d, cm_data.maxVolumes=%d\r\n", cookie, cm_data.currentVolumes, cm_data.maxVolumes);
WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
- for (volp = cm_data.allVolumesp; volp; volp=volp->nextp)
+ for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
{
if (volp->refCount != 0)
{
cm_scache_t *scp;
int scprefs = 0;
- for (scp = cm_data.scacheLRULastp; scp; scp = (cm_scache_t *) osi_QPrev(&scp->q))
+ for (scp = cm_data.allSCachesp; scp; scp = scp->allNextp)
{
if (scp->volp == volp)
scprefs++;
}
sprintf(output, "%s cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x fid (cell=%d, volume=%d, vnode=%d, unique=%d) refCount=%u scpRefs=%u\r\n",
- cookie, volp->cellp->name, volp->namep, volp->rwID, volp->roID, volp->bkID, volp->flags,
+ cookie, volp->cellp->name, volp->namep, volp->rw.ID, volp->ro.ID, volp->bk.ID, volp->flags,
volp->dotdotFid.cell, volp->dotdotFid.volume, volp->dotdotFid.vnode, volp->dotdotFid.unique,
volp->refCount, scprefs);
WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
}
+/*
+ * String hash function used by SDBM project.
+ * It was chosen because it is fast and provides
+ * decent coverage.
+ */
+afs_uint32 SDBMHash(const char * str)
+{
+ afs_uint32 hash = 0;
+ size_t i, len;
+
+ if (str == NULL)
+ return 0;
+
+ for(i = 0, len = strlen(str); i < len; i++)
+ {
+ hash = str[i] + (hash << 6) + (hash << 16) - hash;
+ }
+
+ return (hash & 0x7FFFFFFF);
+}
+
+/* call with volume write-locked and mutex held */
+void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
+{
+ int i;
+
+ if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
+ return;
+
+ i = CM_VOLUME_NAME_HASH(volp->namep);
+
+ volp->nameNextp = cm_data.volumeNameHashTablep[i];
+ cm_data.volumeNameHashTablep[i] = volp;
+ volp->flags |= CM_VOLUMEFLAG_IN_HASH;
+}
+
+/* call with volume write-locked and mutex held */
+void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
+{
+ cm_volume_t **lvolpp;
+ cm_volume_t *tvolp;
+ int i;
+
+ if (volp->flags & CM_VOLUMEFLAG_IN_HASH) {
+ /* hash it out first */
+ i = CM_VOLUME_NAME_HASH(volp->namep);
+ for (lvolpp = &cm_data.volumeNameHashTablep[i], tvolp = cm_data.volumeNameHashTablep[i];
+ tvolp;
+ lvolpp = &tvolp->nameNextp, tvolp = tvolp->nameNextp) {
+ if (tvolp == volp) {
+ *lvolpp = volp->nameNextp;
+ volp->flags &= ~CM_VOLUMEFLAG_IN_HASH;
+ volp->nameNextp = NULL;
+ break;
+ }
+ }
+ }
+}
+
+/* call with volume write-locked and mutex held */
+void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
+{
+ int i;
+ struct cm_vol_state * statep;
+
+ switch (volType) {
+ case RWVOL:
+ statep = &volp->rw;
+ break;
+ case ROVOL:
+ statep = &volp->ro;
+ break;
+ case BACKVOL:
+ statep = &volp->bk;
+ break;
+ default:
+ return;
+ }
+
+ if (statep->flags & CM_VOLUMEFLAG_IN_HASH)
+ return;
+
+ i = CM_VOLUME_ID_HASH(statep->ID);
+
+ switch (volType) {
+ case RWVOL:
+ statep->nextp = cm_data.volumeRWIDHashTablep[i];
+ cm_data.volumeRWIDHashTablep[i] = volp;
+ break;
+ case ROVOL:
+ statep->nextp = cm_data.volumeROIDHashTablep[i];
+ cm_data.volumeROIDHashTablep[i] = volp;
+ break;
+ case BACKVOL:
+ statep->nextp = cm_data.volumeBKIDHashTablep[i];
+ cm_data.volumeBKIDHashTablep[i] = volp;
+ break;
+ }
+ statep->flags |= CM_VOLUMEFLAG_IN_HASH;
+}
+
+
+/* call with volume write-locked and mutex held */
+void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
+{
+ cm_volume_t **lvolpp;
+ cm_volume_t *tvolp;
+ struct cm_vol_state * statep;
+ int i;
+
+ switch (volType) {
+ case RWVOL:
+ statep = &volp->rw;
+ break;
+ case ROVOL:
+ statep = &volp->ro;
+ break;
+ case BACKVOL:
+ statep = &volp->bk;
+ break;
+ default:
+ return;
+ }
+
+ if (statep->flags & CM_VOLUMEFLAG_IN_HASH) {
+ /* hash it out first */
+ i = CM_VOLUME_ID_HASH(statep->ID);
+
+ switch (volType) {
+ case RWVOL:
+ lvolpp = &cm_data.volumeRWIDHashTablep[i];
+ tvolp = cm_data.volumeRWIDHashTablep[i];
+ break;
+ case ROVOL:
+ lvolpp = &cm_data.volumeROIDHashTablep[i];
+ tvolp = cm_data.volumeROIDHashTablep[i];
+ break;
+ case BACKVOL:
+ lvolpp = &cm_data.volumeBKIDHashTablep[i];
+ tvolp = cm_data.volumeBKIDHashTablep[i];
+ break;
+ }
+ do {
+ if (tvolp == volp) {
+ *lvolpp = statep->nextp;
+ statep->flags &= ~CM_VOLUMEFLAG_IN_HASH;
+ statep->nextp = NULL;
+ break;
+ }
+
+ switch (volType) {
+ case RWVOL:
+ lvolpp = &tvolp->rw.nextp;
+ tvolp = tvolp->rw.nextp;
+ break;
+ case ROVOL:
+ lvolpp = &tvolp->ro.nextp;
+ tvolp = tvolp->ro.nextp;
+ break;
+ case BACKVOL:
+ lvolpp = &tvolp->bk.nextp;
+ tvolp = tvolp->bk.nextp;
+ break;
+ }
+ } while(tvolp);
+ }
+}
+
+/* must be called with cm_volumeLock write-locked! */
+void cm_AdjustVolumeLRU(cm_volume_t *volp)
+{
+ if (volp == cm_data.volumeLRULastp)
+ cm_data.volumeLRULastp = (cm_volume_t *) osi_QPrev(&volp->q);
+ if (volp->flags & CM_VOLUMEFLAG_IN_LRU_QUEUE)
+ osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
+ osi_QAdd((osi_queue_t **) &cm_data.volumeLRUFirstp, &volp->q);
+ volp->flags |= CM_VOLUMEFLAG_IN_LRU_QUEUE;
+ if (!cm_data.volumeLRULastp)
+ cm_data.volumeLRULastp = volp;
+}
+
+/* must be called with cm_volumeLock write-locked! */
+void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
+{
+ if (volp->flags & CM_VOLUMEFLAG_IN_LRU_QUEUE) {
+ if (volp == cm_data.volumeLRULastp)
+ cm_data.volumeLRULastp = (cm_volume_t *) osi_QPrev(&volp->q);
+ osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
+ volp->flags &= ~CM_VOLUMEFLAG_IN_LRU_QUEUE;
+ }
+}
+
+static char * volstatus_str(enum volstatus vs)
+{
+ switch (vs) {
+ case vl_online:
+ return "online";
+ case vl_busy:
+ return "busy";
+ case vl_offline:
+ return "offline";
+ case vl_alldown:
+ return "alldown";
+ default:
+ return "unknown";
+ }
+}
+
+void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
+{
+ char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN];
+ char *ext = "";
+
+ if (volID == volp->rw.ID)
+ ext = "";
+ else if (volID == volp->ro.ID)
+ ext = ".readonly";
+ else if (volID == volp->bk.ID)
+ ext = ".backup";
+ else
+ ext = ".nomatch";
+ snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
+
+ osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
+ volstr, volID, volstatus_str(old), volstatus_str(new));
+}
#define CM_VOLUME_MAGIC ('V' | 'O' <<8 | 'L'<<16 | 'M'<<24)
+enum volstatus {vl_online, vl_busy, vl_offline, vl_alldown, vl_unknown};
+
+struct cm_vol_state {
+ afs_uint32 ID; /* by mx */
+ struct cm_volume *nextp; /* volumeIDHashTable; by cm_volumeLock */
+ cm_serverRef_t *serversp; /* by mx */
+ enum volstatus state; /* by mx */
+ afs_uint32 flags; /* by mx */
+};
+
typedef struct cm_volume {
+ osi_queue_t q; /* LRU queue; cm_volumeLock */
afs_uint32 magic;
+ struct cm_volume *allNextp; /* allVolumes; by cm_volumeLock */
+ struct cm_volume *nameNextp; /* volumeNameHashTable; by cm_volumeLock */
cm_cell_t *cellp; /* never changes */
- char namep[VL_MAXNAMELEN]; /* by cm_volumeLock */
- unsigned long rwID; /* by cm_volumeLock */
- unsigned long roID; /* by cm_volumeLock */
- unsigned long bkID; /* by cm_volumeLock */
- struct cm_volume *nextp; /* by cm_volumeLock */
+ char namep[VL_MAXNAMELEN]; /* name of the normal volume - assigned during allocation; */
+ /* by cm_volumeLock */
+ struct cm_vol_state rw; /* by cm_volumeLock */
+ struct cm_vol_state ro; /* by cm_volumeLock */
+ struct cm_vol_state bk; /* by cm_volumeLock */
struct cm_fid dotdotFid; /* parent of volume root */
osi_mutex_t mx;
- long flags; /* by mx */
- unsigned long refCount; /* by cm_volumeLock */
- cm_serverRef_t *rwServersp; /* by mx */
- cm_serverRef_t *roServersp; /* by mx */
- cm_serverRef_t *bkServersp; /* by mx */
+ afs_uint32 flags; /* by mx */
+ afs_uint32 refCount; /* by cm_volumeLock */
} cm_volume_t;
-#define CM_VOLUMEFLAG_RESET 1 /* reload this info on next use */
+#define CM_VOLUMEFLAG_RESET 1 /* reload this info on next use */
+#define CM_VOLUMEFLAG_IN_HASH 2
+#define CM_VOLUMEFLAG_IN_LRU_QUEUE 4
+
+
+typedef struct cm_volumeRef {
+ struct cm_volumeRef * next;
+ afs_uint32 volID;
+} cm_volumeRef_t;
extern void cm_InitVolume(int newFile, long maxVols);
-extern long cm_GetVolumeByName(struct cm_cell *, char *, struct cm_user *,
- struct cm_req *, long, cm_volume_t **);
+extern long cm_GetVolumeByName(struct cm_cell *cellp, char *volNamep,
+ struct cm_user *userp, struct cm_req *reqp,
+ afs_uint32 flags, cm_volume_t **outVolpp);
+
+extern long cm_GetVolumeByID(struct cm_cell *cellp, afs_uint32 volumeID,
+ cm_user_t *userp, cm_req_t *reqp,
+ afs_uint32 flags, cm_volume_t **outVolpp);
-extern long cm_GetVolumeByID(struct cm_cell *cellp, long volumeID,
- cm_user_t *userp, cm_req_t *reqp, cm_volume_t **outVolpp);
+#define CM_GETVOL_FLAG_CREATE 1
+#define CM_GETVOL_FLAG_NO_LRU_UPDATE 2
+
+/* hash define. Must not include the cell, since the callback revocation code
+ * doesn't necessarily know the cell in the case of a multihomed server
+ * contacting us from a mystery address.
+ */
+#define CM_VOLUME_ID_HASH(volid) ((unsigned long) volid \
+ % cm_data.volumeHashTableSize)
+
+#define CM_VOLUME_NAME_HASH(name) (SDBMHash(name) % cm_data.volumeHashTableSize)
+
+extern afs_uint32 SDBMHash(const char *);
extern void cm_GetVolume(cm_volume_t *volp);
extern void cm_ForceUpdateVolume(struct cm_fid *fidp, cm_user_t *userp,
cm_req_t *reqp);
-extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, unsigned long volume);
+extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume);
extern void cm_ChangeRankVolume(cm_server_t *tsp);
extern long cm_ShutdownVolume(void);
extern int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock);
+
+extern int cm_VolNameIsID(char *aname);
+
+extern void cm_RemoveVolumeFromNameHashTable(cm_volume_t * volp);
+
+extern void cm_RemoveVolumeFromIDHashTable(cm_volume_t * volp, afs_uint32 volType);
+
+extern void cm_AddVolumeToNameHashTable(cm_volume_t * volp);
+
+extern void cm_AddVolumeToIDHashTable(cm_volume_t * volp, afs_uint32 volType);
+
+extern void cm_AdjustVolumeLRU(cm_volume_t *volp);
+
+extern void cm_RemoveVolumeFromLRU(cm_volume_t *volp);
+
+extern void cm_CheckBusyVolumes(void);
+
+extern void cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
+
+extern void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new);
+
#endif /* __CM_VOLUME_H_ENV__ */
* this is the first read call. This is the function that actually makes the
* call to the ioctl code.
*/
-smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
+long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
{
long opcode;
smb_ioctlProc_t *procp = NULL;
extern long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
smb_packet_t *outp);
+extern long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp);
+
#endif /* __SMB_IOCTL_H_ENV__ */