2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
26 osi_rwlock_t cm_volumeLock;
29 cm_ValidateVolume(void)
34 for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->allNextp, count++) {
35 if ( volp->magic != CM_VOLUME_MAGIC ) {
36 afsi_log("cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC");
37 fprintf(stderr, "cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC\n");
40 if ( volp->cellp && volp->cellp->magic != CM_CELL_MAGIC ) {
41 afsi_log("cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC");
42 fprintf(stderr, "cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC\n");
45 if ( volp->allNextp && volp->allNextp->magic != CM_VOLUME_MAGIC ) {
46 afsi_log("cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC");
47 fprintf(stderr, "cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC\n");
50 if ( count != 0 && volp == cm_data.allVolumesp ||
51 count > cm_data.maxVolumes ) {
52 afsi_log("cm_ValidateVolume failure: cm_data.allVolumep loop detected");
53 fprintf(stderr, "cm_ValidateVolume failure: cm_data.allVolumep loop detected\n");
58 if ( count != cm_data.currentVolumes ) {
59 afsi_log("cm_ValidateVolume failure: count != cm_data.currentVolumes");
60 fprintf(stderr, "cm_ValidateVolume failure: count != cm_data.currentVolumes\n");
68 cm_ShutdownVolume(void)
72 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
74 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
75 if (volp->vol[volType].ID)
76 cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_alldown);
78 volp->cbExpiresRO = 0;
80 volp->cbServerpRO = NULL;
81 lock_FinalizeRWLock(&volp->rw);
87 void cm_InitVolume(int newFile, long maxVols)
89 static osi_once_t once;
91 if (osi_Once(&once)) {
92 lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock", LOCK_HIERARCHY_VOLUME_GLOBAL);
95 cm_data.allVolumesp = NULL;
96 cm_data.currentVolumes = 0;
97 cm_data.maxVolumes = maxVols;
98 memset(cm_data.volumeNameHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
99 memset(cm_data.volumeRWIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
100 memset(cm_data.volumeROIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
101 memset(cm_data.volumeBKIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
102 cm_data.volumeLRUFirstp = cm_data.volumeLRULastp = NULL;
106 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
109 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
110 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
111 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_UPDATING_VL);
112 volp->lastUpdateTime = 0;
113 for (volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
114 volp->vol[volType].state = vl_unknown;
115 volp->vol[volType].serversp = NULL;
116 if (volp->vol[volType].ID)
117 cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_unknown, volp->vol[volType].state);
119 volp->cbExpiresRO = 0;
120 volp->cbIssuedRO = 0;
121 volp->cbServerpRO = NULL;
129 /* returns true if the id is a decimal integer, in which case we interpret it
130 * as an id. make the cache manager much simpler.
131 * Stolen from src/volser/vlprocs.c */
133 cm_VolNameIsID(char *aname)
136 while (tc = *aname++) {
137 if (tc > '9' || tc < '0')
145 * Update a volume. Caller holds a write lock on the volume (volp->rw).
148 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:38 (JHutz)
149 * Yes, we support multihomed fileservers.
150 * Since before we got the code from IBM.
151 * But to find out about multiple addresses on a multihomed server, you need
152 * to use VL_GetEntryByNameU and VL_GetAddrsU. If you use
153 * VL_GetEntryByNameO or VL_GetEntryByNameN, the vlserver just gives you one
154 * address per server.
155 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:39 (JHutz)
156 * see src/afs/afs_volume.c, paying particular attention to
157 * afs_NewVolumeByName, afs_SetupVolume, and InstallUVolumeEntry
158 * shadow / openafs / jaltman {ANDREW.CMU.EDU} 01:40 (Jeffrey Altman)
159 * thanks. The windows client calls the 0 versions.
160 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:51 (JHutz)
162 * By not using the N versions, you only get up to 8 sites instead of 13.
163 * By not using the U versions, you don't get to know about multihomed serve
164 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:52 (JHutz)
165 * Of course, you probably want to support the older versions for backward
166 * compatibility. If you do that, you need to call the newest interface
167 * first, and fall back to successively older versions if you get
171 cm_GetEntryByName( struct cm_cell *cellp, const char *name,
172 struct vldbentry *vldbEntryp,
173 struct nvldbentry *nvldbEntryp,
174 struct uvldbentry *uvldbEntryp,
182 struct rx_connection * rxconnp;
184 osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s",
185 osi_LogSaveString(afsd_logp,cellp->name),
186 osi_LogSaveString(afsd_logp,name));
189 code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
193 rxconnp = cm_GetRxConn(connp);
194 code = VL_GetEntryByNameU(rxconnp, name, uvldbEntryp);
196 if ( code == RXGEN_OPCODE )
198 code = VL_GetEntryByNameN(rxconnp, name, nvldbEntryp);
201 if ( code == RXGEN_OPCODE ) {
202 code = VL_GetEntryByNameO(rxconnp, name, vldbEntryp);
205 rx_PutConnection(rxconnp);
206 } while (cm_Analyze(connp, userp, reqp, NULL, 0, NULL, cellp->vlServersp, NULL, code));
207 code = cm_MapVLRPCError(code, reqp);
209 osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
210 osi_LogSaveString(afsd_logp,cellp->name),
211 osi_LogSaveString(afsd_logp,name), code);
213 osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
214 osi_LogSaveString(afsd_logp,cellp->name),
215 osi_LogSaveString(afsd_logp,name));
220 cm_GetEntryByID( struct cm_cell *cellp, afs_uint32 id,
221 struct vldbentry *vldbEntryp,
222 struct nvldbentry *nvldbEntryp,
223 struct uvldbentry *uvldbEntryp,
231 StringCbPrintf(name, sizeof(name), "%u", id);
233 return cm_GetEntryByName(cellp, name, vldbEntryp, nvldbEntryp, uvldbEntryp, methodp, userp, reqp);
236 long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
239 struct rx_connection *rxconnp;
243 cm_serverRef_t *tsrp;
245 struct sockaddr_in tsockAddr;
248 struct vldbentry vldbEntry;
249 struct nvldbentry nvldbEntry;
250 struct uvldbentry uvldbEntry;
255 enum volstatus rwNewstate = vl_online;
256 enum volstatus roNewstate = vl_online;
257 enum volstatus bkNewstate = vl_online;
258 #ifdef AFS_FREELANCE_CLIENT
265 lock_AssertWrite(&volp->rw);
268 * If the last volume update was in the last five
269 * minutes and it did not exist, then avoid the RPC
270 * and return No Such Volume immediately.
273 if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
274 (now < volp->lastUpdateTime + 600))
276 return CM_ERROR_NOSUCHVOLUME;
279 #ifdef AFS_FREELANCE_CLIENT
280 if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID )
283 memset(&vldbEntry, 0, sizeof(vldbEntry));
284 vldbEntry.flags |= VLF_RWEXISTS;
285 vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
291 while (volp->flags & CM_VOLUMEFLAG_UPDATING_VL) {
292 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation sleeping name %s:%s flags 0x%x",
293 volp->cellp->name, volp->namep, volp->flags);
294 osi_SleepW((LONG_PTR) &volp->flags, &volp->rw);
295 lock_ObtainWrite(&volp->rw);
296 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation awake name %s:%s flags 0x%x",
297 volp->cellp->name, volp->namep, volp->flags);
298 if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
299 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation nothing to do, waking others name %s:%s flags 0x%x",
300 volp->cellp->name, volp->namep, volp->flags);
301 osi_Wakeup((LONG_PTR) &volp->flags);
307 /* Do not query again if the last update attempt failed in the last 60 seconds */
308 if ((volp->flags & CM_VOLUMEFLAG_RESET) && (volp->lastUpdateTime > now - 60))
310 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation unsuccessful update in last 60 seconds -- name %s:%s flags 0x%x",
311 volp->cellp->name, volp->namep, volp->flags);
312 return(CM_ERROR_ALLDOWN);
315 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_UPDATING_VL);
316 lock_ReleaseWrite(&volp->rw);
318 if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
319 cm_UpdateCell(cellp, 0);
321 /* now we have volume structure locked and held; make RPC to fill it */
322 code = cm_GetEntryByName(cellp, volp->namep, &vldbEntry, &nvldbEntry,
324 &method, userp, reqp);
327 /* We can end up here with code == CM_ERROR_NOSUCHVOLUME if the base volume name
328 * does not exist and is not a numeric string but there might exist a .readonly volume.
329 * If the base name doesn't exist we will not care about the .backup that might be left
330 * behind since there should be no method to access it.
332 if (code == CM_ERROR_NOSUCHVOLUME &&
333 _atoi64(volp->namep) == 0 &&
334 volp->vol[RWVOL].ID == 0 &&
335 strlen(volp->namep) < (VL_MAXNAMELEN - 9)) {
336 char name[VL_MAXNAMELEN];
338 snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
340 /* now we have volume structure locked and held; make RPC to fill it */
341 code = cm_GetEntryByName(cellp, name, &vldbEntry, &nvldbEntry,
343 &method, userp, reqp);
347 * What if there was a volume rename? The volume name no longer exists but the
348 * volume id might. Try to refresh the volume location information based one
349 * of the readwrite or readonly volume id.
351 if (code == CM_ERROR_NOSUCHVOLUME) {
352 if (volp->vol[RWVOL].ID != 0) {
353 code = cm_GetEntryByID(cellp, volp->vol[RWVOL].ID, &vldbEntry, &nvldbEntry,
355 &method, userp, reqp);
356 } else if (volp->vol[ROVOL].ID != 0) {
357 code = cm_GetEntryByID(cellp, volp->vol[ROVOL].ID, &vldbEntry, &nvldbEntry,
359 &method, userp, reqp);
363 lock_ObtainWrite(&volp->rw);
370 afs_int32 serverNumber[NMAXNSERVERS];
371 afs_int32 serverFlags[NMAXNSERVERS];
372 afsUUID serverUUID[NMAXNSERVERS];
373 afs_int32 rwServers_alldown = 1;
374 afs_int32 roServers_alldown = 1;
375 afs_int32 bkServers_alldown = 1;
376 char name[VL_MAXNAMELEN];
378 #ifdef AFS_FREELANCE_CLIENT
380 rwServers_alldown = 0;
383 /* clear out old bindings */
384 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
385 if (volp->vol[volType].serversp)
386 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
389 memset(serverUUID, 0, sizeof(serverUUID));
393 flags = vldbEntry.flags;
394 nServers = vldbEntry.nServers;
395 replicated = (nServers > 0);
396 rwID = vldbEntry.volumeId[0];
397 roID = vldbEntry.volumeId[1];
398 bkID = vldbEntry.volumeId[2];
399 for ( i=0; i<nServers; i++ ) {
400 serverFlags[i] = vldbEntry.serverFlags[i];
401 serverNumber[i] = vldbEntry.serverNumber[i];
403 strncpy(name, vldbEntry.name, VL_MAXNAMELEN);
404 name[VL_MAXNAMELEN - 1] = '\0';
407 flags = nvldbEntry.flags;
408 nServers = nvldbEntry.nServers;
409 replicated = (nServers > 0);
410 rwID = nvldbEntry.volumeId[0];
411 roID = nvldbEntry.volumeId[1];
412 bkID = nvldbEntry.volumeId[2];
413 for ( i=0; i<nServers; i++ ) {
414 serverFlags[i] = nvldbEntry.serverFlags[i];
415 serverNumber[i] = nvldbEntry.serverNumber[i];
417 strncpy(name, nvldbEntry.name, VL_MAXNAMELEN);
418 name[VL_MAXNAMELEN - 1] = '\0';
421 flags = uvldbEntry.flags;
422 nServers = uvldbEntry.nServers;
423 replicated = (nServers > 0);
424 rwID = uvldbEntry.volumeId[0];
425 roID = uvldbEntry.volumeId[1];
426 bkID = uvldbEntry.volumeId[2];
427 for ( i=0, j=0; code == 0 && i<nServers && j<NMAXNSERVERS; i++ ) {
428 if ( !(uvldbEntry.serverFlags[i] & VLSF_UUID) ) {
429 serverFlags[j] = uvldbEntry.serverFlags[i];
430 serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
433 afs_uint32 * addrp, nentries, code, unique;
435 ListAddrByAttributes attrs;
438 memset(&attrs, 0, sizeof(attrs));
439 attrs.Mask = VLADDR_UUID;
440 attrs.uuid = uvldbEntry.serverNumber[i];
441 memset(&uuid, 0, sizeof(uuid));
442 memset(&addrs, 0, sizeof(addrs));
445 code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
449 rxconnp = cm_GetRxConn(connp);
450 code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries, &addrs);
451 rx_PutConnection(rxconnp);
452 } while (cm_Analyze(connp, userp, reqp, NULL, 0, NULL, cellp->vlServersp, NULL, code));
455 code = cm_MapVLRPCError(code, reqp);
456 osi_Log2(afsd_logp, "CALL VL_GetAddrsU serverNumber %u FAILURE, code 0x%x",
460 osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %u SUCCESS", i);
462 addrp = addrs.bulkaddrs_val;
463 for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
464 serverFlags[j] = uvldbEntry.serverFlags[i];
465 serverNumber[j] = addrp[k];
466 serverUUID[j] = uuid;
469 xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
472 code = CM_ERROR_INVAL;
475 nServers = j; /* update the server count */
476 strncpy(name, uvldbEntry.name, VL_MAXNAMELEN);
477 name[VL_MAXNAMELEN - 1] = '\0';
481 /* decode the response */
482 lock_ObtainWrite(&cm_volumeLock);
483 if (!cm_VolNameIsID(volp->namep)) {
488 if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
489 name[len - 7] = '\0';
490 } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
491 name[len - 9] = '\0';
494 osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s",
495 osi_LogSaveString(afsd_logp,volp->namep), osi_LogSaveString(afsd_logp,name));
497 if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
498 cm_RemoveVolumeFromNameHashTable(volp);
500 strcpy(volp->namep, name);
502 cm_AddVolumeToNameHashTable(volp);
505 if (flags & VLF_DFSFILESET) {
506 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_DFS_VOLUME);
507 osi_Log1(afsd_logp, "cm_UpdateVolume Volume Group '%s' is a DFS File Set. Correct behavior is not implemented.",
508 osi_LogSaveString(afsd_logp, volp->namep));
511 if (flags & VLF_RWEXISTS) {
512 if (volp->vol[RWVOL].ID != rwID) {
513 if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
514 cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
515 volp->vol[RWVOL].ID = rwID;
516 cm_AddVolumeToIDHashTable(volp, RWVOL);
519 if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
520 cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
521 volp->vol[RWVOL].ID = 0;
523 if (flags & VLF_ROEXISTS) {
524 if (volp->vol[ROVOL].ID != roID) {
525 if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
526 cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
527 volp->vol[ROVOL].ID = roID;
528 cm_AddVolumeToIDHashTable(volp, ROVOL);
531 _InterlockedOr(&volp->vol[ROVOL].flags, CM_VOL_STATE_FLAG_REPLICATED);
533 _InterlockedAnd(&volp->vol[ROVOL].flags, ~CM_VOL_STATE_FLAG_REPLICATED);
535 if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
536 cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
537 volp->vol[ROVOL].ID = 0;
539 if (flags & VLF_BACKEXISTS) {
540 if (volp->vol[BACKVOL].ID != bkID) {
541 if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
542 cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
543 volp->vol[BACKVOL].ID = bkID;
544 cm_AddVolumeToIDHashTable(volp, BACKVOL);
547 if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
548 cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
549 volp->vol[BACKVOL].ID = 0;
551 lock_ReleaseWrite(&cm_volumeLock);
553 /* See if the replica sites are mixed versions */
554 for (i=0; i<nServers; i++) {
555 if (serverFlags[i] & VLSF_NEWREPSITE) {
561 for (i=0; i<nServers; i++) {
562 /* create a server entry */
563 tflags = serverFlags[i];
564 if (tflags & VLSF_DONTUSE)
566 tsockAddr.sin_port = htons(7000);
567 tsockAddr.sin_family = AF_INET;
568 tempAddr = htonl(serverNumber[i]);
569 tsockAddr.sin_addr.s_addr = tempAddr;
570 tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE, FALSE);
571 if (tsp && (method == 2) && (tsp->flags & CM_SERVERFLAG_UUID)) {
573 * Check to see if the uuid of the server we know at this address
574 * matches the uuid of the server we are being told about by the
575 * vlserver. If not, ...?
577 if (!afs_uuid_equal(&serverUUID[i], &tsp->uuid)) {
578 char uuid1[128], uuid2[128];
581 afsUUID_to_string(&serverUUID[i], uuid1, sizeof(uuid1));
582 afsUUID_to_string(&tsp->uuid, uuid2, sizeof(uuid2));
583 afs_inet_ntoa_r(serverNumber[i], hoststr);
585 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation UUIDs do not match! %s != %s (%s)",
586 osi_LogSaveString(afsd_logp, uuid1),
587 osi_LogSaveString(afsd_logp, uuid2),
588 osi_LogSaveString(afsd_logp, hoststr));
593 * cm_NewServer will probe the file server which in turn will
594 * update the state on the volume group object. Do not probe
595 * in this thread. It will block the thread and can result in
596 * a recursive call to cm_UpdateVolumeLocation().
598 lock_ReleaseWrite(&volp->rw);
599 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, &serverUUID[i], CM_FLAG_NOPROBE);
600 lock_ObtainWrite(&volp->rw);
602 osi_assertx(tsp != NULL, "null cm_server_t");
605 * if this server was created by fs setserverprefs
606 * then it won't have either a cell assignment or
611 if ( (method == 2) && !(tsp->flags & CM_SERVERFLAG_UUID) &&
612 !afs_uuid_is_nil(&serverUUID[i])) {
613 tsp->uuid = serverUUID[i];
614 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
617 /* and add it to the list(s). */
619 * Each call to cm_NewServerRef() increments the
620 * ref count of tsp. These reference will be dropped,
621 * if and when the volume is reset; see reset code
622 * earlier in this function.
624 if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
625 tsrp = cm_NewServerRef(tsp, rwID);
626 cm_InsertServerList(&volp->vol[RWVOL].serversp, tsrp);
627 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
628 rwServers_alldown = 0;
631 * If there are mixed versions of RO releases on the replica
632 * sites, skip the servers with the out of date versions.
634 if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS) &&
635 (!isMixed || (tflags & VLSF_NEWREPSITE))) {
636 tsrp = cm_NewServerRef(tsp, roID);
637 cm_InsertServerList(&volp->vol[ROVOL].serversp, tsrp);
640 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
641 roServers_alldown = 0;
643 /* We don't use VLSF_BACKVOL !?! */
644 /* Because only the backup on the server holding the RW
645 * volume can be valid. This check prevents errors if a
646 * RW is moved but the old backup is not removed.
648 if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
649 tsrp = cm_NewServerRef(tsp, bkID);
650 cm_InsertServerList(&volp->vol[BACKVOL].serversp, tsrp);
652 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
653 bkServers_alldown = 0;
655 /* Drop the reference obtained by cm_FindServer() */
662 * If the first n servers have the same ipRank, then we
663 * randomly pick one among them and move it to the beginning.
664 * We don't bother to re-order the whole list because
665 * the rest of the list is used only if the first server is
666 * down. We only do this for the RO list; we assume the other
667 * lists are length 1.
670 cm_RandomizeServer(&volp->vol[ROVOL].serversp);
673 rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
674 roNewstate = roServers_alldown ? vl_alldown : vl_online;
675 bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
677 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_NOEXIST);
678 } else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
679 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_NOEXIST);
681 rwNewstate = roNewstate = bkNewstate = vl_alldown;
684 if (volp->vol[RWVOL].state != rwNewstate) {
685 if (volp->vol[RWVOL].ID)
686 cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, rwNewstate);
687 volp->vol[RWVOL].state = rwNewstate;
689 if (volp->vol[ROVOL].state != roNewstate) {
690 if (volp->vol[ROVOL].ID)
691 cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, roNewstate);
692 volp->vol[ROVOL].state = roNewstate;
694 if (volp->vol[BACKVOL].state != bkNewstate) {
695 if (volp->vol[BACKVOL].ID)
696 cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, bkNewstate);
697 volp->vol[BACKVOL].state = bkNewstate;
700 volp->lastUpdateTime = time(NULL);
702 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_MIXED);
704 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_MIXED);
707 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RESET);
709 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_UPDATING_VL);
710 osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x",
711 osi_LogSaveString(afsd_logp,volp->cellp->name),
712 osi_LogSaveString(afsd_logp,volp->namep), volp->flags, code);
713 osi_Wakeup((LONG_PTR) &volp->flags);
718 /* Requires read or write lock on cm_volumeLock */
719 void cm_GetVolume(cm_volume_t *volp)
721 InterlockedIncrement(&volp->refCount);
724 cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
729 lock_ObtainRead(&cm_volumeLock);
730 hash = CM_VOLUME_ID_HASH(fidp->volume);
731 /* The volumeID can be any one of the three types. So we must
732 * search the hash table for all three types until we find it.
733 * We will search in the order of RO, RW, BK.
735 for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
736 if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[ROVOL].ID )
741 for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
742 if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[RWVOL].ID )
748 for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
749 if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[BACKVOL].ID )
754 /* hold the volume if we found it */
758 lock_ReleaseRead(&cm_volumeLock);
762 long cm_FindVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
763 cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
766 #ifdef SEARCH_ALL_VOLUMES
769 char volNameString[VL_MAXNAMELEN];
773 lock_ObtainRead(&cm_volumeLock);
774 #ifdef SEARCH_ALL_VOLUMES
775 for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
776 if (cellp == volp->cellp &&
777 ((unsigned) volumeID == volp->vol[RWVOL].ID ||
778 (unsigned) volumeID == volp->vol[ROVOL].ID ||
779 (unsigned) volumeID == volp->vol[BACKVOL].ID))
784 #endif /* SEARCH_ALL_VOLUMES */
786 hash = CM_VOLUME_ID_HASH(volumeID);
787 /* The volumeID can be any one of the three types. So we must
788 * search the hash table for all three types until we find it.
789 * We will search in the order of RO, RW, BK.
791 for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
792 if ( cellp == volp->cellp && volumeID == volp->vol[ROVOL].ID )
797 for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
798 if ( cellp == volp->cellp && volumeID == volp->vol[RWVOL].ID )
804 for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
805 if ( cellp == volp->cellp && volumeID == volp->vol[BACKVOL].ID )
810 #ifdef SEARCH_ALL_VOLUMES
811 osi_assertx(volp == volp2, "unexpected cm_vol_t");
814 /* hold the volume if we found it */
818 lock_ReleaseRead(&cm_volumeLock);
822 lock_ObtainWrite(&volp->rw);
825 if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
826 code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
828 lock_ReleaseWrite(&volp->rw);
832 if (!(flags & CM_GETVOL_FLAG_NO_LRU_UPDATE)) {
833 lock_ObtainWrite(&cm_volumeLock);
834 cm_AdjustVolumeLRU(volp);
835 lock_ReleaseWrite(&cm_volumeLock);
838 lock_ObtainRead(&cm_volumeLock);
840 lock_ReleaseRead(&cm_volumeLock);
845 /* otherwise, we didn't find it so consult the VLDB */
846 sprintf(volNameString, "%u", volumeID);
847 code = cm_FindVolumeByName(cellp, volNameString, userp, reqp,
848 flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL, outVolpp);
850 if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
851 !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
852 cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
855 code = cm_FindVolumeByID(linkedCellp, volumeID, userp, reqp,
856 flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
863 long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
864 struct cm_user *userp, struct cm_req *reqp,
865 afs_uint32 flags, cm_volume_t **outVolpp)
868 #ifdef SEARCH_ALL_VOLUMES
872 char name[VL_MAXNAMELEN];
877 strncpy(name, volumeNamep, VL_MAXNAMELEN);
878 name[VL_MAXNAMELEN-1] = '\0';
881 if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
883 name[len - 7] = '\0';
884 } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
886 name[len - 9] = '\0';
891 lock_ObtainRead(&cm_volumeLock);
892 #ifdef SEARCH_ALL_VOLUMES
893 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
894 if (cellp == volp->cellp && strcmp(name, volp->namep) == 0) {
899 #endif /* SEARCH_ALL_VOLUMES */
901 hash = CM_VOLUME_NAME_HASH(name);
902 for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
903 if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
907 #ifdef SEARCH_ALL_VOLUMES
908 osi_assertx(volp2 == volp, "unexpected cm_vol_t");
911 if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
913 /* otherwise, get from VLDB */
916 * Change to a write lock so that we have exclusive use of
917 * the first cm_volume_t with a refCount of 0 so that we
918 * have time to increment it.
920 lock_ConvertRToW(&cm_volumeLock);
922 if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
923 #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
924 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
925 if ( volp->refCount == 0 ) {
926 /* There is one we can re-use */
931 for ( volp = cm_data.volumeLRULastp;
933 volp = (cm_volume_t *) osi_QPrev(&volp->q))
935 if ( volp->refCount == 0 ) {
936 /* There is one we can re-use */
942 osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
944 InterlockedIncrement(&volp->refCount);
945 lock_ReleaseWrite(&cm_volumeLock);
946 lock_ObtainWrite(&volp->rw);
947 lock_ObtainWrite(&cm_volumeLock);
949 osi_Log2(afsd_logp, "Recycling Volume %s:%s",
950 volp->cellp->name, volp->namep);
952 /* The volp is removed from the LRU queue in order to
953 * prevent two threads from attempting to recycle the
954 * same object. This volp must be re-inserted back into
955 * the LRU queue before this function exits.
957 if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
958 cm_RemoveVolumeFromLRU(volp);
959 if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
960 cm_RemoveVolumeFromNameHashTable(volp);
962 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
963 if (volp->vol[volType].qflags & CM_VOLUME_QFLAG_IN_HASH)
964 cm_RemoveVolumeFromIDHashTable(volp, volType);
965 if (volp->vol[volType].ID)
966 cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_unknown);
967 volp->vol[volType].ID = 0;
968 cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
969 lock_ReleaseWrite(&cm_volumeLock);
970 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
971 lock_ObtainWrite(&cm_volumeLock);
974 volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
975 memset(volp, 0, sizeof(cm_volume_t));
976 volp->magic = CM_VOLUME_MAGIC;
977 volp->allNextp = cm_data.allVolumesp;
978 cm_data.allVolumesp = volp;
979 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
980 lock_ReleaseWrite(&cm_volumeLock);
981 lock_ObtainWrite(&volp->rw);
982 lock_ObtainWrite(&cm_volumeLock);
983 volp->refCount = 1; /* starts off held */
986 strncpy(volp->namep, name, VL_MAXNAMELEN);
987 volp->namep[VL_MAXNAMELEN-1] = '\0';
988 volp->flags = CM_VOLUMEFLAG_RESET;
989 volp->lastUpdateTime = 0;
991 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
992 volp->vol[volType].state = vl_unknown;
993 volp->vol[volType].nextp = NULL;
994 volp->vol[volType].flags = 0;
996 volp->cbExpiresRO = 0;
997 volp->cbIssuedRO = 0;
998 volp->cbServerpRO = NULL;
999 volp->creationDateRO = 0;
1000 cm_AddVolumeToNameHashTable(volp);
1001 lock_ReleaseWrite(&cm_volumeLock);
1006 lock_ReleaseRead(&cm_volumeLock);
1009 return CM_ERROR_NOSUCHVOLUME;
1011 lock_ObtainWrite(&volp->rw);
1014 /* if we get here we are holding the mutex */
1015 if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
1016 code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1018 lock_ReleaseWrite(&volp->rw);
1020 if (code == 0 && (type == BACKVOL && volp->vol[BACKVOL].ID == 0 ||
1021 type == ROVOL && volp->vol[ROVOL].ID == 0))
1022 code = CM_ERROR_NOSUCHVOLUME;
1027 lock_ObtainWrite(&cm_volumeLock);
1028 if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1029 (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1030 cm_AdjustVolumeLRU(volp);
1031 lock_ReleaseWrite(&cm_volumeLock);
1034 * do not return it to the caller but do insert it in the LRU
1035 * otherwise it will be lost
1037 lock_ObtainWrite(&cm_volumeLock);
1038 if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1039 (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1040 cm_AdjustVolumeLRU(volp);
1042 lock_ReleaseWrite(&cm_volumeLock);
1045 if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
1046 !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
1047 cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
1050 code = cm_FindVolumeByName(linkedCellp, volumeNamep, userp, reqp,
1051 flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
1058 * Only call this function in response to a VNOVOL or VMOVED error
1059 * from a file server. Do not call it in response to CM_ERROR_NOSUCHVOLUME
1060 * as that can lead to recursive calls.
1062 long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
1066 #ifdef SEARCH_ALL_VOLUMES
1073 return CM_ERROR_INVAL;
1075 cellp = cm_FindCellByID(fidp->cell, 0);
1077 return CM_ERROR_NOSUCHCELL;
1079 /* search for the volume */
1080 lock_ObtainRead(&cm_volumeLock);
1081 #ifdef SEARCH_ALL_VOLUMES
1082 for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1083 if (cellp == volp->cellp &&
1084 (fidp->volume == volp->vol[RWVOL].ID ||
1085 fidp->volume == volp->vol[ROVOL].ID ||
1086 fidp->volume == volp->vol[BACKVOL].ID))
1089 #endif /* SEARCH_ALL_VOLUMES */
1091 hash = CM_VOLUME_ID_HASH(fidp->volume);
1092 /* The volumeID can be any one of the three types. So we must
1093 * search the hash table for all three types until we find it.
1094 * We will search in the order of RO, RW, BK.
1096 for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
1097 if ( cellp == volp->cellp && fidp->volume == volp->vol[ROVOL].ID )
1101 /* try RW volumes */
1102 for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
1103 if ( cellp == volp->cellp && fidp->volume == volp->vol[RWVOL].ID )
1108 /* try BK volumes */
1109 for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
1110 if ( cellp == volp->cellp && fidp->volume == volp->vol[BACKVOL].ID )
1115 #ifdef SEARCH_ALL_VOLUMES
1116 osi_assertx(volp == volp2, "unexpected cm_vol_t");
1118 /* hold the volume if we found it */
1122 lock_ReleaseRead(&cm_volumeLock);
1125 return CM_ERROR_NOSUCHVOLUME;
1128 cm_data.mountRootGen = time(NULL);
1129 lock_ObtainWrite(&volp->rw);
1130 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1131 volp->lastUpdateTime = 0;
1133 code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1134 lock_ReleaseWrite(&volp->rw);
1136 lock_ObtainRead(&cm_volumeLock);
1138 lock_ReleaseRead(&cm_volumeLock);
1143 /* find the appropriate servers from a volume */
1144 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume, cm_user_t *userp, cm_req_t *reqp)
1146 cm_serverRef_t **serverspp;
1147 cm_serverRef_t *current;
1151 lock_ObtainWrite(&cm_serverLock);
1153 if (volume == volp->vol[RWVOL].ID)
1154 serverspp = &volp->vol[RWVOL].serversp;
1155 else if (volume == volp->vol[ROVOL].ID)
1156 serverspp = &volp->vol[ROVOL].serversp;
1157 else if (volume == volp->vol[BACKVOL].ID)
1158 serverspp = &volp->vol[BACKVOL].serversp;
1160 lock_ReleaseWrite(&cm_serverLock);
1164 lock_ObtainWrite(&volp->rw);
1165 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1166 volp->lastUpdateTime = 0;
1167 code = cm_UpdateVolumeLocation(volp->cellp, userp, reqp, volp);
1168 lock_ReleaseWrite(&volp->rw);
1176 * Increment the refCount on deleted items as well.
1177 * They will be freed by cm_FreeServerList when they get to zero
1179 for (current = *serverspp; current; current = current->next)
1180 cm_GetServerRef(current, TRUE);
1182 lock_ReleaseWrite(&cm_serverLock);
1187 void cm_PutVolume(cm_volume_t *volp)
1189 afs_int32 refCount = InterlockedDecrement(&volp->refCount);
1190 osi_assertx(refCount >= 0, "cm_volume_t refCount underflow has occurred");
1193 /* return the read-only volume, if there is one, or the read-write volume if
1196 long cm_GetROVolumeID(cm_volume_t *volp)
1200 lock_ObtainRead(&volp->rw);
1201 if (volp->vol[ROVOL].ID && volp->vol[ROVOL].serversp)
1202 id = volp->vol[ROVOL].ID;
1204 id = volp->vol[RWVOL].ID;
1205 lock_ReleaseRead(&volp->rw);
1210 void cm_RefreshVolumes(int lifetime)
1218 /* force mount point target updates */
1219 if (cm_data.mountRootGen + lifetime <= now)
1220 cm_data.mountRootGen = now;
1223 * force a re-loading of volume data from the vldb
1224 * if the lifetime for the cached data has expired
1226 lock_ObtainRead(&cm_volumeLock);
1227 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1228 InterlockedIncrement(&volp->refCount);
1229 lock_ReleaseRead(&cm_volumeLock);
1231 if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
1232 lock_ObtainWrite(&volp->rw);
1233 if (volp->flags & CM_VOLUMEFLAG_RO_MIXED) {
1234 if (volp->lastUpdateTime + 300 <= now) {
1235 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1236 volp->lastUpdateTime = 0;
1239 if (volp->lastUpdateTime + lifetime <= now) {
1240 _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1241 volp->lastUpdateTime = 0;
1244 lock_ReleaseWrite(&volp->rw);
1247 lock_ObtainRead(&cm_volumeLock);
1248 refCount = InterlockedDecrement(&volp->refCount);
1249 osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1251 lock_ReleaseRead(&cm_volumeLock);
1255 cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
1256 afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
1260 AFSFetchVolumeStatus volStat;
1265 struct rx_connection * rxconnp;
1267 char offLineMsg[256];
1269 long alldown, alldeleted;
1270 cm_serverRef_t *serversp;
1274 OfflineMsg = offLineMsg;
1277 if (statep->ID != 0 && (!volID || volID == statep->ID)) {
1278 /* create fid for volume root so that VNOVOL and VMOVED errors can be processed */
1279 cm_SetFid(&fid, volp->cellp->cellID, statep->ID, 1, 1);
1281 if (!statep->serversp && !(*volumeUpdatedp)) {
1283 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1284 *volumeUpdatedp = 1;
1287 lock_ObtainRead(&cm_serverLock);
1288 if (statep->serversp) {
1291 for (serversp = statep->serversp; serversp; serversp = serversp->next) {
1292 if (serversp->status == srv_deleted)
1297 if (!(serversp->server->flags & CM_SERVERFLAG_DOWN))
1300 if (serversp->status == srv_busy || serversp->status == srv_offline)
1301 serversp->status = srv_not_busy;
1303 lock_ReleaseRead(&cm_serverLock);
1305 if (alldeleted && !(*volumeUpdatedp)) {
1307 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1308 *volumeUpdatedp = 1;
1311 if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
1312 (!alldown && statep->state == vl_alldown)) {
1314 req.flags |= CM_REQ_OFFLINE_VOL_CHK;
1316 lock_ReleaseWrite(&volp->rw);
1318 code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
1322 rxconnp = cm_GetRxConn(connp);
1323 code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
1324 &volStat, &Name, &OfflineMsg, &MOTD);
1325 rx_PutConnection(rxconnp);
1326 } while (cm_Analyze(connp, cm_rootUserp, &req, &fid, 0, NULL, NULL, NULL, code));
1327 code = cm_MapRPCError(code, &req);
1329 lock_ObtainWrite(&volp->rw);
1330 if (code == 0 && volStat.Online) {
1331 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
1332 statep->state = vl_online;
1334 } else if (code == CM_ERROR_NOACCESS) {
1335 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
1336 statep->state = vl_unknown;
1339 } else if (alldown && statep->state != vl_alldown) {
1340 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1341 statep->state = vl_alldown;
1344 lock_ReleaseRead(&cm_serverLock);
1345 if (statep->state != vl_alldown) {
1346 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1347 statep->state = vl_alldown;
1353 /* The return code is 0 if the volume is not online and
1354 * 1 if the volume is online
1357 cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
1361 afs_uint32 online = 0;
1362 afs_uint32 volumeUpdated = 0;
1364 lock_ObtainWrite(&volp->rw);
1366 if (volp->flags & CM_VOLUMEFLAG_RESET) {
1368 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1372 cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
1373 cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
1374 cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
1376 lock_ReleaseWrite(&volp->rw);
1382 * called from the Daemon thread.
1383 * when checking the offline status, check those of the most recently used volumes first.
1385 void cm_CheckOfflineVolumes(void)
1389 extern int daemon_ShutdownFlag;
1390 extern int powerStateSuspended;
1392 lock_ObtainRead(&cm_volumeLock);
1393 for (volp = cm_data.volumeLRULastp;
1394 volp && !daemon_ShutdownFlag && !powerStateSuspended;
1395 volp=(cm_volume_t *) osi_QPrev(&volp->q)) {
1397 * Skip volume entries that did not exist last time
1398 * the vldb was queried. For those entries wait until
1399 * the next actual request is received for the volume
1400 * before checking its state.
1402 if ((volp->qflags & CM_VOLUME_QFLAG_IN_HASH) &&
1403 !(volp->flags & CM_VOLUMEFLAG_NOEXIST)) {
1404 InterlockedIncrement(&volp->refCount);
1405 lock_ReleaseRead(&cm_volumeLock);
1406 cm_CheckOfflineVolume(volp, 0);
1407 lock_ObtainRead(&cm_volumeLock);
1408 refCount = InterlockedDecrement(&volp->refCount);
1409 osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1412 lock_ReleaseRead(&cm_volumeLock);
1417 cm_UpdateVolumeStatusInt(cm_volume_t *volp, struct cm_vol_state *statep)
1419 enum volstatus newStatus;
1420 cm_serverRef_t *tsrp;
1422 int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
1425 if (!volp || !statep) {
1432 lock_ObtainWrite(&cm_serverLock);
1433 for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1435 sprintf(addr, "%d.%d.%d.%d",
1436 ((tsp->addr.sin_addr.s_addr & 0xff)),
1437 ((tsp->addr.sin_addr.s_addr & 0xff00)>> 8),
1438 ((tsp->addr.sin_addr.s_addr & 0xff0000)>> 16),
1439 ((tsp->addr.sin_addr.s_addr & 0xff000000)>> 24));
1441 if (tsrp->status == srv_deleted) {
1442 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s deleted",
1443 statep->ID, osi_LogSaveString(afsd_logp,addr));
1447 cm_GetServerNoLock(tsp);
1448 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
1450 if (tsrp->status == srv_busy) {
1451 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s busy",
1452 statep->ID, osi_LogSaveString(afsd_logp,addr));
1455 } else if (tsrp->status == srv_offline) {
1456 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s offline",
1457 statep->ID, osi_LogSaveString(afsd_logp,addr));
1461 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s online",
1462 statep->ID, osi_LogSaveString(afsd_logp,addr));
1467 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s down",
1468 statep->ID, osi_LogSaveString(afsd_logp,addr));
1470 cm_PutServerNoLock(tsp);
1473 lock_ReleaseWrite(&cm_serverLock);
1475 osi_Log5(afsd_logp, "cm_UpdateVolumeStatusInt allDown %d allBusy %d someBusy %d someOffline %d allOffline %d",
1476 allDown, allBusy, someBusy, someOffline, allOffline);
1479 newStatus = vl_alldown;
1480 else if (allBusy || (someBusy && someOffline))
1481 newStatus = vl_busy;
1482 else if (allOffline)
1483 newStatus = vl_offline;
1485 newStatus = vl_online;
1487 if (statep->ID && statep->state != newStatus)
1488 cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
1490 statep->state = newStatus;
1494 cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1497 if (volp->vol[RWVOL].ID == volID) {
1498 cm_UpdateVolumeStatusInt(volp, &volp->vol[RWVOL]);
1499 } else if (volp->vol[ROVOL].ID == volID) {
1500 cm_UpdateVolumeStatusInt(volp, &volp->vol[ROVOL]);
1501 } else if (volp->vol[BACKVOL].ID == volID) {
1502 cm_UpdateVolumeStatusInt(volp, &volp->vol[BACKVOL]);
1505 * If we are called with volID == 0 then something has gone wrong.
1506 * Most likely a race occurred in the server volume list maintenance.
1507 * Since we don't know which volume's status should be updated,
1508 * just update all of them that are known to exist. Better to be
1509 * correct than fast.
1512 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1513 if (volp->vol[volType].ID != 0)
1514 cm_UpdateVolumeStatusInt(volp, &volp->vol[volType]);
1520 ** Finds all volumes that reside on this server and reorders their
1521 ** RO list according to the changed rank of server.
1523 void cm_ChangeRankVolume(cm_server_t *tsp)
1529 /* find volumes which might have RO copy on server*/
1530 lock_ObtainRead(&cm_volumeLock);
1531 for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1533 code = 1 ; /* assume that list is unchanged */
1534 InterlockedIncrement(&volp->refCount);
1535 lock_ReleaseRead(&cm_volumeLock);
1536 lock_ObtainWrite(&volp->rw);
1538 if ((tsp->cellp==volp->cellp) && (volp->vol[ROVOL].serversp))
1539 code =cm_ChangeRankServer(&volp->vol[ROVOL].serversp, tsp);
1541 /* this volume list was changed */
1543 cm_RandomizeServer(&volp->vol[ROVOL].serversp);
1545 lock_ReleaseWrite(&volp->rw);
1546 lock_ObtainRead(&cm_volumeLock);
1547 refCount = InterlockedDecrement(&volp->refCount);
1548 osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1550 lock_ReleaseRead(&cm_volumeLock);
1553 /* dump all volumes that have reference count > 0 to a file.
1554 * cookie is used to identify this batch for easy parsing,
1555 * and it a string provided by a caller
1557 int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
1564 lock_ObtainRead(&cm_scacheLock);
1565 lock_ObtainRead(&cm_volumeLock);
1568 sprintf(output, "%s - dumping volumes - cm_data.currentVolumes=%d, cm_data.maxVolumes=%d\r\n",
1569 cookie, cm_data.currentVolumes, cm_data.maxVolumes);
1570 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1572 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1575 char *srvStr = NULL;
1576 afs_uint32 srvStrRpc = TRUE;
1580 if (volp->cbServerpRO) {
1581 if (!((volp->cbServerpRO->flags & CM_SERVERFLAG_UUID) &&
1582 UuidToString((UUID *)&volp->cbServerpRO->uuid, &srvStr) == RPC_S_OK)) {
1583 srvStr = malloc(16);
1585 afs_inet_ntoa_r(volp->cbServerpRO->addr.sin_addr.s_addr, srvStr);
1589 if (volp->cbExpiresRO) {
1590 t = volp->cbExpiresRO;
1594 cbt[strlen(cbt)-1] = '\0';
1597 if (volp->creationDateRO) {
1598 t = volp->creationDateRO;
1601 cdrot = strdup(cdrot);
1602 cdrot[strlen(cdrot)-1] = '\0';
1607 "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x:%x "
1608 "cbServerpRO='%s' cbExpiresRO='%s' creationDateRO='%s' refCount=%u\r\n",
1609 cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID,
1610 volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags, volp->qflags,
1611 srvStr ? srvStr : "<none>", cbt ? cbt : "<none>", cdrot ? cdrot : "<none>",
1613 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1617 RpcStringFree(&srvStr);
1626 sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
1627 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1630 lock_ReleaseRead(&cm_volumeLock);
1631 lock_ReleaseRead(&cm_scacheLock);
1638 * String hash function used by SDBM project.
1639 * It was chosen because it is fast and provides
1642 afs_uint32 SDBMHash(const char * str)
1644 afs_uint32 hash = 0;
1650 for(i = 0, len = strlen(str); i < len; i++)
1652 hash = str[i] + (hash << 6) + (hash << 16) - hash;
1655 return (hash & 0x7FFFFFFF);
1658 /* call with volume write-locked and mutex held */
1659 void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
1663 if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
1666 i = CM_VOLUME_NAME_HASH(volp->namep);
1668 volp->nameNextp = cm_data.volumeNameHashTablep[i];
1669 cm_data.volumeNameHashTablep[i] = volp;
1670 _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_HASH);
1673 /* call with volume write-locked and mutex held */
1674 void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
1676 cm_volume_t **lvolpp;
1680 if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1681 /* hash it out first */
1682 i = CM_VOLUME_NAME_HASH(volp->namep);
1683 for (lvolpp = &cm_data.volumeNameHashTablep[i], tvolp = cm_data.volumeNameHashTablep[i];
1685 lvolpp = &tvolp->nameNextp, tvolp = tvolp->nameNextp) {
1686 if (tvolp == volp) {
1687 *lvolpp = volp->nameNextp;
1688 _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1689 volp->nameNextp = NULL;
1696 /* call with volume write-locked and mutex held */
1697 void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1700 struct cm_vol_state * statep;
1702 statep = cm_VolumeStateByType(volp, volType);
1704 if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH)
1707 i = CM_VOLUME_ID_HASH(statep->ID);
1711 statep->nextp = cm_data.volumeRWIDHashTablep[i];
1712 cm_data.volumeRWIDHashTablep[i] = volp;
1715 statep->nextp = cm_data.volumeROIDHashTablep[i];
1716 cm_data.volumeROIDHashTablep[i] = volp;
1719 statep->nextp = cm_data.volumeBKIDHashTablep[i];
1720 cm_data.volumeBKIDHashTablep[i] = volp;
1723 _InterlockedOr(&statep->qflags, CM_VOLUME_QFLAG_IN_HASH);
1727 /* call with volume write-locked and mutex held */
1728 void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1730 cm_volume_t **lvolpp;
1732 struct cm_vol_state * statep;
1735 statep = cm_VolumeStateByType(volp, volType);
1737 if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1738 /* hash it out first */
1739 i = CM_VOLUME_ID_HASH(statep->ID);
1743 lvolpp = &cm_data.volumeRWIDHashTablep[i];
1744 tvolp = cm_data.volumeRWIDHashTablep[i];
1747 lvolpp = &cm_data.volumeROIDHashTablep[i];
1748 tvolp = cm_data.volumeROIDHashTablep[i];
1751 lvolpp = &cm_data.volumeBKIDHashTablep[i];
1752 tvolp = cm_data.volumeBKIDHashTablep[i];
1755 osi_assertx(0, "invalid volume type");
1758 if (tvolp == volp) {
1759 *lvolpp = statep->nextp;
1760 _InterlockedAnd(&statep->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1761 statep->nextp = NULL;
1765 lvolpp = &tvolp->vol[volType].nextp;
1766 tvolp = tvolp->vol[volType].nextp;
1771 /* must be called with cm_volumeLock write-locked! */
1772 void cm_AdjustVolumeLRU(cm_volume_t *volp)
1774 lock_AssertWrite(&cm_volumeLock);
1776 if (volp == cm_data.volumeLRUFirstp)
1779 if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1780 osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1781 osi_QAddH((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1782 _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1784 osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1787 /* must be called with cm_volumeLock write-locked! */
1788 void cm_MoveVolumeToLRULast(cm_volume_t *volp)
1790 lock_AssertWrite(&cm_volumeLock);
1792 if (volp == cm_data.volumeLRULastp)
1795 if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1796 osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1797 osi_QAddT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1798 _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1800 osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1803 /* must be called with cm_volumeLock write-locked! */
1804 void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
1806 lock_AssertWrite(&cm_volumeLock);
1808 if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) {
1809 osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1810 _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1813 osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1816 static char * volstatus_str(enum volstatus vs)
1832 void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
1834 char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN]="";
1837 if (volID == volp->vol[RWVOL].ID)
1839 else if (volID == volp->vol[ROVOL].ID)
1841 else if (volID == volp->vol[BACKVOL].ID)
1845 snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
1847 osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
1848 osi_LogSaveString(afsd_logp, volstr), volID, volstatus_str(old), volstatus_str(new));
1850 cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new);
1853 enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1855 cm_vol_state_t * statep = cm_VolumeStateByID(volp, volID);
1857 return statep->state;
1862 /* Renew .readonly volume callbacks that are more than
1863 * 30 minutes old. (A volume callback is issued for 2 hours.)
1866 cm_VolumeRenewROCallbacks(void)
1869 time_t minexp = time(NULL) + 90 * 60;
1870 extern int daemon_ShutdownFlag;
1871 extern int powerStateSuspended;
1873 lock_ObtainRead(&cm_volumeLock);
1874 for (volp = cm_data.allVolumesp;
1875 volp && !daemon_ShutdownFlag && !powerStateSuspended;
1876 volp=volp->allNextp) {
1877 if ( volp->cbExpiresRO > 0 && volp->cbExpiresRO < minexp) {
1882 cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
1886 lock_ReleaseRead(&cm_volumeLock);
1887 if (cm_GetSCache(&fid, NULL, &scp, cm_rootUserp, &req) == 0) {
1888 lock_ObtainWrite(&scp->rw);
1889 cm_GetCallback(scp, cm_rootUserp, &req, 1);
1890 lock_ReleaseWrite(&scp->rw);
1891 cm_ReleaseSCache(scp);
1893 lock_ObtainRead(&cm_volumeLock);
1896 lock_ReleaseRead(&cm_volumeLock);
1900 cm_VolumeStateByType(cm_volume_t *volp, afs_uint32 volType)
1902 return &volp->vol[volType];
1906 cm_VolumeStateByID(cm_volume_t *volp, afs_uint32 id)
1908 cm_vol_state_t * statep = NULL;
1910 if (id == volp->vol[RWVOL].ID)
1911 statep = &volp->vol[RWVOL];
1912 else if (id == volp->vol[ROVOL].ID)
1913 statep = &volp->vol[ROVOL];
1914 else if (id == volp->vol[BACKVOL].ID)
1915 statep = &volp->vol[BACKVOL];
1921 cm_VolumeStateByName(cm_volume_t *volp, char *volname)
1923 size_t len = strlen(volname);
1924 cm_vol_state_t *statep;
1926 if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
1927 statep = &volp->vol[ROVOL];
1928 else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
1929 statep = &volp->vol[BACKVOL];
1931 statep = &volp->vol[RWVOL];
1937 cm_VolumeType(cm_volume_t *volp, afs_uint32 id)
1939 if (id == volp->vol[RWVOL].ID)
1941 else if (id == volp->vol[ROVOL].ID)
1943 else if (id == volp->vol[BACKVOL].ID)