Windows: Do not probe new servers from cm_UpdateVolumeLocation
[openafs.git] / src / WINNT / afsd / cm_volume.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <windows.h>
17 #include <winsock2.h>
18 #include <nb30.h>
19 #include <string.h>
20 #include <malloc.h>
21 #include "afsd.h"
22 #include <osi.h>
23 #include <rx/rx.h>
24
25 osi_rwlock_t cm_volumeLock;
26
27 long
28 cm_ValidateVolume(void)
29 {
30     cm_volume_t * volp;
31     afs_uint32 count;
32
33     for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->allNextp, count++) {
34         if ( volp->magic != CM_VOLUME_MAGIC ) {
35             afsi_log("cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC");
36             fprintf(stderr, "cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC\n");
37             return -1;
38         }
39         if ( volp->cellp && volp->cellp->magic != CM_CELL_MAGIC ) {
40             afsi_log("cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC");
41             fprintf(stderr, "cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC\n");
42             return -2;
43         }
44         if ( volp->allNextp && volp->allNextp->magic != CM_VOLUME_MAGIC ) {
45             afsi_log("cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC");
46             fprintf(stderr, "cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC\n");
47             return -3;
48         }
49         if ( count != 0 && volp == cm_data.allVolumesp ||
50              count > cm_data.maxVolumes ) {
51             afsi_log("cm_ValidateVolume failure: cm_data.allVolumep loop detected");
52             fprintf(stderr, "cm_ValidateVolume failure: cm_data.allVolumep loop detected\n");
53             return -4;
54         }
55     }
56
57     if ( count != cm_data.currentVolumes ) {
58         afsi_log("cm_ValidateVolume failure: count != cm_data.currentVolumes");
59         fprintf(stderr, "cm_ValidateVolume failure: count != cm_data.currentVolumes\n");
60         return -5;
61     }
62
63     return 0;
64 }
65
66 long
67 cm_ShutdownVolume(void)
68 {
69     cm_volume_t * volp;
70
71     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
72         afs_uint32 volType;
73         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
74             if (volp->vol[volType].ID)
75                 cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_alldown);
76         }
77         volp->cbExpiresRO = 0;
78         volp->cbServerpRO = NULL;
79         lock_FinalizeRWLock(&volp->rw);
80     }
81
82     return 0;
83 }
84
85 void cm_InitVolume(int newFile, long maxVols)
86 {
87     static osi_once_t once;
88
89     if (osi_Once(&once)) {
90         lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock", LOCK_HIERARCHY_VOLUME_GLOBAL);
91
92         if ( newFile ) {
93             cm_data.allVolumesp = NULL;
94             cm_data.currentVolumes = 0;
95             cm_data.maxVolumes = maxVols;
96             memset(cm_data.volumeNameHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
97             memset(cm_data.volumeRWIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
98             memset(cm_data.volumeROIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
99             memset(cm_data.volumeBKIDHashTablep, 0, sizeof(cm_volume_t *) * cm_data.volumeHashTableSize);
100             cm_data.volumeLRUFirstp = cm_data.volumeLRULastp = NULL;
101         } else {
102             cm_volume_t * volp;
103
104             for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
105                 afs_uint32 volType;
106
107                 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
108                 volp->flags |= CM_VOLUMEFLAG_RESET;
109                 volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
110                 for (volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
111                     volp->vol[volType].state = vl_unknown;
112                     volp->vol[volType].serversp = NULL;
113                     if (volp->vol[volType].ID)
114                         cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_unknown, volp->vol[volType].state);
115                 }
116                 volp->cbExpiresRO = 0;
117                 volp->cbServerpRO = NULL;
118             }
119         }
120         osi_EndOnce(&once);
121     }
122 }
123
124
125 /* returns true if the id is a decimal integer, in which case we interpret it
126  * as an id.  make the cache manager much simpler.
127  * Stolen from src/volser/vlprocs.c */
128 int
129 cm_VolNameIsID(char *aname)
130 {
131     int tc;
132     while (tc = *aname++) {
133         if (tc > '9' || tc < '0')
134             return 0;
135     }
136     return 1;
137 }
138
139
140 /*
141  * Update a volume.  Caller holds a write lock on the volume (volp->rw).
142  *
143  *
144  *  shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU}  01:38    (JHutz)
145  *    Yes, we support multihomed fileservers.
146  *    Since before we got the code from IBM.
147  *    But to find out about multiple addresses on a multihomed server, you need
148  *    to use VL_GetEntryByNameU and VL_GetAddrsU.  If you use
149  *    VL_GetEntryByNameO or VL_GetEntryByNameN, the vlserver just gives you one
150  *    address per server.
151  *  shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU}  01:39    (JHutz)
152  *    see src/afs/afs_volume.c, paying particular attention to
153  *    afs_NewVolumeByName, afs_SetupVolume, and InstallUVolumeEntry
154  *  shadow / openafs / jaltman {ANDREW.CMU.EDU}  01:40    (Jeffrey Altman)
155  *    thanks.  The windows client calls the 0 versions.
156  *  shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU}  01:51    (JHutz)
157  *    Oh.  Ew.
158  *    By not using the N versions, you only get up to 8 sites instead of 13.
159  *    By not using the U versions, you don't get to know about multihomed serve
160  *  shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU}  01:52    (JHutz)
161  *    Of course, you probably want to support the older versions for backward
162  *    compatibility.  If you do that, you need to call the newest interface
163  *    first, and fall back to successively older versions if you get
164  *    RXGEN_OPCODE.
165  */
166 #define MULTIHOMED 1
167 long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
168                      cm_volume_t *volp)
169 {
170     cm_conn_t *connp;
171     int i;
172     afs_uint32 j, k;
173     cm_serverRef_t *tsrp;
174     cm_server_t *tsp;
175     struct sockaddr_in tsockAddr;
176     long tflags;
177     u_long tempAddr;
178     struct vldbentry vldbEntry;
179     struct nvldbentry nvldbEntry;
180 #ifdef MULTIHOMED
181     struct uvldbentry uvldbEntry;
182 #endif
183     int method = -1;
184     int ROcount = 0;
185     long code;
186     enum volstatus rwNewstate = vl_online;
187     enum volstatus roNewstate = vl_online;
188     enum volstatus bkNewstate = vl_online;
189 #ifdef AFS_FREELANCE_CLIENT
190     int freelance = 0;
191 #endif
192     afs_uint32 volType;
193     time_t now;
194
195     lock_AssertWrite(&volp->rw);
196
197     /*
198      * If the last volume update was in the last five
199      * minutes and it did not exist, then avoid the RPC
200      * and return No Such Volume immediately.
201      */
202     now = time(NULL);
203     if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
204         (now < volp->lastUpdateTime + 600))
205     {
206         return CM_ERROR_NOSUCHVOLUME;
207     }
208
209 #ifdef AFS_FREELANCE_CLIENT
210     if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID )
211     {
212         freelance = 1;
213         memset(&vldbEntry, 0, sizeof(vldbEntry));
214         vldbEntry.flags |= VLF_RWEXISTS;
215         vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
216         code = 0;
217         method = 0;
218     } else
219 #endif
220     {
221         while (volp->flags & CM_VOLUMEFLAG_UPDATING_VL) {
222             osi_Log3(afsd_logp, "cm_UpdateVolumeLocation sleeping name %s:%s flags 0x%x",
223                      volp->cellp->name, volp->namep, volp->flags);
224             osi_SleepW((LONG_PTR) &volp->flags, &volp->rw);
225             lock_ObtainWrite(&volp->rw);
226             osi_Log3(afsd_logp, "cm_UpdateVolumeLocation awake name %s:%s flags 0x%x",
227                      volp->cellp->name, volp->namep, volp->flags);
228             if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
229                 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation nothing to do, waking others name %s:%s flags 0x%x",
230                          volp->cellp->name, volp->namep, volp->flags);
231                 osi_Wakeup((LONG_PTR) &volp->flags);
232                 return 0;
233             }
234         }
235
236         volp->flags |= CM_VOLUMEFLAG_UPDATING_VL;
237         lock_ReleaseWrite(&volp->rw);
238
239         if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
240             cm_UpdateCell(cellp, 0);
241
242         /* now we have volume structure locked and held; make RPC to fill it */
243         osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s",
244                   osi_LogSaveString(afsd_logp,volp->cellp->name),
245                   osi_LogSaveString(afsd_logp,volp->namep));
246         do {
247             struct rx_connection * rxconnp;
248
249             code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
250             if (code)
251                 continue;
252
253             rxconnp = cm_GetRxConn(connp);
254 #ifdef MULTIHOMED
255             code = VL_GetEntryByNameU(rxconnp, volp->namep, &uvldbEntry);
256             method = 2;
257             if ( code == RXGEN_OPCODE )
258 #endif
259             {
260                 code = VL_GetEntryByNameN(rxconnp, volp->namep, &nvldbEntry);
261                 method = 1;
262             }
263             if ( code == RXGEN_OPCODE ) {
264                 code = VL_GetEntryByNameO(rxconnp, volp->namep, &vldbEntry);
265                 method = 0;
266             }
267             rx_PutConnection(rxconnp);
268         } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
269         code = cm_MapVLRPCError(code, reqp);
270         if ( code )
271             osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
272                       osi_LogSaveString(afsd_logp,volp->cellp->name),
273                       osi_LogSaveString(afsd_logp,volp->namep), code);
274         else
275             osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
276                       osi_LogSaveString(afsd_logp,volp->cellp->name),
277                       osi_LogSaveString(afsd_logp,volp->namep));
278     }
279
280     /* We can end up here with code == CM_ERROR_NOSUCHVOLUME if the base volume name
281      * does not exist and is not a numeric string but there might exist a .readonly volume.
282      * If the base name doesn't exist we will not care about the .backup that might be left
283      * behind since there should be no method to access it.
284      */
285     if (code == CM_ERROR_NOSUCHVOLUME &&
286         _atoi64(volp->namep) == 0 &&
287         volp->vol[RWVOL].ID == 0 &&
288         strlen(volp->namep) < (VL_MAXNAMELEN - 9)) {
289         char name[VL_MAXNAMELEN];
290
291         snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
292
293         /* now we have volume structure locked and held; make RPC to fill it */
294         osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s",
295                  osi_LogSaveString(afsd_logp,volp->cellp->name),
296                  osi_LogSaveString(afsd_logp,name));
297         do {
298             struct rx_connection * rxconnp;
299
300             code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
301             if (code)
302                 continue;
303
304             rxconnp = cm_GetRxConn(connp);
305 #ifdef MULTIHOMED
306             code = VL_GetEntryByNameU(connp->rxconnp, name, &uvldbEntry);
307             method = 2;
308             if ( code == RXGEN_OPCODE )
309 #endif
310             {
311                 code = VL_GetEntryByNameN(connp->rxconnp, name, &nvldbEntry);
312                 method = 1;
313             }
314             if ( code == RXGEN_OPCODE ) {
315                 code = VL_GetEntryByNameO(connp->rxconnp, name, &vldbEntry);
316                 method = 0;
317             }
318             rx_PutConnection(rxconnp);
319         } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
320         code = cm_MapVLRPCError(code, reqp);
321         if ( code )
322             osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
323                      osi_LogSaveString(afsd_logp,volp->cellp->name),
324                      osi_LogSaveString(afsd_logp,name), code);
325         else
326             osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
327                      osi_LogSaveString(afsd_logp,volp->cellp->name),
328                      osi_LogSaveString(afsd_logp,name));
329     }
330
331     lock_ObtainWrite(&volp->rw);
332     if (code == 0) {
333         afs_int32 flags;
334         afs_int32 nServers;
335         afs_int32 rwID;
336         afs_int32 roID;
337         afs_int32 bkID;
338         afs_int32 serverNumber[NMAXNSERVERS];
339         afs_int32 serverFlags[NMAXNSERVERS];
340         afsUUID   serverUUID[NMAXNSERVERS];
341         afs_int32 rwServers_alldown = 1;
342         afs_int32 roServers_alldown = 1;
343         afs_int32 bkServers_alldown = 1;
344         char      name[VL_MAXNAMELEN];
345
346 #ifdef AFS_FREELANCE_CLIENT
347         if (freelance)
348             rwServers_alldown = 0;
349 #endif
350
351         /* clear out old bindings */
352         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
353             if (volp->vol[volType].serversp)
354                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
355         }
356
357         memset(serverUUID, 0, sizeof(serverUUID));
358
359         switch ( method ) {
360         case 0:
361             flags = vldbEntry.flags;
362             nServers = vldbEntry.nServers;
363             rwID = vldbEntry.volumeId[0];
364             roID = vldbEntry.volumeId[1];
365             bkID = vldbEntry.volumeId[2];
366             for ( i=0; i<nServers; i++ ) {
367                 serverFlags[i] = vldbEntry.serverFlags[i];
368                 serverNumber[i] = vldbEntry.serverNumber[i];
369             }
370             strncpy(name, vldbEntry.name, VL_MAXNAMELEN);
371             name[VL_MAXNAMELEN - 1] = '\0';
372             break;
373         case 1:
374             flags = nvldbEntry.flags;
375             nServers = nvldbEntry.nServers;
376             rwID = nvldbEntry.volumeId[0];
377             roID = nvldbEntry.volumeId[1];
378             bkID = nvldbEntry.volumeId[2];
379             for ( i=0; i<nServers; i++ ) {
380                 serverFlags[i] = nvldbEntry.serverFlags[i];
381                 serverNumber[i] = nvldbEntry.serverNumber[i];
382             }
383             strncpy(name, nvldbEntry.name, VL_MAXNAMELEN);
384             name[VL_MAXNAMELEN - 1] = '\0';
385             break;
386 #ifdef MULTIHOMED
387         case 2:
388             flags = uvldbEntry.flags;
389             nServers = uvldbEntry.nServers;
390             rwID = uvldbEntry.volumeId[0];
391             roID = uvldbEntry.volumeId[1];
392             bkID = uvldbEntry.volumeId[2];
393             for ( i=0, j=0; code == 0 && i<nServers && j<NMAXNSERVERS; i++ ) {
394                 if ( !(uvldbEntry.serverFlags[i] & VLSERVER_FLAG_UUID) ) {
395                     serverFlags[j] = uvldbEntry.serverFlags[i];
396                     serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
397                     j++;
398                 } else {
399                     afs_uint32 * addrp, nentries, code, unique;
400                     bulkaddrs  addrs;
401                     ListAddrByAttributes attrs;
402                     afsUUID uuid;
403
404                     memset(&attrs, 0, sizeof(attrs));
405                     attrs.Mask = VLADDR_UUID;
406                     attrs.uuid = uvldbEntry.serverNumber[i];
407                     memset(&uuid, 0, sizeof(uuid));
408                     memset(&addrs, 0, sizeof(addrs));
409
410                     do {
411                         struct rx_connection *rxconnp;
412
413                         code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
414                         if (code)
415                             continue;
416
417                         rxconnp = cm_GetRxConn(connp);
418                         code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries, &addrs);
419                         rx_PutConnection(rxconnp);
420                     } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
421
422                     if ( code ) {
423                         code = cm_MapVLRPCError(code, reqp);
424                         osi_Log2(afsd_logp, "CALL VL_GetAddrsU serverNumber %u FAILURE, code 0x%x",
425                                  i, code);
426                         continue;
427                     }
428                     osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %u SUCCESS", i);
429
430                     addrp = addrs.bulkaddrs_val;
431                     for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
432                         serverFlags[j] = uvldbEntry.serverFlags[i];
433                         serverNumber[j] = addrp[k];
434                         serverUUID[j] = uuid;
435                     }
436
437                     xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
438
439                     if (nentries == 0)
440                         code = CM_ERROR_INVAL;
441                 }
442             }
443             nServers = j;                                       /* update the server count */
444             strncpy(name, uvldbEntry.name, VL_MAXNAMELEN);
445             name[VL_MAXNAMELEN - 1] = '\0';
446             break;
447 #endif
448         }
449
450         /* decode the response */
451         lock_ObtainWrite(&cm_volumeLock);
452         if (cm_VolNameIsID(volp->namep)) {
453             size_t    len;
454
455             len = strlen(name);
456
457             if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
458                 name[len - 7] = '\0';
459             } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
460                 name[len - 9] = '\0';
461             }
462
463             osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s",
464                      osi_LogSaveString(afsd_logp,volp->namep), osi_LogSaveString(afsd_logp,name));
465
466             if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
467                 cm_RemoveVolumeFromNameHashTable(volp);
468
469             strcpy(volp->namep, name);
470
471             cm_AddVolumeToNameHashTable(volp);
472         }
473
474         if (flags & VLF_DFSFILESET) {
475             volp->flags |= CM_VOLUMEFLAG_DFS_VOLUME;
476             osi_Log1(afsd_logp, "cm_UpdateVolume Volume Group '%s' is a DFS File Set.  Correct behavior is not implemented.",
477                      osi_LogSaveString(afsd_logp, volp->namep));
478         }
479
480         if (flags & VLF_RWEXISTS) {
481             if (volp->vol[RWVOL].ID != rwID) {
482                 if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
483                     cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
484                 volp->vol[RWVOL].ID = rwID;
485                 cm_AddVolumeToIDHashTable(volp, RWVOL);
486             }
487         } else {
488             if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
489                 cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
490             volp->vol[RWVOL].ID = 0;
491         }
492         if (flags & VLF_ROEXISTS) {
493             if (volp->vol[ROVOL].ID != roID) {
494                 if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
495                     cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
496                 volp->vol[ROVOL].ID = roID;
497                 cm_AddVolumeToIDHashTable(volp, ROVOL);
498             }
499         } else {
500             if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
501                 cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
502             volp->vol[ROVOL].ID = 0;
503         }
504         if (flags & VLF_BACKEXISTS) {
505             if (volp->vol[BACKVOL].ID != bkID) {
506                 if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
507                     cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
508                 volp->vol[BACKVOL].ID = bkID;
509                 cm_AddVolumeToIDHashTable(volp, BACKVOL);
510             }
511         } else {
512             if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
513                 cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
514             volp->vol[BACKVOL].ID = 0;
515         }
516         lock_ReleaseWrite(&cm_volumeLock);
517         for (i=0; i<nServers; i++) {
518             /* create a server entry */
519             tflags = serverFlags[i];
520             if (tflags & VLSF_DONTUSE)
521                 continue;
522             tsockAddr.sin_port = htons(7000);
523             tsockAddr.sin_family = AF_INET;
524             tempAddr = htonl(serverNumber[i]);
525             tsockAddr.sin_addr.s_addr = tempAddr;
526             tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
527             if (tsp && (method == 2) && (tsp->flags & CM_SERVERFLAG_UUID)) {
528                 /*
529                  * Check to see if the uuid of the server we know at this address
530                  * matches the uuid of the server we are being told about by the
531                  * vlserver.  If not, ...?
532                  */
533                 if (!afs_uuid_equal(&serverUUID[i], &tsp->uuid)) {
534                     char uuid1[128], uuid2[128];
535                     char hoststr[16];
536
537                     afsUUID_to_string(&serverUUID[i], uuid1, sizeof(uuid1));
538                     afsUUID_to_string(&tsp->uuid, uuid2, sizeof(uuid2));
539                     afs_inet_ntoa_r(serverNumber[i], hoststr);
540
541                     osi_Log3(afsd_logp, "cm_UpdateVolumeLocation UUIDs do not match! %s != %s (%s)",
542                               osi_LogSaveString(afsd_logp, uuid1),
543                               osi_LogSaveString(afsd_logp, uuid2),
544                               osi_LogSaveString(afsd_logp, hoststr));
545                 }
546             }
547             if (!tsp) {
548                 /*
549                  * cm_NewServer will probe the file server which in turn will
550                  * update the state on the volume group object.  Do not probe
551                  * in this thread.  It will block the thread and can result in
552                  * a recursive call to cm_UpdateVolumeLocation().
553                  */
554                 lock_ReleaseWrite(&volp->rw);
555                 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, &serverUUID[i], CM_FLAG_NOPROBE);
556                 lock_ObtainWrite(&volp->rw);
557             }
558             osi_assertx(tsp != NULL, "null cm_server_t");
559
560             /*
561              * if this server was created by fs setserverprefs
562              * then it won't have either a cell assignment or
563              * a server uuid.
564              */
565             if ( !tsp->cellp )
566                 tsp->cellp = cellp;
567             if ( (method == 2) && !(tsp->flags & CM_SERVERFLAG_UUID) &&
568                  !afs_uuid_is_nil(&serverUUID[i])) {
569                 tsp->uuid = serverUUID[i];
570                 tsp->flags |= CM_SERVERFLAG_UUID;
571             }
572
573             /* and add it to the list(s). */
574             /*
575              * Each call to cm_NewServerRef() increments the
576              * ref count of tsp.  These reference will be dropped,
577              * if and when the volume is reset; see reset code
578              * earlier in this function.
579              */
580             if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
581                 tsrp = cm_NewServerRef(tsp, rwID);
582                 cm_InsertServerList(&volp->vol[RWVOL].serversp, tsrp);
583
584                 lock_ObtainWrite(&cm_serverLock);
585                 tsrp->refCount--;       /* drop allocation reference */
586                 lock_ReleaseWrite(&cm_serverLock);
587
588                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
589                     rwServers_alldown = 0;
590             }
591             if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS)) {
592                 tsrp = cm_NewServerRef(tsp, roID);
593                 cm_InsertServerList(&volp->vol[ROVOL].serversp, tsrp);
594                 lock_ObtainWrite(&cm_serverLock);
595                 tsrp->refCount--;       /* drop allocation reference */
596                 lock_ReleaseWrite(&cm_serverLock);
597                 ROcount++;
598
599                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
600                     roServers_alldown = 0;
601             }
602             /* We don't use VLSF_BACKVOL !?! */
603             /* Because only the backup on the server holding the RW
604              * volume can be valid.  This check prevents errors if a
605              * RW is moved but the old backup is not removed.
606              */
607             if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
608                 tsrp = cm_NewServerRef(tsp, bkID);
609                 cm_InsertServerList(&volp->vol[BACKVOL].serversp, tsrp);
610                 lock_ObtainWrite(&cm_serverLock);
611                 tsrp->refCount--;       /* drop allocation reference */
612                 lock_ReleaseWrite(&cm_serverLock);
613
614                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
615                     bkServers_alldown = 0;
616             }
617             /* Drop the reference obtained by cm_FindServer() */
618             cm_PutServer(tsp);
619         }
620
621         /*
622          * Randomize RO list
623          *
624          * If the first n servers have the same ipRank, then we
625          * randomly pick one among them and move it to the beginning.
626          * We don't bother to re-order the whole list because
627          * the rest of the list is used only if the first server is
628          * down.  We only do this for the RO list; we assume the other
629          * lists are length 1.
630          */
631         if (ROcount > 1) {
632             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
633         }
634
635         rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
636         roNewstate = roServers_alldown ? vl_alldown : vl_online;
637         bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
638
639         volp->flags &= ~CM_VOLUMEFLAG_NOEXIST;
640     } else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
641         volp->flags |= CM_VOLUMEFLAG_NOEXIST;
642     } else {
643         rwNewstate = roNewstate = bkNewstate = vl_alldown;
644     }
645
646     if (volp->vol[RWVOL].state != rwNewstate) {
647         if (volp->vol[RWVOL].ID)
648             cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, rwNewstate);
649         volp->vol[RWVOL].state = rwNewstate;
650     }
651     if (volp->vol[ROVOL].state != roNewstate) {
652         if (volp->vol[ROVOL].ID)
653             cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, roNewstate);
654         volp->vol[ROVOL].state = roNewstate;
655     }
656     if (volp->vol[BACKVOL].state != bkNewstate) {
657         if (volp->vol[BACKVOL].ID)
658             cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, bkNewstate);
659         volp->vol[BACKVOL].state = bkNewstate;
660     }
661
662     volp->lastUpdateTime = time(NULL);
663
664     if (code == 0)
665         volp->flags &= ~CM_VOLUMEFLAG_RESET;
666
667     volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
668     osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x",
669              osi_LogSaveString(afsd_logp,volp->cellp->name),
670              osi_LogSaveString(afsd_logp,volp->namep), volp->flags, code);
671     osi_Wakeup((LONG_PTR) &volp->flags);
672
673     return code;
674 }
675
676 /* Requires read or write lock on cm_volumeLock */
677 void cm_GetVolume(cm_volume_t *volp)
678 {
679     InterlockedIncrement(&volp->refCount);
680 }
681
682 cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
683 {
684     cm_volume_t *volp;
685     afs_uint32 hash;
686
687     lock_ObtainRead(&cm_volumeLock);
688     hash = CM_VOLUME_ID_HASH(fidp->volume);
689     /* The volumeID can be any one of the three types.  So we must
690      * search the hash table for all three types until we find it.
691      * We will search in the order of RO, RW, BK.
692      */
693     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
694         if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[ROVOL].ID )
695             break;
696     }
697     if (!volp) {
698         /* try RW volumes */
699         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
700             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[RWVOL].ID )
701                 break;
702         }
703     }
704     if (!volp) {
705         /* try BK volumes */
706         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
707             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[BACKVOL].ID )
708                 break;
709         }
710     }
711
712     /* hold the volume if we found it */
713     if (volp)
714         cm_GetVolume(volp);
715
716     lock_ReleaseRead(&cm_volumeLock);
717     return volp;
718 }
719
720 long cm_FindVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
721                       cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
722 {
723     cm_volume_t *volp;
724 #ifdef SEARCH_ALL_VOLUMES
725     cm_volume_t *volp2;
726 #endif
727     char volNameString[VL_MAXNAMELEN];
728     afs_uint32 hash;
729     long code = 0;
730
731     lock_ObtainRead(&cm_volumeLock);
732 #ifdef SEARCH_ALL_VOLUMES
733     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
734         if (cellp == volp->cellp &&
735              ((unsigned) volumeID == volp->vol[RWVOL].ID ||
736                (unsigned) volumeID == volp->vol[ROVOL].ID ||
737                (unsigned) volumeID == volp->vol[BACKVOL].ID))
738             break;
739     }
740
741     volp2 = volp;
742 #endif /* SEARCH_ALL_VOLUMES */
743
744     hash = CM_VOLUME_ID_HASH(volumeID);
745     /* The volumeID can be any one of the three types.  So we must
746      * search the hash table for all three types until we find it.
747      * We will search in the order of RO, RW, BK.
748      */
749     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
750         if ( cellp == volp->cellp && volumeID == volp->vol[ROVOL].ID )
751             break;
752     }
753     if (!volp) {
754         /* try RW volumes */
755         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
756             if ( cellp == volp->cellp && volumeID == volp->vol[RWVOL].ID )
757                 break;
758         }
759     }
760     if (!volp) {
761         /* try BK volumes */
762         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
763             if ( cellp == volp->cellp && volumeID == volp->vol[BACKVOL].ID )
764                 break;
765         }
766     }
767
768 #ifdef SEARCH_ALL_VOLUMES
769     osi_assertx(volp == volp2, "unexpected cm_vol_t");
770 #endif
771
772     /* hold the volume if we found it */
773     if (volp)
774         cm_GetVolume(volp);
775
776     lock_ReleaseRead(&cm_volumeLock);
777
778     /* return it held */
779     if (volp) {
780         lock_ObtainWrite(&volp->rw);
781
782         code = 0;
783         if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
784             code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
785         }
786         lock_ReleaseWrite(&volp->rw);
787         if (code == 0) {
788             *outVolpp = volp;
789
790             if (!(flags & CM_GETVOL_FLAG_NO_LRU_UPDATE)) {
791                 lock_ObtainWrite(&cm_volumeLock);
792                 cm_AdjustVolumeLRU(volp);
793                 lock_ReleaseWrite(&cm_volumeLock);
794             }
795         } else {
796             lock_ObtainRead(&cm_volumeLock);
797             cm_PutVolume(volp);
798             lock_ReleaseRead(&cm_volumeLock);
799         }
800         return code;
801     }
802
803     /* otherwise, we didn't find it so consult the VLDB */
804     sprintf(volNameString, "%u", volumeID);
805     code = cm_FindVolumeByName(cellp, volNameString, userp, reqp,
806                               flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL, outVolpp);
807
808     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
809         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
810         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
811
812         if (linkedCellp)
813             code = cm_FindVolumeByID(linkedCellp, volumeID, userp, reqp,
814                                      flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
815                                      outVolpp);
816     }
817     return code;
818 }
819
820
821 long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
822                         struct cm_user *userp, struct cm_req *reqp,
823                         afs_uint32 flags, cm_volume_t **outVolpp)
824 {
825     cm_volume_t *volp;
826 #ifdef SEARCH_ALL_VOLUMES
827     cm_volume_t *volp2;
828 #endif
829     long        code = 0;
830     char        name[VL_MAXNAMELEN];
831     size_t      len;
832     int         type;
833     afs_uint32  hash;
834
835     strncpy(name, volumeNamep, VL_MAXNAMELEN);
836     name[VL_MAXNAMELEN-1] = '\0';
837     len = strlen(name);
838
839     if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
840         type = BACKVOL;
841         name[len - 7] = '\0';
842     } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
843         type = ROVOL;
844         name[len - 9] = '\0';
845     } else {
846         type = RWVOL;
847     }
848
849     lock_ObtainRead(&cm_volumeLock);
850 #ifdef SEARCH_ALL_VOLUMES
851     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
852         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0) {
853             break;
854         }
855     }
856     volp2 = volp;
857 #endif /* SEARCH_ALL_VOLUMES */
858
859     hash = CM_VOLUME_NAME_HASH(name);
860     for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
861         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
862             break;
863     }
864
865 #ifdef SEARCH_ALL_VOLUMES
866     osi_assertx(volp2 == volp, "unexpected cm_vol_t");
867 #endif
868
869     if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
870         afs_uint32 volType;
871         /* otherwise, get from VLDB */
872
873         /*
874          * Change to a write lock so that we have exclusive use of
875          * the first cm_volume_t with a refCount of 0 so that we
876          * have time to increment it.
877          */
878         lock_ConvertRToW(&cm_volumeLock);
879
880         if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
881 #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
882             for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
883                 if ( volp->refCount == 0 ) {
884                     /* There is one we can re-use */
885                     break;
886                 }
887             }
888 #else
889             for ( volp = cm_data.volumeLRULastp;
890                   volp;
891                   volp = (cm_volume_t *) osi_QPrev(&volp->q))
892             {
893                 if ( volp->refCount == 0 ) {
894                     /* There is one we can re-use */
895                     break;
896                 }
897             }
898 #endif
899             if (!volp)
900                 osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
901
902             InterlockedIncrement(&volp->refCount);
903             lock_ReleaseWrite(&cm_volumeLock);
904             lock_ObtainWrite(&volp->rw);
905             lock_ObtainWrite(&cm_volumeLock);
906
907             osi_Log2(afsd_logp, "Recycling Volume %s:%s",
908                      volp->cellp->name, volp->namep);
909
910             /* The volp is removed from the LRU queue in order to
911              * prevent two threads from attempting to recycle the
912              * same object.  This volp must be re-inserted back into
913              * the LRU queue before this function exits.
914              */
915             if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
916                 cm_RemoveVolumeFromLRU(volp);
917             if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
918                 cm_RemoveVolumeFromNameHashTable(volp);
919
920             for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
921                 if (volp->vol[volType].qflags & CM_VOLUME_QFLAG_IN_HASH)
922                     cm_RemoveVolumeFromIDHashTable(volp, volType);
923                 if (volp->vol[volType].ID)
924                     cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_unknown);
925                 volp->vol[volType].ID = 0;
926                 cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
927                 lock_ReleaseWrite(&cm_volumeLock);
928                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
929                 lock_ObtainWrite(&cm_volumeLock);
930             }
931         } else {
932             volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
933             memset(volp, 0, sizeof(cm_volume_t));
934             volp->magic = CM_VOLUME_MAGIC;
935             volp->allNextp = cm_data.allVolumesp;
936             cm_data.allVolumesp = volp;
937             lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
938             lock_ReleaseWrite(&cm_volumeLock);
939             lock_ObtainWrite(&volp->rw);
940             lock_ObtainWrite(&cm_volumeLock);
941             volp->refCount = 1; /* starts off held */
942         }
943         volp->cellp = cellp;
944         strncpy(volp->namep, name, VL_MAXNAMELEN);
945         volp->namep[VL_MAXNAMELEN-1] = '\0';
946         volp->flags = CM_VOLUMEFLAG_RESET;
947
948         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
949             volp->vol[volType].state = vl_unknown;
950             volp->vol[volType].nextp = NULL;
951             volp->vol[volType].flags = 0;
952         }
953         volp->cbExpiresRO = 0;
954         volp->cbServerpRO = NULL;
955         volp->creationDateRO = 0;
956         cm_AddVolumeToNameHashTable(volp);
957         lock_ReleaseWrite(&cm_volumeLock);
958     }
959     else {
960         if (volp)
961             cm_GetVolume(volp);
962         lock_ReleaseRead(&cm_volumeLock);
963
964         if (!volp)
965             return CM_ERROR_NOSUCHVOLUME;
966
967         lock_ObtainWrite(&volp->rw);
968     }
969
970     /* if we get here we are holding the mutex */
971     if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
972         code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
973     }
974     lock_ReleaseWrite(&volp->rw);
975
976     if (code == 0 && (type == BACKVOL && volp->vol[BACKVOL].ID == 0 ||
977                       type == ROVOL && volp->vol[ROVOL].ID == 0))
978         code = CM_ERROR_NOSUCHVOLUME;
979
980     if (code == 0) {
981         *outVolpp = volp;
982
983         lock_ObtainWrite(&cm_volumeLock);
984         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
985              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
986             cm_AdjustVolumeLRU(volp);
987         lock_ReleaseWrite(&cm_volumeLock);
988     } else {
989         /*
990          * do not return it to the caller but do insert it in the LRU
991          * otherwise it will be lost
992          */
993         lock_ObtainWrite(&cm_volumeLock);
994         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
995              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
996             cm_AdjustVolumeLRU(volp);
997         cm_PutVolume(volp);
998         lock_ReleaseWrite(&cm_volumeLock);
999     }
1000
1001     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
1002         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
1003         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
1004
1005         if (linkedCellp)
1006             code = cm_FindVolumeByName(linkedCellp, volumeNamep, userp, reqp,
1007                                        flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
1008                                        outVolpp);
1009     }
1010     return code;
1011 }
1012
1013 /*
1014  * Only call this function in response to a VNOVOL or VMOVED error
1015  * from a file server.  Do not call it in response to CM_ERROR_NOSUCHVOLUME
1016  * as that can lead to recursive calls.
1017  */
1018 long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
1019 {
1020     cm_cell_t *cellp;
1021     cm_volume_t *volp;
1022 #ifdef SEARCH_ALL_VOLUMES
1023     cm_volume_t *volp2;
1024 #endif
1025     afs_uint32  hash;
1026     long code;
1027
1028     if (!fidp)
1029         return CM_ERROR_INVAL;
1030
1031     cellp = cm_FindCellByID(fidp->cell, 0);
1032     if (!cellp)
1033         return CM_ERROR_NOSUCHCELL;
1034
1035     /* search for the volume */
1036     lock_ObtainRead(&cm_volumeLock);
1037 #ifdef SEARCH_ALL_VOLUMES
1038     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1039         if (cellp == volp->cellp &&
1040              (fidp->volume == volp->vol[RWVOL].ID ||
1041                fidp->volume == volp->vol[ROVOL].ID ||
1042                fidp->volume == volp->vol[BACKVOL].ID))
1043             break;
1044     }
1045 #endif /* SEARCH_ALL_VOLUMES */
1046
1047     hash = CM_VOLUME_ID_HASH(fidp->volume);
1048     /* The volumeID can be any one of the three types.  So we must
1049      * search the hash table for all three types until we find it.
1050      * We will search in the order of RO, RW, BK.
1051      */
1052     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
1053         if ( cellp == volp->cellp && fidp->volume == volp->vol[ROVOL].ID )
1054             break;
1055     }
1056     if (!volp) {
1057         /* try RW volumes */
1058         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
1059             if ( cellp == volp->cellp && fidp->volume == volp->vol[RWVOL].ID )
1060                 break;
1061         }
1062     }
1063     if (!volp) {
1064         /* try BK volumes */
1065         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
1066             if ( cellp == volp->cellp && fidp->volume == volp->vol[BACKVOL].ID )
1067                 break;
1068         }
1069     }
1070
1071 #ifdef SEARCH_ALL_VOLUMES
1072     osi_assertx(volp == volp2, "unexpected cm_vol_t");
1073 #endif
1074     /* hold the volume if we found it */
1075     if (volp)
1076         cm_GetVolume(volp);
1077
1078     lock_ReleaseRead(&cm_volumeLock);
1079
1080     if (!volp)
1081         return CM_ERROR_NOSUCHVOLUME;
1082
1083     /* update it */
1084     cm_data.mountRootGen = time(NULL);
1085     lock_ObtainWrite(&volp->rw);
1086     volp->flags |= CM_VOLUMEFLAG_RESET;
1087
1088     code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1089     lock_ReleaseWrite(&volp->rw);
1090
1091     lock_ObtainRead(&cm_volumeLock);
1092     cm_PutVolume(volp);
1093     lock_ReleaseRead(&cm_volumeLock);
1094
1095     return code;
1096 }
1097
1098 /* find the appropriate servers from a volume */
1099 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume, cm_user_t *userp, cm_req_t *reqp)
1100 {
1101     cm_serverRef_t **serverspp;
1102     cm_serverRef_t *current;
1103     int firstTry = 1;
1104
1105   start:
1106     lock_ObtainWrite(&cm_serverLock);
1107
1108     if (volume == volp->vol[RWVOL].ID)
1109         serverspp = &volp->vol[RWVOL].serversp;
1110     else if (volume == volp->vol[ROVOL].ID)
1111         serverspp = &volp->vol[ROVOL].serversp;
1112     else if (volume == volp->vol[BACKVOL].ID)
1113         serverspp = &volp->vol[BACKVOL].serversp;
1114     else {
1115         lock_ReleaseWrite(&cm_serverLock);
1116         if (firstTry) {
1117             afs_int32 code;
1118             firstTry = 0;
1119             lock_ObtainWrite(&volp->rw);
1120             volp->flags |= CM_VOLUMEFLAG_RESET;
1121             code = cm_UpdateVolumeLocation(volp->cellp, userp, reqp, volp);
1122             lock_ReleaseWrite(&volp->rw);
1123             if (code == 0)
1124                 goto start;
1125         }
1126         return NULL;
1127     }
1128
1129     /*
1130      * Increment the refCount on deleted items as well.
1131      * They will be freed by cm_FreeServerList when they get to zero
1132      */
1133     for (current = *serverspp; current; current = current->next)
1134         current->refCount++;
1135
1136     lock_ReleaseWrite(&cm_serverLock);
1137
1138     return serverspp;
1139 }
1140
1141 void cm_PutVolume(cm_volume_t *volp)
1142 {
1143     afs_int32 refCount = InterlockedDecrement(&volp->refCount);
1144     osi_assertx(refCount >= 0, "cm_volume_t refCount underflow has occurred");
1145 }
1146
1147 /* return the read-only volume, if there is one, or the read-write volume if
1148  * not.
1149  */
1150 long cm_GetROVolumeID(cm_volume_t *volp)
1151 {
1152     long id;
1153
1154     lock_ObtainRead(&volp->rw);
1155     if (volp->vol[ROVOL].ID && volp->vol[ROVOL].serversp)
1156         id = volp->vol[ROVOL].ID;
1157     else
1158         id = volp->vol[RWVOL].ID;
1159     lock_ReleaseRead(&volp->rw);
1160
1161     return id;
1162 }
1163
1164 void cm_RefreshVolumes(int lifetime)
1165 {
1166     cm_volume_t *volp;
1167     afs_int32 refCount;
1168     time_t now;
1169
1170     now = time(NULL);
1171
1172     /* force mount point target updates */
1173     if (cm_data.mountRootGen + lifetime <= now)
1174         cm_data.mountRootGen = now;
1175
1176     /*
1177      * force a re-loading of volume data from the vldb
1178      * if the lifetime for the cached data has expired
1179      */
1180     lock_ObtainRead(&cm_volumeLock);
1181     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1182         InterlockedIncrement(&volp->refCount);
1183         lock_ReleaseRead(&cm_volumeLock);
1184
1185         if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
1186             lock_ObtainWrite(&volp->rw);
1187             if (volp->lastUpdateTime + lifetime <= now)
1188                 volp->flags |= CM_VOLUMEFLAG_RESET;
1189             lock_ReleaseWrite(&volp->rw);
1190         }
1191
1192         lock_ObtainRead(&cm_volumeLock);
1193         refCount = InterlockedDecrement(&volp->refCount);
1194         osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1195     }
1196     lock_ReleaseRead(&cm_volumeLock);
1197 }
1198
1199 void
1200 cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
1201                            afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
1202 {
1203     cm_conn_t *connp;
1204     long code;
1205     AFSFetchVolumeStatus volStat;
1206     char *Name;
1207     char *OfflineMsg;
1208     char *MOTD;
1209     cm_req_t req;
1210     struct rx_connection * rxconnp;
1211     char volName[32];
1212     char offLineMsg[256];
1213     char motd[256];
1214     long alldown, alldeleted;
1215     cm_serverRef_t *serversp;
1216     cm_fid_t fid;
1217
1218     Name = volName;
1219     OfflineMsg = offLineMsg;
1220     MOTD = motd;
1221
1222     if (statep->ID != 0 && (!volID || volID == statep->ID)) {
1223         /* create fid for volume root so that VNOVOL and VMOVED errors can be processed */
1224         cm_SetFid(&fid, volp->cellp->cellID, statep->ID, 1, 1);
1225
1226         if (!statep->serversp && !(*volumeUpdatedp)) {
1227             cm_InitReq(&req);
1228             code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1229             *volumeUpdatedp = 1;
1230         }
1231
1232         if (statep->serversp) {
1233             alldown = 1;
1234             alldeleted = 1;
1235             for (serversp = statep->serversp; serversp; serversp = serversp->next) {
1236                 if (serversp->status == srv_deleted)
1237                     continue;
1238
1239                 alldeleted = 0;
1240                 *onlinep = 1;
1241                 alldown = 0;
1242
1243                 if (serversp->status == srv_busy || serversp->status == srv_offline)
1244                     serversp->status = srv_not_busy;
1245             }
1246
1247             if (alldeleted && !(*volumeUpdatedp)) {
1248                 cm_InitReq(&req);
1249                 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1250                 *volumeUpdatedp = 1;
1251             }
1252
1253             if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
1254                 (!alldown && statep->state == vl_alldown)) {
1255                 cm_InitReq(&req);
1256                 req.flags |= CM_REQ_OFFLINE_VOL_CHK;
1257
1258                 lock_ReleaseWrite(&volp->rw);
1259                 do {
1260                     code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
1261                     if (code)
1262                         continue;
1263
1264                     rxconnp = cm_GetRxConn(connp);
1265                     code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
1266                                                  &volStat, &Name, &OfflineMsg, &MOTD);
1267                     rx_PutConnection(rxconnp);
1268                 } while (cm_Analyze(connp, cm_rootUserp, &req, &fid, NULL, NULL, NULL, code));
1269                 code = cm_MapRPCError(code, &req);
1270
1271                 lock_ObtainWrite(&volp->rw);
1272                 if (code == 0 && volStat.Online) {
1273                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
1274                     statep->state = vl_online;
1275                     *onlinep = 1;
1276                 } else if (code == CM_ERROR_NOACCESS) {
1277                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
1278                     statep->state = vl_unknown;
1279                     *onlinep = 1;
1280                 }
1281             } else if (alldown && statep->state != vl_alldown) {
1282                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1283                 statep->state = vl_alldown;
1284             }
1285         } else if (statep->state != vl_alldown) {
1286             cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1287             statep->state = vl_alldown;
1288         }
1289     }
1290 }
1291
1292 /* The return code is 0 if the volume is not online and
1293  * 1 if the volume is online
1294  */
1295 long
1296 cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
1297 {
1298     long code;
1299     cm_req_t req;
1300     afs_uint32 online = 0;
1301     afs_uint32 volumeUpdated = 0;
1302
1303     lock_ObtainWrite(&volp->rw);
1304
1305     if (volp->flags & CM_VOLUMEFLAG_RESET) {
1306         cm_InitReq(&req);
1307         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1308         volumeUpdated = 1;
1309     }
1310
1311     cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
1312     cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
1313     cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
1314
1315     lock_ReleaseWrite(&volp->rw);
1316     return online;
1317 }
1318
1319
1320 /*
1321  * called from the Daemon thread.
1322  * when checking the offline status, check those of the most recently used volumes first.
1323  */
1324 void cm_CheckOfflineVolumes(void)
1325 {
1326     cm_volume_t *volp;
1327     afs_int32 refCount;
1328     extern int daemon_ShutdownFlag;
1329     extern int powerStateSuspended;
1330
1331     lock_ObtainRead(&cm_volumeLock);
1332     for (volp = cm_data.volumeLRULastp;
1333          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1334          volp=(cm_volume_t *) osi_QPrev(&volp->q)) {
1335         /*
1336          * Skip volume entries that did not exist last time
1337          * the vldb was queried.  For those entries wait until
1338          * the next actual request is received for the volume
1339          * before checking its state.
1340          */
1341         if ((volp->qflags & CM_VOLUME_QFLAG_IN_HASH) &&
1342             !(volp->flags & CM_VOLUMEFLAG_NOEXIST)) {
1343             InterlockedIncrement(&volp->refCount);
1344             lock_ReleaseRead(&cm_volumeLock);
1345             cm_CheckOfflineVolume(volp, 0);
1346             lock_ObtainRead(&cm_volumeLock);
1347             refCount = InterlockedDecrement(&volp->refCount);
1348             osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1349         }
1350     }
1351     lock_ReleaseRead(&cm_volumeLock);
1352 }
1353
1354
1355 static void
1356 cm_UpdateVolumeStatusInt(cm_volume_t *volp, struct cm_vol_state *statep)
1357 {
1358     enum volstatus newStatus;
1359     cm_serverRef_t *tsrp;
1360     cm_server_t *tsp;
1361     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
1362     char addr[16];
1363
1364     if (!volp || !statep) {
1365 #ifdef DEBUG
1366         DebugBreak();
1367 #endif
1368         return;
1369     }
1370
1371     lock_ObtainWrite(&cm_serverLock);
1372     for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1373         tsp = tsrp->server;
1374         sprintf(addr, "%d.%d.%d.%d",
1375                  ((tsp->addr.sin_addr.s_addr & 0xff)),
1376                  ((tsp->addr.sin_addr.s_addr & 0xff00)>> 8),
1377                  ((tsp->addr.sin_addr.s_addr & 0xff0000)>> 16),
1378                  ((tsp->addr.sin_addr.s_addr & 0xff000000)>> 24));
1379
1380         if (tsrp->status == srv_deleted) {
1381             osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s deleted",
1382                      statep->ID, osi_LogSaveString(afsd_logp,addr));
1383             continue;
1384         }
1385         if (tsp) {
1386             cm_GetServerNoLock(tsp);
1387             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
1388                 allDown = 0;
1389                 if (tsrp->status == srv_busy) {
1390                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s busy",
1391                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1392                     allOffline = 0;
1393                     someBusy = 1;
1394                 } else if (tsrp->status == srv_offline) {
1395                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s offline",
1396                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1397                     allBusy = 0;
1398                     someOffline = 1;
1399                 } else {
1400                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s online",
1401                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1402                     allOffline = 0;
1403                     allBusy = 0;
1404                 }
1405             } else {
1406                 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s down",
1407                           statep->ID, osi_LogSaveString(afsd_logp,addr));
1408             }
1409             cm_PutServerNoLock(tsp);
1410         }
1411     }
1412     lock_ReleaseWrite(&cm_serverLock);
1413
1414     osi_Log5(afsd_logp, "cm_UpdateVolumeStatusInt allDown %d allBusy %d someBusy %d someOffline %d allOffline %d",
1415              allDown, allBusy, someBusy, someOffline, allOffline);
1416
1417     if (allDown)
1418         newStatus = vl_alldown;
1419     else if (allBusy || (someBusy && someOffline))
1420         newStatus = vl_busy;
1421     else if (allOffline)
1422         newStatus = vl_offline;
1423     else
1424         newStatus = vl_online;
1425
1426     if (statep->ID && statep->state != newStatus)
1427         cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
1428
1429     statep->state = newStatus;
1430 }
1431
1432 void
1433 cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1434 {
1435
1436     if (volp->vol[RWVOL].ID == volID) {
1437         cm_UpdateVolumeStatusInt(volp, &volp->vol[RWVOL]);
1438     } else if (volp->vol[ROVOL].ID == volID) {
1439         cm_UpdateVolumeStatusInt(volp, &volp->vol[ROVOL]);
1440     } else if (volp->vol[BACKVOL].ID == volID) {
1441         cm_UpdateVolumeStatusInt(volp, &volp->vol[BACKVOL]);
1442     } else {
1443         /*
1444          * If we are called with volID == 0 then something has gone wrong.
1445          * Most likely a race occurred in the server volume list maintenance.
1446          * Since we don't know which volume's status should be updated,
1447          * just update all of them that are known to exist.  Better to be
1448          * correct than fast.
1449          */
1450         afs_uint32 volType;
1451         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1452             if (volp->vol[volType].ID != 0)
1453                 cm_UpdateVolumeStatusInt(volp, &volp->vol[volType]);
1454         }
1455     }
1456 }
1457
1458 /*
1459 ** Finds all volumes that reside on this server and reorders their
1460 ** RO list according to the changed rank of server.
1461 */
1462 void cm_ChangeRankVolume(cm_server_t *tsp)
1463 {
1464     int                 code;
1465     cm_volume_t*        volp;
1466     afs_int32 refCount;
1467
1468     /* find volumes which might have RO copy on server*/
1469     lock_ObtainRead(&cm_volumeLock);
1470     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1471     {
1472         code = 1 ;      /* assume that list is unchanged */
1473         InterlockedIncrement(&volp->refCount);
1474         lock_ReleaseRead(&cm_volumeLock);
1475         lock_ObtainWrite(&volp->rw);
1476
1477         if ((tsp->cellp==volp->cellp) && (volp->vol[ROVOL].serversp))
1478             code =cm_ChangeRankServer(&volp->vol[ROVOL].serversp, tsp);
1479
1480         /* this volume list was changed */
1481         if ( !code )
1482             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
1483
1484         lock_ReleaseWrite(&volp->rw);
1485         lock_ObtainRead(&cm_volumeLock);
1486         refCount = InterlockedDecrement(&volp->refCount);
1487         osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1488     }
1489     lock_ReleaseRead(&cm_volumeLock);
1490 }
1491
1492 /* dump all volumes that have reference count > 0 to a file.
1493  * cookie is used to identify this batch for easy parsing,
1494  * and it a string provided by a caller
1495  */
1496 int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
1497 {
1498     int zilch;
1499     cm_volume_t *volp;
1500     char output[1024];
1501
1502     if (lock) {
1503         lock_ObtainRead(&cm_scacheLock);
1504         lock_ObtainRead(&cm_volumeLock);
1505     }
1506
1507     sprintf(output, "%s - dumping volumes - cm_data.currentVolumes=%d, cm_data.maxVolumes=%d\r\n",
1508             cookie, cm_data.currentVolumes, cm_data.maxVolumes);
1509     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1510
1511     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1512     {
1513         time_t t;
1514         char *srvStr = NULL;
1515         afs_uint32 srvStrRpc = TRUE;
1516         char *cbt = NULL;
1517         char *cdrot = NULL;
1518
1519         if (volp->cbServerpRO) {
1520             if (!((volp->cbServerpRO->flags & CM_SERVERFLAG_UUID) &&
1521                 UuidToString((UUID *)&volp->cbServerpRO->uuid, &srvStr) == RPC_S_OK)) {
1522                 srvStr = malloc(16);
1523                 if (srvStr != NULL)
1524                     afs_inet_ntoa_r(volp->cbServerpRO->addr.sin_addr.s_addr, srvStr);
1525                 srvStrRpc = FALSE;
1526             }
1527         }
1528         if (volp->cbExpiresRO) {
1529             t = volp->cbExpiresRO;
1530             cbt = ctime(&t);
1531             if (cbt) {
1532                 cbt = strdup(cbt);
1533                 cbt[strlen(cbt)-1] = '\0';
1534             }
1535         }
1536         if (volp->creationDateRO) {
1537             t = volp->creationDateRO;
1538             cdrot = ctime(&t);
1539             if (cdrot) {
1540                 cdrot = strdup(cdrot);
1541                 cdrot[strlen(cdrot)-1] = '\0';
1542             }
1543         }
1544
1545         sprintf(output,
1546                 "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x:%x "
1547                 "cbServerpRO='%s' cbExpiresRO='%s' creationDateRO='%s' refCount=%u\r\n",
1548                  cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID,
1549                  volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags, volp->qflags,
1550                  srvStr ? srvStr : "<none>", cbt ? cbt : "<none>", cdrot ? cdrot : "<none>",
1551                  volp->refCount);
1552         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1553
1554         if (srvStr) {
1555             if (srvStrRpc)
1556                 RpcStringFree(&srvStr);
1557             else
1558                 free(srvStr);
1559         }
1560         if (cbt)
1561             free(cbt);
1562         if (cdrot)
1563             free(cdrot);
1564     }
1565     sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
1566     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1567
1568     if (lock) {
1569         lock_ReleaseRead(&cm_volumeLock);
1570         lock_ReleaseRead(&cm_scacheLock);
1571     }
1572     return (0);
1573 }
1574
1575
1576 /*
1577  * String hash function used by SDBM project.
1578  * It was chosen because it is fast and provides
1579  * decent coverage.
1580  */
1581 afs_uint32 SDBMHash(const char * str)
1582 {
1583     afs_uint32 hash = 0;
1584     size_t i, len;
1585
1586     if (str == NULL)
1587         return 0;
1588
1589     for(i = 0, len = strlen(str); i < len; i++)
1590     {
1591         hash = str[i] + (hash << 6) + (hash << 16) - hash;
1592     }
1593
1594     return (hash & 0x7FFFFFFF);
1595 }
1596
1597 /* call with volume write-locked and mutex held */
1598 void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
1599 {
1600     int i;
1601
1602     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
1603         return;
1604
1605     i = CM_VOLUME_NAME_HASH(volp->namep);
1606
1607     volp->nameNextp = cm_data.volumeNameHashTablep[i];
1608     cm_data.volumeNameHashTablep[i] = volp;
1609     volp->qflags |= CM_VOLUME_QFLAG_IN_HASH;
1610 }
1611
1612 /* call with volume write-locked and mutex held */
1613 void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
1614 {
1615     cm_volume_t **lvolpp;
1616     cm_volume_t *tvolp;
1617     int i;
1618
1619     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1620         /* hash it out first */
1621         i = CM_VOLUME_NAME_HASH(volp->namep);
1622         for (lvolpp = &cm_data.volumeNameHashTablep[i], tvolp = cm_data.volumeNameHashTablep[i];
1623              tvolp;
1624              lvolpp = &tvolp->nameNextp, tvolp = tvolp->nameNextp) {
1625             if (tvolp == volp) {
1626                 *lvolpp = volp->nameNextp;
1627                 volp->qflags &= ~CM_VOLUME_QFLAG_IN_HASH;
1628                 volp->nameNextp = NULL;
1629                 break;
1630             }
1631         }
1632     }
1633 }
1634
1635 /* call with volume write-locked and mutex held */
1636 void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1637 {
1638     int i;
1639     struct cm_vol_state * statep;
1640
1641     statep = cm_VolumeStateByType(volp, volType);
1642
1643     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH)
1644         return;
1645
1646     i = CM_VOLUME_ID_HASH(statep->ID);
1647
1648     switch (volType) {
1649     case RWVOL:
1650         statep->nextp = cm_data.volumeRWIDHashTablep[i];
1651         cm_data.volumeRWIDHashTablep[i] = volp;
1652         break;
1653     case ROVOL:
1654         statep->nextp = cm_data.volumeROIDHashTablep[i];
1655         cm_data.volumeROIDHashTablep[i] = volp;
1656         break;
1657     case BACKVOL:
1658         statep->nextp = cm_data.volumeBKIDHashTablep[i];
1659         cm_data.volumeBKIDHashTablep[i] = volp;
1660         break;
1661     }
1662     statep->qflags |= CM_VOLUME_QFLAG_IN_HASH;
1663 }
1664
1665
1666 /* call with volume write-locked and mutex held */
1667 void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1668 {
1669     cm_volume_t **lvolpp;
1670     cm_volume_t *tvolp;
1671     struct cm_vol_state * statep;
1672     int i;
1673
1674     statep = cm_VolumeStateByType(volp, volType);
1675
1676     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1677         /* hash it out first */
1678         i = CM_VOLUME_ID_HASH(statep->ID);
1679
1680         switch (volType) {
1681         case RWVOL:
1682             lvolpp = &cm_data.volumeRWIDHashTablep[i];
1683             tvolp = cm_data.volumeRWIDHashTablep[i];
1684             break;
1685         case ROVOL:
1686             lvolpp = &cm_data.volumeROIDHashTablep[i];
1687             tvolp = cm_data.volumeROIDHashTablep[i];
1688             break;
1689         case BACKVOL:
1690             lvolpp = &cm_data.volumeBKIDHashTablep[i];
1691             tvolp = cm_data.volumeBKIDHashTablep[i];
1692             break;
1693         default:
1694             osi_assertx(0, "invalid volume type");
1695         }
1696         do {
1697             if (tvolp == volp) {
1698                 *lvolpp = statep->nextp;
1699                 statep->qflags &= ~CM_VOLUME_QFLAG_IN_HASH;
1700                 statep->nextp = NULL;
1701                 break;
1702             }
1703
1704             lvolpp = &tvolp->vol[volType].nextp;
1705             tvolp = tvolp->vol[volType].nextp;
1706         } while(tvolp);
1707     }
1708 }
1709
1710 /* must be called with cm_volumeLock write-locked! */
1711 void cm_AdjustVolumeLRU(cm_volume_t *volp)
1712 {
1713     lock_AssertWrite(&cm_volumeLock);
1714
1715     if (volp == cm_data.volumeLRUFirstp)
1716         return;
1717
1718     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1719         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1720     osi_QAddH((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1721     volp->qflags |= CM_VOLUME_QFLAG_IN_LRU_QUEUE;
1722
1723     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1724 }
1725
1726 /* must be called with cm_volumeLock write-locked! */
1727 void cm_MoveVolumeToLRULast(cm_volume_t *volp)
1728 {
1729     lock_AssertWrite(&cm_volumeLock);
1730
1731     if (volp == cm_data.volumeLRULastp)
1732         return;
1733
1734     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1735         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1736     osi_QAddT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1737     volp->qflags |= CM_VOLUME_QFLAG_IN_LRU_QUEUE;
1738
1739     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1740 }
1741
1742 /* must be called with cm_volumeLock write-locked! */
1743 void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
1744 {
1745     lock_AssertWrite(&cm_volumeLock);
1746
1747     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) {
1748         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1749         volp->qflags &= ~CM_VOLUME_QFLAG_IN_LRU_QUEUE;
1750     }
1751
1752     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1753 }
1754
1755 static char * volstatus_str(enum volstatus vs)
1756 {
1757     switch (vs) {
1758     case vl_online:
1759         return "online";
1760     case vl_busy:
1761         return "busy";
1762     case vl_offline:
1763         return "offline";
1764     case vl_alldown:
1765         return "alldown";
1766     default:
1767         return "unknown";
1768     }
1769 }
1770
1771 void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
1772 {
1773     char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN]="";
1774     char *ext = "";
1775
1776     if (volID == volp->vol[RWVOL].ID)
1777         ext = "";
1778     else if (volID == volp->vol[ROVOL].ID)
1779         ext = ".readonly";
1780     else if (volID == volp->vol[BACKVOL].ID)
1781         ext = ".backup";
1782     else
1783         ext = ".nomatch";
1784     snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
1785
1786     osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
1787              osi_LogSaveString(afsd_logp, volstr), volID, volstatus_str(old), volstatus_str(new));
1788
1789     cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new);
1790 }
1791
1792 enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1793 {
1794     cm_vol_state_t * statep = cm_VolumeStateByID(volp, volID);
1795     if (statep)
1796         return statep->state;
1797     else
1798         return vl_unknown;
1799 }
1800
1801 /* Renew .readonly volume callbacks that are more than
1802  * 30 minutes old.  (A volume callback is issued for 2 hours.)
1803  */
1804 void
1805 cm_VolumeRenewROCallbacks(void)
1806 {
1807     cm_volume_t * volp;
1808     time_t minexp = time(NULL) + 90 * 60;
1809     extern int daemon_ShutdownFlag;
1810     extern int powerStateSuspended;
1811
1812     lock_ObtainRead(&cm_volumeLock);
1813     for (volp = cm_data.allVolumesp;
1814          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1815          volp=volp->allNextp) {
1816         if ( volp->cbExpiresRO > 0 && volp->cbExpiresRO < minexp) {
1817             cm_req_t      req;
1818             cm_fid_t      fid;
1819             cm_scache_t * scp;
1820
1821             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
1822
1823             cm_InitReq(&req);
1824
1825             lock_ReleaseRead(&cm_volumeLock);
1826             if (cm_GetSCache(&fid, &scp, cm_rootUserp, &req) == 0) {
1827                 lock_ObtainWrite(&scp->rw);
1828                 cm_GetCallback(scp, cm_rootUserp, &req, 1);
1829                 lock_ReleaseWrite(&scp->rw);
1830                 cm_ReleaseSCache(scp);
1831             }
1832             lock_ObtainRead(&cm_volumeLock);
1833         }
1834     }
1835     lock_ReleaseRead(&cm_volumeLock);
1836 }
1837
1838 cm_vol_state_t *
1839 cm_VolumeStateByType(cm_volume_t *volp, afs_uint32 volType)
1840 {
1841     return &volp->vol[volType];
1842 }
1843
1844 cm_vol_state_t *
1845 cm_VolumeStateByID(cm_volume_t *volp, afs_uint32 id)
1846 {
1847     cm_vol_state_t * statep = NULL;
1848
1849     if (id == volp->vol[RWVOL].ID)
1850         statep = &volp->vol[RWVOL];
1851     else if (id == volp->vol[ROVOL].ID)
1852         statep = &volp->vol[ROVOL];
1853     else if (id == volp->vol[BACKVOL].ID)
1854         statep = &volp->vol[BACKVOL];
1855
1856     return(statep);
1857 }
1858
1859 cm_vol_state_t *
1860 cm_VolumeStateByName(cm_volume_t *volp, char *volname)
1861 {
1862     size_t len = strlen(volname);
1863     cm_vol_state_t *statep;
1864
1865     if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
1866         statep = &volp->vol[ROVOL];
1867     else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
1868         statep = &volp->vol[BACKVOL];
1869     else
1870         statep = &volp->vol[RWVOL];
1871
1872     return statep;
1873 }
1874
1875 afs_int32
1876 cm_VolumeType(cm_volume_t *volp, afs_uint32 id)
1877 {
1878     if (id == volp->vol[RWVOL].ID)
1879         return(RWVOL);
1880     else if (id == volp->vol[ROVOL].ID)
1881         return(ROVOL);
1882     else if (id == volp->vol[BACKVOL].ID)
1883         return (BACKVOL);
1884
1885     return -1;
1886 }