Windows: force vldb lookup if server list is empty
[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 <strsafe.h>
21 #include <malloc.h>
22 #include "afsd.h"
23 #include <osi.h>
24 #include <rx/rx.h>
25
26 osi_rwlock_t cm_volumeLock;
27
28 long
29 cm_ValidateVolume(void)
30 {
31     cm_volume_t * volp;
32     afs_uint32 count;
33
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");
38             return -1;
39         }
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");
43             return -2;
44         }
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");
48             return -3;
49         }
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");
54             return -4;
55         }
56     }
57
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");
61         return -5;
62     }
63
64     return 0;
65 }
66
67 long
68 cm_ShutdownVolume(void)
69 {
70     cm_volume_t * volp;
71
72     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
73         afs_uint32 volType;
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);
77         }
78         volp->cbExpiresRO = 0;
79         volp->cbIssuedRO = 0;
80         volp->cbServerpRO = NULL;
81         lock_FinalizeRWLock(&volp->rw);
82     }
83
84     return 0;
85 }
86
87 void cm_InitVolume(int newFile, long maxVols)
88 {
89     static osi_once_t once;
90
91     if (osi_Once(&once)) {
92         lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock", LOCK_HIERARCHY_VOLUME_GLOBAL);
93
94         if ( newFile ) {
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;
103         } else {
104             cm_volume_t * volp;
105
106             for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
107                 afs_uint32 volType;
108
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);
118                 }
119                 volp->cbExpiresRO = 0;
120                 volp->cbIssuedRO = 0;
121                 volp->cbServerpRO = NULL;
122             }
123         }
124         osi_EndOnce(&once);
125     }
126 }
127
128
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 */
132 int
133 cm_VolNameIsID(char *aname)
134 {
135     int tc;
136     while (tc = *aname++) {
137         if (tc > '9' || tc < '0')
138             return 0;
139     }
140     return 1;
141 }
142
143
144 /*
145  * Update a volume.  Caller holds a write lock on the volume (volp->rw).
146  *
147  *
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)
161  *    Oh.  Ew.
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
168  *    RXGEN_OPCODE.
169  */
170 static long
171 cm_GetEntryByName( struct cm_cell *cellp, const char *name,
172                    struct vldbentry *vldbEntryp,
173                    struct nvldbentry *nvldbEntryp,
174                    struct uvldbentry *uvldbEntryp,
175                    int *methodp,
176                    cm_user_t *userp,
177                    cm_req_t *reqp
178                    )
179 {
180     long code;
181     cm_conn_t *connp;
182     struct rx_connection * rxconnp;
183
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));
187     do {
188
189         code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
190         if (code)
191             continue;
192
193         rxconnp = cm_GetRxConn(connp);
194         code = VL_GetEntryByNameU(rxconnp, name, uvldbEntryp);
195         *methodp = 2;
196         if ( code == RXGEN_OPCODE )
197         {
198             code = VL_GetEntryByNameN(rxconnp, name, nvldbEntryp);
199             *methodp = 1;
200         }
201         if ( code == RXGEN_OPCODE ) {
202             code = VL_GetEntryByNameO(rxconnp, name, vldbEntryp);
203             *methodp = 0;
204         }
205         rx_PutConnection(rxconnp);
206     } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, cellp->vlServersp, NULL, code));
207     code = cm_MapVLRPCError(code, reqp);
208     if ( code )
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);
212     else
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));
216     return code;
217 }
218
219 static long
220 cm_GetEntryByID( struct cm_cell *cellp, afs_uint32 id,
221                  struct vldbentry *vldbEntryp,
222                  struct nvldbentry *nvldbEntryp,
223                  struct uvldbentry *uvldbEntryp,
224                  int *methodp,
225                  cm_user_t *userp,
226                  cm_req_t *reqp
227                  )
228 {
229     char name[64];
230
231     StringCbPrintf(name, sizeof(name), "%u", id);
232
233     return cm_GetEntryByName(cellp, name, vldbEntryp, nvldbEntryp, uvldbEntryp, methodp, userp, reqp);
234 }
235
236 long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
237                      cm_volume_t *volp)
238 {
239     struct rx_connection *rxconnp;
240     cm_conn_t *connp;
241     int i;
242     afs_uint32 j, k;
243     cm_serverRef_t *tsrp;
244     cm_server_t *tsp;
245     struct sockaddr_in tsockAddr;
246     long tflags;
247     u_long tempAddr;
248     struct vldbentry vldbEntry;
249     struct nvldbentry nvldbEntry;
250     struct uvldbentry uvldbEntry;
251     int method = -1;
252     int ROcount = 0;
253     int isMixed = 0;
254     long code;
255     enum volstatus rwNewstate = vl_online;
256     enum volstatus roNewstate = vl_online;
257     enum volstatus bkNewstate = vl_online;
258 #ifdef AFS_FREELANCE_CLIENT
259     int freelance = 0;
260 #endif
261     afs_uint32 volType;
262     time_t now;
263     int replicated = 0;
264
265     lock_AssertWrite(&volp->rw);
266
267     /*
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.
271      */
272     now = time(NULL);
273     if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
274         (now < volp->lastUpdateTime + 600))
275     {
276         return CM_ERROR_NOSUCHVOLUME;
277     }
278
279 #ifdef AFS_FREELANCE_CLIENT
280     if (cellp->cellID == AFS_FAKE_ROOT_CELL_ID)
281     {
282         freelance = 1;
283         memset(&vldbEntry, 0, sizeof(vldbEntry));
284         vldbEntry.flags |= VLF_RWEXISTS;
285         vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
286         code = 0;
287         method = 0;
288     } else
289 #endif
290     {
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);
302                 return 0;
303             }
304             now = time(NULL);
305         }
306
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))
309         {
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);
313         }
314
315         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_UPDATING_VL);
316         lock_ReleaseWrite(&volp->rw);
317
318         if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
319              cm_UpdateCell(cellp, 0);
320
321         /* now we have volume structure locked and held; make RPC to fill it */
322         code = cm_GetEntryByName(cellp, volp->namep, &vldbEntry, &nvldbEntry,
323                                  &uvldbEntry,
324                                  &method, userp, reqp);
325     }
326
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.
331      */
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];
337
338         snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
339
340         /* now we have volume structure locked and held; make RPC to fill it */
341         code = cm_GetEntryByName(cellp, name, &vldbEntry, &nvldbEntry,
342                                  &uvldbEntry,
343                                  &method, userp, reqp);
344     }
345
346     /*
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.
350      */
351     if (code == CM_ERROR_NOSUCHVOLUME) {
352         if (volp->vol[RWVOL].ID != 0) {
353             code = cm_GetEntryByID(cellp, volp->vol[RWVOL].ID, &vldbEntry, &nvldbEntry,
354                                     &uvldbEntry,
355                                     &method, userp, reqp);
356         } else if (volp->vol[ROVOL].ID != 0) {
357             code = cm_GetEntryByID(cellp, volp->vol[ROVOL].ID, &vldbEntry, &nvldbEntry,
358                                     &uvldbEntry,
359                                     &method, userp, reqp);
360         }
361     }
362
363     lock_ObtainWrite(&volp->rw);
364     if (code == 0) {
365         afs_int32 flags;
366         afs_int32 nServers;
367         afs_int32 rwID;
368         afs_int32 roID;
369         afs_int32 bkID;
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];
377
378 #ifdef AFS_FREELANCE_CLIENT
379         if (freelance)
380             rwServers_alldown = 0;
381 #endif
382
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);
387         }
388
389         memset(serverUUID, 0, sizeof(serverUUID));
390
391         switch ( method ) {
392         case 0:
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];
402             }
403             strncpy(name, vldbEntry.name, VL_MAXNAMELEN);
404             name[VL_MAXNAMELEN - 1] = '\0';
405             break;
406         case 1:
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];
416             }
417             strncpy(name, nvldbEntry.name, VL_MAXNAMELEN);
418             name[VL_MAXNAMELEN - 1] = '\0';
419             break;
420         case 2:
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;
431                     j++;
432                 } else {
433                     afs_uint32 * addrp, nentries, code, unique;
434                     bulkaddrs  addrs;
435                     ListAddrByAttributes attrs;
436                     afsUUID uuid;
437
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));
443
444                     do {
445                         code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
446                         if (code)
447                             continue;
448
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, cellp, 0, NULL, cellp->vlServersp, NULL, code));
453
454                     if ( code ) {
455                         code = cm_MapVLRPCError(code, reqp);
456                         osi_Log2(afsd_logp, "CALL VL_GetAddrsU serverNumber %u FAILURE, code 0x%x",
457                                  i, code);
458                         continue;
459                     }
460                     osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %u SUCCESS", i);
461
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;
467                     }
468
469                     xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
470
471                     if (nentries == 0)
472                         code = CM_ERROR_INVAL;
473                 }
474             }
475             nServers = j;                                       /* update the server count */
476             strncpy(name, uvldbEntry.name, VL_MAXNAMELEN);
477             name[VL_MAXNAMELEN - 1] = '\0';
478             break;
479         }
480
481         /* decode the response */
482         lock_ObtainWrite(&cm_volumeLock);
483         if (!cm_VolNameIsID(volp->namep)) {
484             size_t    len;
485
486             len = strlen(name);
487
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';
492             }
493
494             osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s",
495                      osi_LogSaveString(afsd_logp,volp->namep), osi_LogSaveString(afsd_logp,name));
496
497             if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
498                 cm_RemoveVolumeFromNameHashTable(volp);
499
500             strcpy(volp->namep, name);
501
502             cm_AddVolumeToNameHashTable(volp);
503         }
504
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));
509         }
510
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);
517             }
518         } else {
519             if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
520                 cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
521             volp->vol[RWVOL].ID = 0;
522         }
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);
529             }
530             if (replicated)
531                 _InterlockedOr(&volp->vol[ROVOL].flags, CM_VOL_STATE_FLAG_REPLICATED);
532             else
533                 _InterlockedAnd(&volp->vol[ROVOL].flags, ~CM_VOL_STATE_FLAG_REPLICATED);
534         } else {
535             if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
536                 cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
537             volp->vol[ROVOL].ID = 0;
538         }
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);
545             }
546         } else {
547             if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
548                 cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
549             volp->vol[BACKVOL].ID = 0;
550         }
551         lock_ReleaseWrite(&cm_volumeLock);
552
553         /* See if the replica sites are mixed versions */
554         for (i=0; i<nServers; i++) {
555             if (serverFlags[i] & VLSF_NEWREPSITE) {
556                 isMixed = 1;
557                 break;
558             }
559         }
560
561         for (i=0; i<nServers; i++) {
562             /* create a server entry */
563             tflags = serverFlags[i];
564             if (tflags & VLSF_DONTUSE)
565                 continue;
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)) {
572                 /*
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, ...?
576                  */
577                 if (!afs_uuid_equal(&serverUUID[i], &tsp->uuid)) {
578                     char uuid1[128], uuid2[128];
579                     char hoststr[16];
580
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);
584
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));
589                 }
590             }
591             if (!tsp) {
592                 /*
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().
597                  */
598                 lock_ReleaseWrite(&volp->rw);
599                 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, &serverUUID[i], CM_FLAG_NOPROBE);
600                 lock_ObtainWrite(&volp->rw);
601             }
602             osi_assertx(tsp != NULL, "null cm_server_t");
603
604             /*
605              * if this server was created by fs setserverprefs
606              * then it won't have either a cell assignment or
607              * a server uuid.
608              */
609             if ( !tsp->cellp )
610                 tsp->cellp = cellp;
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);
615             }
616
617             /* and add it to the list(s). */
618             /*
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.
623              */
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;
629             }
630             /*
631              * If there are mixed versions of RO releases on the replica
632              * sites, skip the servers with the out of date versions.
633              */
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);
638                 ROcount++;
639
640                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
641                     roServers_alldown = 0;
642             }
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.
647              */
648             if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
649                 tsrp = cm_NewServerRef(tsp, bkID);
650                 cm_InsertServerList(&volp->vol[BACKVOL].serversp, tsrp);
651
652                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
653                     bkServers_alldown = 0;
654             }
655             /* Drop the reference obtained by cm_FindServer() */
656             cm_PutServer(tsp);
657         }
658
659         /*
660          * Randomize RO list
661          *
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.
668          */
669         if (ROcount > 1) {
670             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
671         }
672
673         rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
674         roNewstate = roServers_alldown ? vl_alldown : vl_online;
675         bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
676
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);
680     } else {
681         rwNewstate = roNewstate = bkNewstate = vl_alldown;
682     }
683
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;
688     }
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;
693     }
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;
698     }
699
700     volp->lastUpdateTime = time(NULL);
701     if (isMixed)
702         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_MIXED);
703     else
704         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_MIXED);
705
706     if (code == 0)
707         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RESET);
708
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);
714
715     return code;
716 }
717
718 /* Requires read or write lock on cm_volumeLock */
719 void cm_GetVolume(cm_volume_t *volp)
720 {
721     InterlockedIncrement(&volp->refCount);
722 }
723
724 cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
725 {
726     cm_volume_t *volp;
727     afs_uint32 hash;
728
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.
734      */
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 )
737             break;
738     }
739     if (!volp) {
740         /* try RW volumes */
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 )
743                 break;
744         }
745     }
746     if (!volp) {
747         /* try BK volumes */
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 )
750                 break;
751         }
752     }
753
754     /* hold the volume if we found it */
755     if (volp)
756         cm_GetVolume(volp);
757
758     lock_ReleaseRead(&cm_volumeLock);
759     return volp;
760 }
761
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)
764 {
765     cm_volume_t *volp;
766 #ifdef SEARCH_ALL_VOLUMES
767     cm_volume_t *volp2;
768 #endif
769     char volNameString[VL_MAXNAMELEN];
770     afs_uint32 hash;
771     long code = 0;
772
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))
780             break;
781     }
782
783     volp2 = volp;
784 #endif /* SEARCH_ALL_VOLUMES */
785
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.
790      */
791     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
792         if ( cellp == volp->cellp && volumeID == volp->vol[ROVOL].ID )
793             break;
794     }
795     if (!volp) {
796         /* try RW volumes */
797         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
798             if ( cellp == volp->cellp && volumeID == volp->vol[RWVOL].ID )
799                 break;
800         }
801     }
802     if (!volp) {
803         /* try BK volumes */
804         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
805             if ( cellp == volp->cellp && volumeID == volp->vol[BACKVOL].ID )
806                 break;
807         }
808     }
809
810 #ifdef SEARCH_ALL_VOLUMES
811     osi_assertx(volp == volp2, "unexpected cm_vol_t");
812 #endif
813
814     /* hold the volume if we found it */
815     if (volp)
816         cm_GetVolume(volp);
817
818     lock_ReleaseRead(&cm_volumeLock);
819
820     /* return it held */
821     if (volp) {
822         lock_ObtainWrite(&volp->rw);
823
824         code = 0;
825         if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
826             code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
827         }
828         lock_ReleaseWrite(&volp->rw);
829         if (code == 0) {
830             *outVolpp = volp;
831
832             if (!(flags & CM_GETVOL_FLAG_NO_LRU_UPDATE)) {
833                 lock_ObtainWrite(&cm_volumeLock);
834                 cm_AdjustVolumeLRU(volp);
835                 lock_ReleaseWrite(&cm_volumeLock);
836             }
837         } else {
838             lock_ObtainRead(&cm_volumeLock);
839             cm_PutVolume(volp);
840             lock_ReleaseRead(&cm_volumeLock);
841         }
842         return code;
843     }
844
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);
849
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);
853
854         if (linkedCellp)
855             code = cm_FindVolumeByID(linkedCellp, volumeID, userp, reqp,
856                                      flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
857                                      outVolpp);
858     }
859     return code;
860 }
861
862
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)
866 {
867     cm_volume_t *volp;
868 #ifdef SEARCH_ALL_VOLUMES
869     cm_volume_t *volp2;
870 #endif
871     long        code = 0;
872     char        name[VL_MAXNAMELEN];
873     size_t      len;
874     int         type;
875     afs_uint32  hash;
876
877     strncpy(name, volumeNamep, VL_MAXNAMELEN);
878     name[VL_MAXNAMELEN-1] = '\0';
879     len = strlen(name);
880
881     if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
882         type = BACKVOL;
883         name[len - 7] = '\0';
884     } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
885         type = ROVOL;
886         name[len - 9] = '\0';
887     } else {
888         type = RWVOL;
889     }
890
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) {
895             break;
896         }
897     }
898     volp2 = volp;
899 #endif /* SEARCH_ALL_VOLUMES */
900
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)
904             break;
905     }
906
907 #ifdef SEARCH_ALL_VOLUMES
908     osi_assertx(volp2 == volp, "unexpected cm_vol_t");
909 #endif
910
911     if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
912         afs_uint32 volType;
913         /* otherwise, get from VLDB */
914
915         /*
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.
919          */
920         lock_ConvertRToW(&cm_volumeLock);
921
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 */
927                     break;
928                 }
929             }
930 #else
931             for ( volp = cm_data.volumeLRULastp;
932                   volp;
933                   volp = (cm_volume_t *) osi_QPrev(&volp->q))
934             {
935                 if ( volp->refCount == 0 ) {
936                     /* There is one we can re-use */
937                     break;
938                 }
939             }
940 #endif
941             if (!volp)
942                 osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
943
944             InterlockedIncrement(&volp->refCount);
945             lock_ReleaseWrite(&cm_volumeLock);
946             lock_ObtainWrite(&volp->rw);
947             lock_ObtainWrite(&cm_volumeLock);
948
949             osi_Log2(afsd_logp, "Recycling Volume %s:%s",
950                      volp->cellp->name, volp->namep);
951
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.
956              */
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);
961
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);
972             }
973         } else {
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 */
984         }
985         volp->cellp = cellp;
986         strncpy(volp->namep, name, VL_MAXNAMELEN);
987         volp->namep[VL_MAXNAMELEN-1] = '\0';
988         volp->flags = CM_VOLUMEFLAG_RESET;
989         volp->lastUpdateTime = 0;
990
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;
995         }
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);
1002     }
1003     else {
1004         if (volp)
1005             cm_GetVolume(volp);
1006         lock_ReleaseRead(&cm_volumeLock);
1007
1008         if (!volp)
1009             return CM_ERROR_NOSUCHVOLUME;
1010
1011         lock_ObtainWrite(&volp->rw);
1012     }
1013
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);
1017     }
1018     lock_ReleaseWrite(&volp->rw);
1019
1020     if (code == 0 && (type == BACKVOL && volp->vol[BACKVOL].ID == 0 ||
1021                       type == ROVOL && volp->vol[ROVOL].ID == 0))
1022         code = CM_ERROR_NOSUCHVOLUME;
1023
1024     if (code == 0) {
1025         *outVolpp = volp;
1026
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);
1032     } else {
1033         /*
1034          * do not return it to the caller but do insert it in the LRU
1035          * otherwise it will be lost
1036          */
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);
1041         cm_PutVolume(volp);
1042         lock_ReleaseWrite(&cm_volumeLock);
1043     }
1044
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);
1048
1049         if (linkedCellp)
1050             code = cm_FindVolumeByName(linkedCellp, volumeNamep, userp, reqp,
1051                                        flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
1052                                        outVolpp);
1053     }
1054     return code;
1055 }
1056
1057 /*
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.
1061  */
1062 long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
1063 {
1064     cm_cell_t *cellp;
1065     cm_volume_t *volp;
1066 #ifdef SEARCH_ALL_VOLUMES
1067     cm_volume_t *volp2;
1068 #endif
1069     afs_uint32  hash;
1070     long code;
1071
1072     if (!fidp)
1073         return CM_ERROR_INVAL;
1074
1075     cellp = cm_FindCellByID(fidp->cell, 0);
1076     if (!cellp)
1077         return CM_ERROR_NOSUCHCELL;
1078
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))
1087             break;
1088     }
1089 #endif /* SEARCH_ALL_VOLUMES */
1090
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.
1095      */
1096     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
1097         if ( cellp == volp->cellp && fidp->volume == volp->vol[ROVOL].ID )
1098             break;
1099     }
1100     if (!volp) {
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 )
1104                 break;
1105         }
1106     }
1107     if (!volp) {
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 )
1111                 break;
1112         }
1113     }
1114
1115 #ifdef SEARCH_ALL_VOLUMES
1116     osi_assertx(volp == volp2, "unexpected cm_vol_t");
1117 #endif
1118     /* hold the volume if we found it */
1119     if (volp)
1120         cm_GetVolume(volp);
1121
1122     lock_ReleaseRead(&cm_volumeLock);
1123
1124     if (!volp)
1125         return CM_ERROR_NOSUCHVOLUME;
1126
1127     /* update it */
1128     cm_data.mountRootGen = time(NULL);
1129     lock_ObtainWrite(&volp->rw);
1130     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1131     volp->lastUpdateTime = 0;
1132
1133     code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1134     lock_ReleaseWrite(&volp->rw);
1135
1136     lock_ObtainRead(&cm_volumeLock);
1137     cm_PutVolume(volp);
1138     lock_ReleaseRead(&cm_volumeLock);
1139
1140     return code;
1141 }
1142
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)
1145 {
1146     cm_serverRef_t **serverspp;
1147     cm_serverRef_t *current;
1148     int firstTry = 1;
1149
1150   start:
1151     lock_ObtainWrite(&cm_serverLock);
1152
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;
1159     else {
1160         lock_ReleaseWrite(&cm_serverLock);
1161         if (firstTry) {
1162             afs_int32 code;
1163             firstTry = 0;
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);
1169             if (code == 0)
1170                 goto start;
1171         }
1172         return NULL;
1173     }
1174
1175     /*
1176      * Increment the refCount on deleted items as well.
1177      * They will be freed by cm_FreeServerList when they get to zero
1178      */
1179     for (current = *serverspp; current; current = current->next)
1180         cm_GetServerRef(current, TRUE);
1181
1182     lock_ReleaseWrite(&cm_serverLock);
1183
1184     return serverspp;
1185 }
1186
1187 void cm_PutVolume(cm_volume_t *volp)
1188 {
1189     afs_int32 refCount = InterlockedDecrement(&volp->refCount);
1190     osi_assertx(refCount >= 0, "cm_volume_t refCount underflow has occurred");
1191 }
1192
1193 /* return the read-only volume, if there is one, or the read-write volume if
1194  * not.
1195  */
1196 long cm_GetROVolumeID(cm_volume_t *volp)
1197 {
1198     long id;
1199
1200     lock_ObtainRead(&volp->rw);
1201     if (volp->vol[ROVOL].ID && volp->vol[ROVOL].serversp)
1202         id = volp->vol[ROVOL].ID;
1203     else
1204         id = volp->vol[RWVOL].ID;
1205     lock_ReleaseRead(&volp->rw);
1206
1207     return id;
1208 }
1209
1210 void cm_RefreshVolumes(int lifetime)
1211 {
1212     cm_volume_t *volp;
1213     afs_int32 refCount;
1214     time_t now;
1215
1216     now = time(NULL);
1217
1218     /* force mount point target updates */
1219     if (cm_data.mountRootGen + lifetime <= now)
1220         cm_data.mountRootGen = now;
1221
1222     /*
1223      * force a re-loading of volume data from the vldb
1224      * if the lifetime for the cached data has expired
1225      */
1226     lock_ObtainRead(&cm_volumeLock);
1227     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1228         InterlockedIncrement(&volp->refCount);
1229         lock_ReleaseRead(&cm_volumeLock);
1230
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;
1237                 }
1238             } else {
1239                 if (volp->lastUpdateTime + lifetime <= now) {
1240                     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1241                     volp->lastUpdateTime = 0;
1242                 }
1243             }
1244             lock_ReleaseWrite(&volp->rw);
1245         }
1246
1247         lock_ObtainRead(&cm_volumeLock);
1248         refCount = InterlockedDecrement(&volp->refCount);
1249         osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1250     }
1251     lock_ReleaseRead(&cm_volumeLock);
1252 }
1253
1254 void
1255 cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
1256                            afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
1257 {
1258     cm_conn_t *connp;
1259     long code;
1260     AFSFetchVolumeStatus volStat;
1261     char *Name;
1262     char *OfflineMsg;
1263     char *MOTD;
1264     cm_req_t req;
1265     struct rx_connection * rxconnp;
1266     char volName[32];
1267     char offLineMsg[256];
1268     char motd[256];
1269     long alldown, alldeleted;
1270     cm_serverRef_t *serversp;
1271     cm_fid_t fid;
1272
1273     Name = volName;
1274     OfflineMsg = offLineMsg;
1275     MOTD = motd;
1276
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);
1280
1281         if (!statep->serversp && !(*volumeUpdatedp)) {
1282             cm_InitReq(&req);
1283             code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1284             *volumeUpdatedp = 1;
1285         }
1286
1287         lock_ObtainRead(&cm_serverLock);
1288         if (statep->serversp) {
1289             alldown = 1;
1290             alldeleted = 1;
1291             for (serversp = statep->serversp; serversp; serversp = serversp->next) {
1292                 if (serversp->status == srv_deleted)
1293                     continue;
1294
1295                 alldeleted = 0;
1296
1297                 if (!(serversp->server->flags & CM_SERVERFLAG_DOWN))
1298                     alldown = 0;
1299
1300                 if (serversp->status == srv_busy || serversp->status == srv_offline)
1301                     serversp->status = srv_not_busy;
1302             }
1303             lock_ReleaseRead(&cm_serverLock);
1304
1305             if (alldeleted && !(*volumeUpdatedp)) {
1306                 cm_InitReq(&req);
1307                 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1308                 *volumeUpdatedp = 1;
1309             }
1310
1311             if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
1312                 (!alldown && statep->state == vl_alldown)) {
1313                 cm_InitReq(&req);
1314                 req.flags |= CM_REQ_OFFLINE_VOL_CHK;
1315
1316                 lock_ReleaseWrite(&volp->rw);
1317                 do {
1318                     code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
1319                     if (code)
1320                         continue;
1321
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, NULL, 0, NULL, NULL, NULL, code));
1327                 code = cm_MapRPCError(code, &req);
1328
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;
1333                     *onlinep = 1;
1334                 } else if (code == CM_ERROR_NOACCESS) {
1335                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
1336                     statep->state = vl_unknown;
1337                     *onlinep = 1;
1338                 }
1339             } else if (alldown && statep->state != vl_alldown) {
1340                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1341                 statep->state = vl_alldown;
1342             }
1343         } else {
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;
1348             }
1349         }
1350     }
1351 }
1352
1353 /* The return code is 0 if the volume is not online and
1354  * 1 if the volume is online
1355  */
1356 long
1357 cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
1358 {
1359     long code;
1360     cm_req_t req;
1361     afs_uint32 online = 0;
1362     afs_uint32 volumeUpdated = 0;
1363
1364     lock_ObtainWrite(&volp->rw);
1365
1366     if (volp->flags & CM_VOLUMEFLAG_RESET) {
1367         cm_InitReq(&req);
1368         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1369         volumeUpdated = 1;
1370     }
1371
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);
1375
1376     lock_ReleaseWrite(&volp->rw);
1377     return online;
1378 }
1379
1380
1381 /*
1382  * called from the Daemon thread.
1383  * when checking the offline status, check those of the most recently used volumes first.
1384  */
1385 void cm_CheckOfflineVolumes(void)
1386 {
1387     cm_volume_t *volp;
1388     afs_int32 refCount;
1389     extern int daemon_ShutdownFlag;
1390     extern int powerStateSuspended;
1391
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)) {
1396         /*
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.
1401          */
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");
1410         }
1411     }
1412     lock_ReleaseRead(&cm_volumeLock);
1413 }
1414
1415
1416 static void
1417 cm_UpdateVolumeStatusInt(cm_volume_t *volp, struct cm_vol_state *statep)
1418 {
1419     enum volstatus newStatus;
1420     cm_serverRef_t *tsrp;
1421     cm_server_t *tsp;
1422     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
1423     char addr[16];
1424
1425     if (!volp || !statep) {
1426 #ifdef DEBUG
1427         DebugBreak();
1428 #endif
1429         return;
1430     }
1431
1432     lock_ObtainWrite(&cm_serverLock);
1433     for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1434         tsp = tsrp->server;
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));
1440
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));
1444             continue;
1445         }
1446         if (tsp) {
1447             cm_GetServerNoLock(tsp);
1448             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
1449                 allDown = 0;
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));
1453                     allOffline = 0;
1454                     someBusy = 1;
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));
1458                     allBusy = 0;
1459                     someOffline = 1;
1460                 } else {
1461                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s online",
1462                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1463                     allOffline = 0;
1464                     allBusy = 0;
1465                 }
1466             } else {
1467                 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s down",
1468                           statep->ID, osi_LogSaveString(afsd_logp,addr));
1469             }
1470             cm_PutServerNoLock(tsp);
1471         }
1472     }
1473     lock_ReleaseWrite(&cm_serverLock);
1474
1475     osi_Log5(afsd_logp, "cm_UpdateVolumeStatusInt allDown %d allBusy %d someBusy %d someOffline %d allOffline %d",
1476              allDown, allBusy, someBusy, someOffline, allOffline);
1477
1478     if (allDown)
1479         newStatus = vl_alldown;
1480     else if (allBusy || (someBusy && someOffline))
1481         newStatus = vl_busy;
1482     else if (allOffline)
1483         newStatus = vl_offline;
1484     else
1485         newStatus = vl_online;
1486
1487     if (statep->ID && statep->state != newStatus)
1488         cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
1489
1490     statep->state = newStatus;
1491 }
1492
1493 void
1494 cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1495 {
1496
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]);
1503     } else {
1504         /*
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.
1510          */
1511         afs_uint32 volType;
1512         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1513             if (volp->vol[volType].ID != 0)
1514                 cm_UpdateVolumeStatusInt(volp, &volp->vol[volType]);
1515         }
1516     }
1517 }
1518
1519 /*
1520 ** Finds all volumes that reside on this server and reorders their
1521 ** RO list according to the changed rank of server.
1522 */
1523 void cm_ChangeRankVolume(cm_server_t *tsp)
1524 {
1525     int                 code;
1526     cm_volume_t*        volp;
1527     afs_int32 refCount;
1528
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)
1532     {
1533         code = 1 ;      /* assume that list is unchanged */
1534         InterlockedIncrement(&volp->refCount);
1535         lock_ReleaseRead(&cm_volumeLock);
1536         lock_ObtainWrite(&volp->rw);
1537
1538         if ((tsp->cellp==volp->cellp) && (volp->vol[ROVOL].serversp))
1539             code =cm_ChangeRankServer(&volp->vol[ROVOL].serversp, tsp);
1540
1541         /* this volume list was changed */
1542         if ( !code )
1543             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
1544
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");
1549     }
1550     lock_ReleaseRead(&cm_volumeLock);
1551 }
1552
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
1556  */
1557 int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
1558 {
1559     int zilch;
1560     cm_volume_t *volp;
1561     char output[1024];
1562
1563     if (lock) {
1564         lock_ObtainRead(&cm_scacheLock);
1565         lock_ObtainRead(&cm_volumeLock);
1566     }
1567
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);
1571
1572     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1573     {
1574         time_t t;
1575         char *srvStr = NULL;
1576         afs_uint32 srvStrRpc = TRUE;
1577         char *cbt = NULL;
1578         char *cdrot = NULL;
1579
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);
1584                 if (srvStr != NULL)
1585                     afs_inet_ntoa_r(volp->cbServerpRO->addr.sin_addr.s_addr, srvStr);
1586                 srvStrRpc = FALSE;
1587             }
1588         }
1589         if (volp->cbExpiresRO) {
1590             t = volp->cbExpiresRO;
1591             cbt = ctime(&t);
1592             if (cbt) {
1593                 cbt = strdup(cbt);
1594                 cbt[strlen(cbt)-1] = '\0';
1595             }
1596         }
1597         if (volp->creationDateRO) {
1598             t = volp->creationDateRO;
1599             cdrot = ctime(&t);
1600             if (cdrot) {
1601                 cdrot = strdup(cdrot);
1602                 cdrot[strlen(cdrot)-1] = '\0';
1603             }
1604         }
1605
1606         sprintf(output,
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>",
1612                  volp->refCount);
1613         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1614
1615         if (srvStr) {
1616             if (srvStrRpc)
1617                 RpcStringFree(&srvStr);
1618             else
1619                 free(srvStr);
1620         }
1621         if (cbt)
1622             free(cbt);
1623         if (cdrot)
1624             free(cdrot);
1625     }
1626     sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
1627     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1628
1629     if (lock) {
1630         lock_ReleaseRead(&cm_volumeLock);
1631         lock_ReleaseRead(&cm_scacheLock);
1632     }
1633     return (0);
1634 }
1635
1636
1637 /*
1638  * String hash function used by SDBM project.
1639  * It was chosen because it is fast and provides
1640  * decent coverage.
1641  */
1642 afs_uint32 SDBMHash(const char * str)
1643 {
1644     afs_uint32 hash = 0;
1645     size_t i, len;
1646
1647     if (str == NULL)
1648         return 0;
1649
1650     for(i = 0, len = strlen(str); i < len; i++)
1651     {
1652         hash = str[i] + (hash << 6) + (hash << 16) - hash;
1653     }
1654
1655     return (hash & 0x7FFFFFFF);
1656 }
1657
1658 /* call with volume write-locked and mutex held */
1659 void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
1660 {
1661     int i;
1662
1663     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
1664         return;
1665
1666     i = CM_VOLUME_NAME_HASH(volp->namep);
1667
1668     volp->nameNextp = cm_data.volumeNameHashTablep[i];
1669     cm_data.volumeNameHashTablep[i] = volp;
1670     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_HASH);
1671 }
1672
1673 /* call with volume write-locked and mutex held */
1674 void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
1675 {
1676     cm_volume_t **lvolpp;
1677     cm_volume_t *tvolp;
1678     int i;
1679
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];
1684              tvolp;
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;
1690                 break;
1691             }
1692         }
1693     }
1694 }
1695
1696 /* call with volume write-locked and mutex held */
1697 void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1698 {
1699     int i;
1700     struct cm_vol_state * statep;
1701
1702     statep = cm_VolumeStateByType(volp, volType);
1703
1704     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH)
1705         return;
1706
1707     i = CM_VOLUME_ID_HASH(statep->ID);
1708
1709     switch (volType) {
1710     case RWVOL:
1711         statep->nextp = cm_data.volumeRWIDHashTablep[i];
1712         cm_data.volumeRWIDHashTablep[i] = volp;
1713         break;
1714     case ROVOL:
1715         statep->nextp = cm_data.volumeROIDHashTablep[i];
1716         cm_data.volumeROIDHashTablep[i] = volp;
1717         break;
1718     case BACKVOL:
1719         statep->nextp = cm_data.volumeBKIDHashTablep[i];
1720         cm_data.volumeBKIDHashTablep[i] = volp;
1721         break;
1722     }
1723     _InterlockedOr(&statep->qflags, CM_VOLUME_QFLAG_IN_HASH);
1724 }
1725
1726
1727 /* call with volume write-locked and mutex held */
1728 void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1729 {
1730     cm_volume_t **lvolpp;
1731     cm_volume_t *tvolp;
1732     struct cm_vol_state * statep;
1733     int i;
1734
1735     statep = cm_VolumeStateByType(volp, volType);
1736
1737     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1738         /* hash it out first */
1739         i = CM_VOLUME_ID_HASH(statep->ID);
1740
1741         switch (volType) {
1742         case RWVOL:
1743             lvolpp = &cm_data.volumeRWIDHashTablep[i];
1744             tvolp = cm_data.volumeRWIDHashTablep[i];
1745             break;
1746         case ROVOL:
1747             lvolpp = &cm_data.volumeROIDHashTablep[i];
1748             tvolp = cm_data.volumeROIDHashTablep[i];
1749             break;
1750         case BACKVOL:
1751             lvolpp = &cm_data.volumeBKIDHashTablep[i];
1752             tvolp = cm_data.volumeBKIDHashTablep[i];
1753             break;
1754         default:
1755             osi_assertx(0, "invalid volume type");
1756         }
1757         do {
1758             if (tvolp == volp) {
1759                 *lvolpp = statep->nextp;
1760                 _InterlockedAnd(&statep->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1761                 statep->nextp = NULL;
1762                 break;
1763             }
1764
1765             lvolpp = &tvolp->vol[volType].nextp;
1766             tvolp = tvolp->vol[volType].nextp;
1767         } while(tvolp);
1768     }
1769 }
1770
1771 /* must be called with cm_volumeLock write-locked! */
1772 void cm_AdjustVolumeLRU(cm_volume_t *volp)
1773 {
1774     lock_AssertWrite(&cm_volumeLock);
1775
1776     if (volp == cm_data.volumeLRUFirstp)
1777         return;
1778
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);
1783
1784     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1785 }
1786
1787 /* must be called with cm_volumeLock write-locked! */
1788 void cm_MoveVolumeToLRULast(cm_volume_t *volp)
1789 {
1790     lock_AssertWrite(&cm_volumeLock);
1791
1792     if (volp == cm_data.volumeLRULastp)
1793         return;
1794
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);
1799
1800     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1801 }
1802
1803 /* must be called with cm_volumeLock write-locked! */
1804 void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
1805 {
1806     lock_AssertWrite(&cm_volumeLock);
1807
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);
1811     }
1812
1813     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1814 }
1815
1816 static char * volstatus_str(enum volstatus vs)
1817 {
1818     switch (vs) {
1819     case vl_online:
1820         return "online";
1821     case vl_busy:
1822         return "busy";
1823     case vl_offline:
1824         return "offline";
1825     case vl_alldown:
1826         return "alldown";
1827     default:
1828         return "unknown";
1829     }
1830 }
1831
1832 void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
1833 {
1834     char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN]="";
1835     char *ext = "";
1836
1837     if (volID == volp->vol[RWVOL].ID)
1838         ext = "";
1839     else if (volID == volp->vol[ROVOL].ID)
1840         ext = ".readonly";
1841     else if (volID == volp->vol[BACKVOL].ID)
1842         ext = ".backup";
1843     else
1844         ext = ".nomatch";
1845     snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
1846
1847     osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
1848              osi_LogSaveString(afsd_logp, volstr), volID, volstatus_str(old), volstatus_str(new));
1849
1850     cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new);
1851 }
1852
1853 enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1854 {
1855     cm_vol_state_t * statep = cm_VolumeStateByID(volp, volID);
1856     if (statep)
1857         return statep->state;
1858     else
1859         return vl_unknown;
1860 }
1861
1862 /* Renew .readonly volume callbacks that are more than
1863  * 30 minutes old.  (A volume callback is issued for 2 hours.)
1864  */
1865 void
1866 cm_VolumeRenewROCallbacks(void)
1867 {
1868     cm_volume_t * volp;
1869     time_t minexp = time(NULL) + 90 * 60;
1870     extern int daemon_ShutdownFlag;
1871     extern int powerStateSuspended;
1872
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) {
1878             cm_req_t      req;
1879             cm_fid_t      fid;
1880             cm_scache_t * scp;
1881
1882             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
1883
1884             cm_InitReq(&req);
1885
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);
1892             }
1893             lock_ObtainRead(&cm_volumeLock);
1894         }
1895     }
1896     lock_ReleaseRead(&cm_volumeLock);
1897 }
1898
1899 cm_vol_state_t *
1900 cm_VolumeStateByType(cm_volume_t *volp, afs_uint32 volType)
1901 {
1902     return &volp->vol[volType];
1903 }
1904
1905 cm_vol_state_t *
1906 cm_VolumeStateByID(cm_volume_t *volp, afs_uint32 id)
1907 {
1908     cm_vol_state_t * statep = NULL;
1909
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];
1916
1917     return(statep);
1918 }
1919
1920 cm_vol_state_t *
1921 cm_VolumeStateByName(cm_volume_t *volp, char *volname)
1922 {
1923     size_t len = strlen(volname);
1924     cm_vol_state_t *statep;
1925
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];
1930     else
1931         statep = &volp->vol[RWVOL];
1932
1933     return statep;
1934 }
1935
1936 afs_int32
1937 cm_VolumeType(cm_volume_t *volp, afs_uint32 id)
1938 {
1939     if (id == volp->vol[RWVOL].ID)
1940         return(RWVOL);
1941     else if (id == volp->vol[ROVOL].ID)
1942         return(ROVOL);
1943     else if (id == volp->vol[BACKVOL].ID)
1944         return (BACKVOL);
1945
1946     return -1;
1947 }
1948
1949 LONG_PTR
1950 cm_ChecksumVolumeServerList(struct cm_fid *fidp, cm_user_t *userp, cm_req_t *reqp)
1951 {
1952     LONG_PTR cksum = 0;
1953     long code;
1954     afs_uint32 replicated;
1955     cm_serverRef_t **serverspp;
1956
1957     code = cm_GetServerList(fidp, userp, reqp, &replicated, &serverspp);
1958     if (code == 0) {
1959         cksum = cm_ChecksumServerList(*serverspp);
1960         cm_FreeServerList(serverspp, 0);
1961     }
1962     return cksum;
1963 }