Windows: cm_FindVolumeByName refactoring
[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
264     lock_AssertWrite(&volp->rw);
265
266     /*
267      * If the last volume update was in the last five
268      * minutes and it did not exist, then avoid the RPC
269      * and return No Such Volume immediately.
270      */
271     now = time(NULL);
272     if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
273         (now < volp->lastUpdateTime + 600))
274     {
275         return CM_ERROR_NOSUCHVOLUME;
276     }
277
278 #ifdef AFS_FREELANCE_CLIENT
279     if (cellp->cellID == AFS_FAKE_ROOT_CELL_ID)
280     {
281         freelance = 1;
282         memset(&vldbEntry, 0, sizeof(vldbEntry));
283         vldbEntry.flags |= VLF_RWEXISTS;
284         vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
285         code = 0;
286         method = 0;
287     } else
288 #endif
289     {
290         while (volp->flags & CM_VOLUMEFLAG_UPDATING_VL) {
291             osi_Log3(afsd_logp, "cm_UpdateVolumeLocation sleeping name %s:%s flags 0x%x",
292                      volp->cellp->name, volp->namep, volp->flags);
293             osi_SleepW((LONG_PTR) &volp->flags, &volp->rw);
294             lock_ObtainWrite(&volp->rw);
295             osi_Log3(afsd_logp, "cm_UpdateVolumeLocation awake name %s:%s flags 0x%x",
296                      volp->cellp->name, volp->namep, volp->flags);
297             if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
298                 osi_Log3(afsd_logp, "cm_UpdateVolumeLocation nothing to do, waking others name %s:%s flags 0x%x",
299                          volp->cellp->name, volp->namep, volp->flags);
300                 osi_Wakeup((LONG_PTR) &volp->flags);
301                 return 0;
302             }
303             now = time(NULL);
304         }
305
306         /* Do not query again if the last update attempt failed in the last 60 seconds */
307         if ((volp->flags & CM_VOLUMEFLAG_RESET) && (volp->lastUpdateTime > now - 60))
308         {
309             osi_Log3(afsd_logp, "cm_UpdateVolumeLocation unsuccessful update in last 60 seconds -- name %s:%s flags 0x%x",
310                       volp->cellp->name, volp->namep, volp->flags);
311             return(CM_ERROR_ALLDOWN);
312         }
313
314         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_UPDATING_VL);
315
316         /* Do not hold the volume lock across the RPC calls */
317         lock_ReleaseWrite(&volp->rw);
318
319         if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
320              cm_UpdateCell(cellp, 0);
321
322         /* now we have volume structure locked and held; make RPC to fill it */
323         code = cm_GetEntryByName(cellp, volp->namep, &vldbEntry, &nvldbEntry,
324                                  &uvldbEntry,
325                                  &method, userp, reqp);
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         lock_ObtainWrite(&volp->rw);
363     }
364
365     if (code == 0) {
366         afs_int32 flags;
367         afs_int32 nServers;
368         afs_int32 rwID;
369         afs_int32 roID;
370         afs_int32 bkID;
371         afs_int32 serverNumber[NMAXNSERVERS];
372         afs_int32 serverFlags[NMAXNSERVERS];
373         afsUUID   serverUUID[NMAXNSERVERS];
374         afs_int32 rwServers_alldown = 1;
375         afs_int32 roServers_alldown = 1;
376         afs_int32 bkServers_alldown = 1;
377         char      name[VL_MAXNAMELEN];
378
379 #ifdef AFS_FREELANCE_CLIENT
380         if (freelance)
381             rwServers_alldown = 0;
382 #endif
383
384         /* clear out old bindings */
385         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
386             if (volp->vol[volType].serversp)
387                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
388         }
389
390         memset(serverUUID, 0, sizeof(serverUUID));
391
392         switch ( method ) {
393         case 0:
394             flags = vldbEntry.flags;
395             nServers = vldbEntry.nServers;
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             rwID = nvldbEntry.volumeId[0];
410             roID = nvldbEntry.volumeId[1];
411             bkID = nvldbEntry.volumeId[2];
412             for ( i=0; i<nServers; i++ ) {
413                 serverFlags[i] = nvldbEntry.serverFlags[i];
414                 serverNumber[i] = nvldbEntry.serverNumber[i];
415             }
416             strncpy(name, nvldbEntry.name, VL_MAXNAMELEN);
417             name[VL_MAXNAMELEN - 1] = '\0';
418             break;
419         case 2:
420             flags = uvldbEntry.flags;
421             nServers = uvldbEntry.nServers;
422             rwID = uvldbEntry.volumeId[0];
423             roID = uvldbEntry.volumeId[1];
424             bkID = uvldbEntry.volumeId[2];
425             for ( i=0, j=0; code == 0 && i<nServers && j<NMAXNSERVERS; i++ ) {
426                 if ( !(uvldbEntry.serverFlags[i] & VLSF_UUID) ) {
427                     serverFlags[j] = uvldbEntry.serverFlags[i];
428                     serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
429                     j++;
430                 } else {
431                     afs_uint32 * addrp, nentries, code, unique;
432                     bulkaddrs  addrs;
433                     ListAddrByAttributes attrs;
434                     afsUUID uuid;
435
436                     memset(&attrs, 0, sizeof(attrs));
437                     attrs.Mask = VLADDR_UUID;
438                     attrs.uuid = uvldbEntry.serverNumber[i];
439                     memset(&uuid, 0, sizeof(uuid));
440                     memset(&addrs, 0, sizeof(addrs));
441
442                     do {
443                         code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
444                         if (code)
445                             continue;
446
447                         rxconnp = cm_GetRxConn(connp);
448                         code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries, &addrs);
449                         rx_PutConnection(rxconnp);
450                     } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, cellp->vlServersp, NULL, code));
451
452                     if ( code ) {
453                         code = cm_MapVLRPCError(code, reqp);
454                         osi_Log2(afsd_logp, "CALL VL_GetAddrsU serverNumber %u FAILURE, code 0x%x",
455                                  i, code);
456                         continue;
457                     }
458                     osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %u SUCCESS", i);
459
460                     addrp = addrs.bulkaddrs_val;
461                     for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
462                         serverFlags[j] = uvldbEntry.serverFlags[i];
463                         serverNumber[j] = addrp[k];
464                         serverUUID[j] = uuid;
465                     }
466
467                     xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
468
469                     if (nentries == 0)
470                         code = CM_ERROR_INVAL;
471                 }
472             }
473             nServers = j;                                       /* update the server count */
474             strncpy(name, uvldbEntry.name, VL_MAXNAMELEN);
475             name[VL_MAXNAMELEN - 1] = '\0';
476             break;
477         }
478
479         /* decode the response */
480         lock_ObtainWrite(&cm_volumeLock);
481         if (!cm_VolNameIsID(volp->namep)) {
482             size_t    len;
483
484             len = strlen(name);
485
486             if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
487                 name[len - 7] = '\0';
488             } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
489                 name[len - 9] = '\0';
490             }
491
492             osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s",
493                      osi_LogSaveString(afsd_logp,volp->namep), osi_LogSaveString(afsd_logp,name));
494
495             if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
496                 cm_RemoveVolumeFromNameHashTable(volp);
497
498             strcpy(volp->namep, name);
499
500             cm_AddVolumeToNameHashTable(volp);
501         }
502
503         if (flags & VLF_DFSFILESET) {
504             _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_DFS_VOLUME);
505             osi_Log1(afsd_logp, "cm_UpdateVolume Volume Group '%s' is a DFS File Set.  Correct behavior is not implemented.",
506                      osi_LogSaveString(afsd_logp, volp->namep));
507         }
508
509         if (flags & VLF_RWEXISTS) {
510             if (volp->vol[RWVOL].ID != rwID) {
511                 if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
512                     cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
513                 volp->vol[RWVOL].ID = rwID;
514                 cm_AddVolumeToIDHashTable(volp, RWVOL);
515             }
516         } else {
517             if (volp->vol[RWVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
518                 cm_RemoveVolumeFromIDHashTable(volp, RWVOL);
519             volp->vol[RWVOL].ID = 0;
520         }
521         if (flags & VLF_ROEXISTS) {
522             if (volp->vol[ROVOL].ID != roID) {
523                 if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
524                     cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
525                 volp->vol[ROVOL].ID = roID;
526                 cm_AddVolumeToIDHashTable(volp, ROVOL);
527             }
528         } else {
529             if (volp->vol[ROVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
530                 cm_RemoveVolumeFromIDHashTable(volp, ROVOL);
531             volp->vol[ROVOL].ID = 0;
532         }
533         if (flags & VLF_BACKEXISTS) {
534             if (volp->vol[BACKVOL].ID != bkID) {
535                 if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
536                     cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
537                 volp->vol[BACKVOL].ID = bkID;
538                 cm_AddVolumeToIDHashTable(volp, BACKVOL);
539             }
540         } else {
541             if (volp->vol[BACKVOL].qflags & CM_VOLUME_QFLAG_IN_HASH)
542                 cm_RemoveVolumeFromIDHashTable(volp, BACKVOL);
543             volp->vol[BACKVOL].ID = 0;
544         }
545         lock_ReleaseWrite(&cm_volumeLock);
546
547         /* See if the replica sites are mixed versions */
548         for (i=0; i<nServers; i++) {
549             if (serverFlags[i] & VLSF_NEWREPSITE) {
550                 isMixed = 1;
551                 break;
552             }
553         }
554
555         for (i=0; i<nServers; i++) {
556             /* create a server entry */
557             tflags = serverFlags[i];
558             if (tflags & VLSF_DONTUSE)
559                 continue;
560             tsockAddr.sin_port = htons(7000);
561             tsockAddr.sin_family = AF_INET;
562             tempAddr = htonl(serverNumber[i]);
563             tsockAddr.sin_addr.s_addr = tempAddr;
564             tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE, FALSE);
565             if (tsp && (method == 2) && (tsp->flags & CM_SERVERFLAG_UUID)) {
566                 /*
567                  * Check to see if the uuid of the server we know at this address
568                  * matches the uuid of the server we are being told about by the
569                  * vlserver.  If not, ...?
570                  */
571                 if (!afs_uuid_equal(&serverUUID[i], &tsp->uuid)) {
572                     char uuid1[128], uuid2[128];
573                     char hoststr[16];
574
575                     afsUUID_to_string(&serverUUID[i], uuid1, sizeof(uuid1));
576                     afsUUID_to_string(&tsp->uuid, uuid2, sizeof(uuid2));
577                     afs_inet_ntoa_r(serverNumber[i], hoststr);
578
579                     osi_Log3(afsd_logp, "cm_UpdateVolumeLocation UUIDs do not match! %s != %s (%s)",
580                               osi_LogSaveString(afsd_logp, uuid1),
581                               osi_LogSaveString(afsd_logp, uuid2),
582                               osi_LogSaveString(afsd_logp, hoststr));
583                 }
584             }
585             if (!tsp) {
586                 /*
587                  * cm_NewServer will probe the file server which in turn will
588                  * update the state on the volume group object.  Do not probe
589                  * in this thread.  It will block the thread and can result in
590                  * a recursive call to cm_UpdateVolumeLocation().
591                  */
592                 lock_ReleaseWrite(&volp->rw);
593                 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, &serverUUID[i], CM_FLAG_NOPROBE);
594                 lock_ObtainWrite(&volp->rw);
595             }
596             osi_assertx(tsp != NULL, "null cm_server_t");
597
598             /*
599              * if this server was created by fs setserverprefs
600              * then it won't have either a cell assignment or
601              * a server uuid.
602              */
603             if ( !tsp->cellp )
604                 tsp->cellp = cellp;
605             if ( (method == 2) && !(tsp->flags & CM_SERVERFLAG_UUID) &&
606                  !afs_uuid_is_nil(&serverUUID[i])) {
607                 tsp->uuid = serverUUID[i];
608                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
609             }
610
611             /* and add it to the list(s). */
612             /*
613              * Each call to cm_NewServerRef() increments the
614              * ref count of tsp.  These reference will be dropped,
615              * if and when the volume is reset; see reset code
616              * earlier in this function.
617              */
618             if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
619                 tsrp = cm_NewServerRef(tsp, rwID);
620                 cm_InsertServerList(&volp->vol[RWVOL].serversp, tsrp);
621                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
622                     rwServers_alldown = 0;
623             }
624             /*
625              * If there are mixed versions of RO releases on the replica
626              * sites, skip the servers with the out of date versions.
627              */
628             if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS) &&
629                 (!isMixed || (tflags & VLSF_NEWREPSITE))) {
630                 tsrp = cm_NewServerRef(tsp, roID);
631                 cm_InsertServerList(&volp->vol[ROVOL].serversp, tsrp);
632                 ROcount++;
633
634                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
635                     roServers_alldown = 0;
636             }
637             /* We don't use VLSF_BACKVOL !?! */
638             /* Because only the backup on the server holding the RW
639              * volume can be valid.  This check prevents errors if a
640              * RW is moved but the old backup is not removed.
641              */
642             if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
643                 tsrp = cm_NewServerRef(tsp, bkID);
644                 cm_InsertServerList(&volp->vol[BACKVOL].serversp, tsrp);
645
646                 if (!(tsp->flags & CM_SERVERFLAG_DOWN))
647                     bkServers_alldown = 0;
648             }
649             /* Drop the reference obtained by cm_FindServer() */
650             cm_PutServer(tsp);
651         }
652
653         /*
654          * Randomize RO list
655          *
656          * If the first n servers have the same rank, then we
657          * randomly pick one among them and move it to the beginning.
658          * We don't bother to re-order the whole list because
659          * the rest of the list is used only if the first server is
660          * down.  We only do this for the RO list; we assume the other
661          * lists are length 1.
662          */
663         if (ROcount > 1) {
664             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
665             _InterlockedOr(&volp->vol[ROVOL].flags, CM_VOL_STATE_FLAG_REPLICATED);
666         }
667         else {
668             _InterlockedAnd(&volp->vol[ROVOL].flags, ~CM_VOL_STATE_FLAG_REPLICATED);
669         }
670
671         rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
672         roNewstate = roServers_alldown ? vl_alldown : vl_online;
673         bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
674
675         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_NOEXIST);
676     } else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
677         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_NOEXIST);
678     } else {
679         rwNewstate = roNewstate = bkNewstate = vl_alldown;
680
681         /*
682          * we are updating lastUpdateTime but didn't get an answer
683          * so clear the no exist flag.
684          */
685         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_NOEXIST);
686     }
687
688     if (volp->vol[RWVOL].state != rwNewstate) {
689         if (volp->vol[RWVOL].ID)
690             cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, rwNewstate);
691         volp->vol[RWVOL].state = rwNewstate;
692     }
693     if (volp->vol[ROVOL].state != roNewstate) {
694         if (volp->vol[ROVOL].ID)
695             cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, roNewstate);
696         volp->vol[ROVOL].state = roNewstate;
697     }
698     if (volp->vol[BACKVOL].state != bkNewstate) {
699         if (volp->vol[BACKVOL].ID)
700             cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, bkNewstate);
701         volp->vol[BACKVOL].state = bkNewstate;
702     }
703
704     volp->lastUpdateTime = time(NULL);
705     if (isMixed)
706         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_MIXED);
707     else
708         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_MIXED);
709
710     if (code == 0)
711         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RESET);
712
713     _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_UPDATING_VL);
714     osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x",
715              osi_LogSaveString(afsd_logp,volp->cellp->name),
716              osi_LogSaveString(afsd_logp,volp->namep), volp->flags, code);
717     osi_Wakeup((LONG_PTR) &volp->flags);
718
719     return code;
720 }
721
722 /* Requires read or write lock on cm_volumeLock */
723 void cm_GetVolume(cm_volume_t *volp)
724 {
725     InterlockedIncrement(&volp->refCount);
726 }
727
728 cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
729 {
730     cm_volume_t *volp;
731     afs_uint32 hash;
732
733     lock_ObtainRead(&cm_volumeLock);
734     hash = CM_VOLUME_ID_HASH(fidp->volume);
735     /* The volumeID can be any one of the three types.  So we must
736      * search the hash table for all three types until we find it.
737      * We will search in the order of RO, RW, BK.
738      */
739     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
740         if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[ROVOL].ID )
741             break;
742     }
743     if (!volp) {
744         /* try RW volumes */
745         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
746             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[RWVOL].ID )
747                 break;
748         }
749     }
750     if (!volp) {
751         /* try BK volumes */
752         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
753             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[BACKVOL].ID )
754                 break;
755         }
756     }
757
758     /* hold the volume if we found it */
759     if (volp)
760         cm_GetVolume(volp);
761
762     lock_ReleaseRead(&cm_volumeLock);
763     return volp;
764 }
765
766 long cm_FindVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
767                       cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
768 {
769     cm_volume_t *volp;
770 #ifdef SEARCH_ALL_VOLUMES
771     cm_volume_t *volp2;
772 #endif
773     char volNameString[VL_MAXNAMELEN];
774     afs_uint32 hash;
775     long code = 0;
776
777     lock_ObtainRead(&cm_volumeLock);
778 #ifdef SEARCH_ALL_VOLUMES
779     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
780         if (cellp == volp->cellp &&
781              ((unsigned) volumeID == volp->vol[RWVOL].ID ||
782                (unsigned) volumeID == volp->vol[ROVOL].ID ||
783                (unsigned) volumeID == volp->vol[BACKVOL].ID))
784             break;
785     }
786
787     volp2 = volp;
788 #endif /* SEARCH_ALL_VOLUMES */
789
790     hash = CM_VOLUME_ID_HASH(volumeID);
791     /* The volumeID can be any one of the three types.  So we must
792      * search the hash table for all three types until we find it.
793      * We will search in the order of RO, RW, BK.
794      */
795     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
796         if ( cellp == volp->cellp && volumeID == volp->vol[ROVOL].ID )
797             break;
798     }
799     if (!volp) {
800         /* try RW volumes */
801         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
802             if ( cellp == volp->cellp && volumeID == volp->vol[RWVOL].ID )
803                 break;
804         }
805     }
806     if (!volp) {
807         /* try BK volumes */
808         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
809             if ( cellp == volp->cellp && volumeID == volp->vol[BACKVOL].ID )
810                 break;
811         }
812     }
813
814 #ifdef SEARCH_ALL_VOLUMES
815     osi_assertx(volp == volp2, "unexpected cm_vol_t");
816 #endif
817
818     /* hold the volume if we found it */
819     if (volp)
820         cm_GetVolume(volp);
821
822     lock_ReleaseRead(&cm_volumeLock);
823
824     /* return it held */
825     if (volp) {
826         lock_ObtainWrite(&volp->rw);
827
828         code = 0;
829         if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
830             code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
831         }
832         lock_ReleaseWrite(&volp->rw);
833         if (code == 0) {
834             *outVolpp = volp;
835
836             if (!(flags & CM_GETVOL_FLAG_NO_LRU_UPDATE)) {
837                 lock_ObtainWrite(&cm_volumeLock);
838                 cm_AdjustVolumeLRU(volp);
839                 lock_ReleaseWrite(&cm_volumeLock);
840             }
841         } else {
842             lock_ObtainRead(&cm_volumeLock);
843             cm_PutVolume(volp);
844             lock_ReleaseRead(&cm_volumeLock);
845         }
846         return code;
847     }
848
849     /* otherwise, we didn't find it so consult the VLDB */
850     sprintf(volNameString, "%u", volumeID);
851     code = cm_FindVolumeByName(cellp, volNameString, userp, reqp,
852                               flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL, outVolpp);
853
854     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
855         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
856         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
857
858         if (linkedCellp)
859             code = cm_FindVolumeByID(linkedCellp, volumeID, userp, reqp,
860                                      flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
861                                      outVolpp);
862     }
863     return code;
864 }
865
866
867 long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
868                         struct cm_user *userp, struct cm_req *reqp,
869                         afs_uint32 flags, cm_volume_t **outVolpp)
870 {
871     cm_volume_t *volp;
872 #ifdef SEARCH_ALL_VOLUMES
873     cm_volume_t *volp2;
874 #endif
875     long        code = 0;
876     char        name[VL_MAXNAMELEN];
877     size_t      len;
878     int         type;
879     afs_uint32  hash;
880
881     strncpy(name, volumeNamep, VL_MAXNAMELEN);
882     name[VL_MAXNAMELEN-1] = '\0';
883     len = strlen(name);
884
885     if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
886         type = BACKVOL;
887         name[len - 7] = '\0';
888     } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
889         type = ROVOL;
890         name[len - 9] = '\0';
891     } else {
892         type = RWVOL;
893     }
894
895     lock_ObtainRead(&cm_volumeLock);
896 #ifdef SEARCH_ALL_VOLUMES
897     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
898         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0) {
899             break;
900         }
901     }
902     volp2 = volp;
903 #endif /* SEARCH_ALL_VOLUMES */
904
905     hash = CM_VOLUME_NAME_HASH(name);
906     for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
907         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
908             break;
909     }
910
911 #ifdef SEARCH_ALL_VOLUMES
912     osi_assertx(volp2 == volp, "unexpected cm_vol_t");
913 #endif
914
915     if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
916         afs_uint32 volType;
917         /* otherwise, get from VLDB */
918
919         /*
920          * Change to a write lock so that we have exclusive use of
921          * the first cm_volume_t with a refCount of 0 so that we
922          * have time to increment it.
923          */
924         lock_ConvertRToW(&cm_volumeLock);
925
926         /*
927          * While the lock was converted it may have been dropped
928          * Search again now that we are exclusive.
929          */
930         for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
931             if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
932                 break;
933         }
934
935         if (volp) {
936             cm_GetVolume(volp);
937             lock_ReleaseWrite(&cm_volumeLock);
938             lock_ObtainWrite(&volp->rw);
939         } else {
940             if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
941 #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
942                 for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
943                     if ( volp->refCount == 0 ) {
944                         /* There is one we can re-use */
945                         break;
946                     }
947                 }
948 #else
949                 for ( volp = cm_data.volumeLRULastp;
950                       volp;
951                       volp = (cm_volume_t *) osi_QPrev(&volp->q))
952                 {
953                     if ( volp->refCount == 0 ) {
954                         /* There is one we can re-use */
955                         break;
956                     }
957                 }
958 #endif
959                 if (!volp)
960                     osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
961
962                 osi_Log2(afsd_logp, "Recycling Volume %s:%s",
963                          volp->cellp->name, volp->namep);
964
965                 /* The volp is removed from the LRU queue in order to
966                  * prevent two threads from attempting to recycle the
967                  * same object.  This volp must be re-inserted back into
968                  * the LRU queue before this function exits.
969                  */
970                 if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
971                     cm_RemoveVolumeFromLRU(volp);
972                 if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
973                     cm_RemoveVolumeFromNameHashTable(volp);
974
975                 for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
976                     if (volp->vol[volType].qflags & CM_VOLUME_QFLAG_IN_HASH)
977                         cm_RemoveVolumeFromIDHashTable(volp, volType);
978                     if (volp->vol[volType].ID)
979                         cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_unknown);
980                     volp->vol[volType].ID = 0;
981                     cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
982                 }
983             } else {
984                 volp = &cm_data.volumeBaseAddress[InterlockedIncrement(&cm_data.currentVolumes) - 1];
985                 memset(volp, 0, sizeof(cm_volume_t));
986                 volp->magic = CM_VOLUME_MAGIC;
987                 volp->allNextp = cm_data.allVolumesp;
988                 cm_data.allVolumesp = volp;
989                 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
990             }
991             /*
992              * no one else can find this object and we have not dropped
993              * cm_volumeLock in any case.  The object is either new or
994              * recycled.  Initialize its new values and put it into the
995              * name hash table before dropping cm_volumeLock which makes
996              * it visible to competing threads.
997              */
998             volp->cellp = cellp;
999             strncpy(volp->namep, name, VL_MAXNAMELEN);
1000             volp->namep[VL_MAXNAMELEN-1] = '\0';
1001             volp->flags = CM_VOLUMEFLAG_RESET;
1002             volp->lastUpdateTime = 0;
1003
1004             for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1005                 volp->vol[volType].state = vl_unknown;
1006                 volp->vol[volType].nextp = NULL;
1007                 volp->vol[volType].flags = 0;
1008             }
1009             volp->cbExpiresRO = 0;
1010             volp->cbIssuedRO = 0;
1011             volp->cbServerpRO = NULL;
1012             volp->creationDateRO = 0;
1013             cm_AddVolumeToNameHashTable(volp);
1014             cm_GetVolume(volp);
1015             lock_ReleaseWrite(&cm_volumeLock);
1016             lock_ObtainWrite(&volp->rw);
1017             for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1018                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
1019             }
1020         }
1021     }
1022     else if (volp) {
1023         cm_GetVolume(volp);
1024         lock_ReleaseRead(&cm_volumeLock);
1025         lock_ObtainWrite(&volp->rw);
1026     } else {
1027         lock_ReleaseRead(&cm_volumeLock);
1028         return CM_ERROR_NOSUCHVOLUME;
1029     }
1030
1031     /* if we get here we are holding the mutex */
1032     if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
1033         code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1034     }
1035     lock_ReleaseWrite(&volp->rw);
1036
1037     if (code == 0 && (type == BACKVOL && volp->vol[BACKVOL].ID == 0 ||
1038                       type == ROVOL && volp->vol[ROVOL].ID == 0))
1039         code = CM_ERROR_NOSUCHVOLUME;
1040
1041     if (code == 0) {
1042         *outVolpp = volp;
1043
1044         lock_ObtainWrite(&cm_volumeLock);
1045         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1046              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1047             cm_AdjustVolumeLRU(volp);
1048         lock_ReleaseWrite(&cm_volumeLock);
1049     } else {
1050         /*
1051          * do not return it to the caller but do insert it in the LRU
1052          * otherwise it will be lost
1053          */
1054         lock_ObtainWrite(&cm_volumeLock);
1055         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1056              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1057             cm_AdjustVolumeLRU(volp);
1058         cm_PutVolume(volp);
1059         lock_ReleaseWrite(&cm_volumeLock);
1060     }
1061
1062     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
1063         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
1064         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
1065
1066         if (linkedCellp)
1067             code = cm_FindVolumeByName(linkedCellp, volumeNamep, userp, reqp,
1068                                        flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
1069                                        outVolpp);
1070     }
1071     return code;
1072 }
1073
1074 /*
1075  * Only call this function in response to a VNOVOL or VMOVED error
1076  * from a file server.  Do not call it in response to CM_ERROR_NOSUCHVOLUME
1077  * as that can lead to recursive calls.
1078  */
1079 long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
1080 {
1081     cm_cell_t *cellp;
1082     cm_volume_t *volp;
1083 #ifdef SEARCH_ALL_VOLUMES
1084     cm_volume_t *volp2;
1085 #endif
1086     afs_uint32  hash;
1087     long code;
1088
1089     if (!fidp)
1090         return CM_ERROR_INVAL;
1091
1092     cellp = cm_FindCellByID(fidp->cell, 0);
1093     if (!cellp)
1094         return CM_ERROR_NOSUCHCELL;
1095
1096     /* search for the volume */
1097     lock_ObtainRead(&cm_volumeLock);
1098 #ifdef SEARCH_ALL_VOLUMES
1099     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1100         if (cellp == volp->cellp &&
1101              (fidp->volume == volp->vol[RWVOL].ID ||
1102                fidp->volume == volp->vol[ROVOL].ID ||
1103                fidp->volume == volp->vol[BACKVOL].ID))
1104             break;
1105     }
1106 #endif /* SEARCH_ALL_VOLUMES */
1107
1108     hash = CM_VOLUME_ID_HASH(fidp->volume);
1109     /* The volumeID can be any one of the three types.  So we must
1110      * search the hash table for all three types until we find it.
1111      * We will search in the order of RO, RW, BK.
1112      */
1113     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
1114         if ( cellp == volp->cellp && fidp->volume == volp->vol[ROVOL].ID )
1115             break;
1116     }
1117     if (!volp) {
1118         /* try RW volumes */
1119         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
1120             if ( cellp == volp->cellp && fidp->volume == volp->vol[RWVOL].ID )
1121                 break;
1122         }
1123     }
1124     if (!volp) {
1125         /* try BK volumes */
1126         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
1127             if ( cellp == volp->cellp && fidp->volume == volp->vol[BACKVOL].ID )
1128                 break;
1129         }
1130     }
1131
1132 #ifdef SEARCH_ALL_VOLUMES
1133     osi_assertx(volp == volp2, "unexpected cm_vol_t");
1134 #endif
1135     /* hold the volume if we found it */
1136     if (volp)
1137         cm_GetVolume(volp);
1138
1139     lock_ReleaseRead(&cm_volumeLock);
1140
1141     if (!volp)
1142         return CM_ERROR_NOSUCHVOLUME;
1143
1144     /* update it */
1145     cm_data.mountRootGen = time(NULL);
1146     lock_ObtainWrite(&volp->rw);
1147     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1148     volp->lastUpdateTime = 0;
1149
1150     code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1151     lock_ReleaseWrite(&volp->rw);
1152
1153     lock_ObtainRead(&cm_volumeLock);
1154     cm_PutVolume(volp);
1155     lock_ReleaseRead(&cm_volumeLock);
1156
1157     return code;
1158 }
1159
1160 /* find the appropriate servers from a volume */
1161 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volid, cm_user_t *userp, cm_req_t *reqp, afs_uint32 *replicated)
1162 {
1163     cm_serverRef_t **serverspp;
1164     cm_serverRef_t *current;
1165     int firstTry = 1;
1166     cm_vol_state_t *volstatep = NULL;
1167
1168   start:
1169     volstatep = cm_VolumeStateByID(volp, volid);
1170
1171     lock_ObtainWrite(&cm_serverLock);
1172     if (volstatep) {
1173         if (replicated)
1174             *replicated = (volstatep->flags & CM_VOL_STATE_FLAG_REPLICATED);
1175         serverspp = &volstatep->serversp;
1176     } else {
1177         lock_ReleaseWrite(&cm_serverLock);
1178         if (firstTry) {
1179             afs_int32 code;
1180             firstTry = 0;
1181             lock_ObtainWrite(&volp->rw);
1182             _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1183             volp->lastUpdateTime = 0;
1184             code = cm_UpdateVolumeLocation(volp->cellp, userp, reqp, volp);
1185             lock_ReleaseWrite(&volp->rw);
1186             if (code == 0)
1187                 goto start;
1188         }
1189         return NULL;
1190     }
1191
1192     /*
1193      * Increment the refCount on deleted items as well.
1194      * They will be freed by cm_FreeServerList when they get to zero
1195      */
1196     for (current = *serverspp; current; current = current->next)
1197         cm_GetServerRef(current, TRUE);
1198
1199     lock_ReleaseWrite(&cm_serverLock);
1200
1201     return serverspp;
1202 }
1203
1204 void cm_PutVolume(cm_volume_t *volp)
1205 {
1206     afs_int32 refCount = InterlockedDecrement(&volp->refCount);
1207     osi_assertx(refCount >= 0, "cm_volume_t refCount underflow has occurred");
1208 }
1209
1210 /* return the read-only volume, if there is one, or the read-write volume if
1211  * not.
1212  */
1213 long cm_GetROVolumeID(cm_volume_t *volp)
1214 {
1215     long id;
1216
1217     lock_ObtainRead(&volp->rw);
1218     if (volp->vol[ROVOL].ID && !cm_IsServerListEmpty(volp->vol[ROVOL].serversp))
1219         id = volp->vol[ROVOL].ID;
1220     else
1221         id = volp->vol[RWVOL].ID;
1222     lock_ReleaseRead(&volp->rw);
1223
1224     return id;
1225 }
1226
1227 void cm_RefreshVolumes(int lifetime)
1228 {
1229     cm_volume_t *volp;
1230     afs_int32 refCount;
1231     time_t now;
1232
1233     now = time(NULL);
1234
1235     /* force mount point target updates */
1236     if (cm_data.mountRootGen + lifetime <= now)
1237         cm_data.mountRootGen = now;
1238
1239     /*
1240      * force a re-loading of volume data from the vldb
1241      * if the lifetime for the cached data has expired
1242      */
1243     lock_ObtainRead(&cm_volumeLock);
1244     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1245         cm_GetVolume(volp);
1246         lock_ReleaseRead(&cm_volumeLock);
1247
1248         if (!(volp->flags & CM_VOLUMEFLAG_RESET) ||
1249             (volp->flags & CM_VOLUMEFLAG_NOEXIST)) {
1250             lock_ObtainWrite(&volp->rw);
1251             if (volp->flags & CM_VOLUMEFLAG_NOEXIST) {
1252                 _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_NOEXIST);
1253             }
1254
1255             if (volp->flags & CM_VOLUMEFLAG_RO_MIXED) {
1256                 if (volp->lastUpdateTime + 300 <= now) {
1257                     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1258                     volp->lastUpdateTime = 0;
1259                 }
1260             } else {
1261                 if (volp->lastUpdateTime + lifetime <= now) {
1262                     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1263                     volp->lastUpdateTime = 0;
1264                 }
1265             }
1266             lock_ReleaseWrite(&volp->rw);
1267         }
1268
1269         lock_ObtainRead(&cm_volumeLock);
1270         cm_PutVolume(volp);
1271     }
1272     lock_ReleaseRead(&cm_volumeLock);
1273 }
1274
1275 void
1276 cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
1277                            afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
1278 {
1279     cm_conn_t *connp;
1280     long code;
1281     AFSFetchVolumeStatus volStat;
1282     char *Name;
1283     char *OfflineMsg;
1284     char *MOTD;
1285     cm_req_t req;
1286     struct rx_connection * rxconnp;
1287     char volName[32];
1288     char offLineMsg[256];
1289     char motd[256];
1290     long alldown, alldeleted;
1291     cm_serverRef_t *serversp;
1292     cm_fid_t vfid;
1293     cm_scache_t *vscp = NULL;
1294
1295     Name = volName;
1296     OfflineMsg = offLineMsg;
1297     MOTD = motd;
1298
1299     if (statep->ID != 0 && (!volID || volID == statep->ID)) {
1300         /* create fid for volume root so that VNOVOL and VMOVED errors can be processed */
1301         cm_SetFid(&vfid, volp->cellp->cellID, statep->ID, 1, 1);
1302
1303         if (!statep->serversp && !(*volumeUpdatedp)) {
1304             cm_InitReq(&req);
1305             code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1306             *volumeUpdatedp = 1;
1307         }
1308
1309         lock_ObtainRead(&cm_serverLock);
1310         if (statep->serversp) {
1311             alldown = 1;
1312             alldeleted = 1;
1313             for (serversp = statep->serversp; serversp; serversp = serversp->next) {
1314                 if (serversp->status == srv_deleted)
1315                     continue;
1316
1317                 alldeleted = 0;
1318
1319                 if (!(serversp->server->flags & CM_SERVERFLAG_DOWN))
1320                     alldown = 0;
1321
1322                 if (serversp->status == srv_busy || serversp->status == srv_offline)
1323                     serversp->status = srv_not_busy;
1324             }
1325             lock_ReleaseRead(&cm_serverLock);
1326
1327             if (alldeleted && !(*volumeUpdatedp)) {
1328                 cm_InitReq(&req);
1329                 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1330                 *volumeUpdatedp = 1;
1331             }
1332
1333             if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
1334                 (!alldown && statep->state == vl_alldown)) {
1335                 cm_InitReq(&req);
1336                 req.flags |= CM_REQ_OFFLINE_VOL_CHK;
1337                 lock_ReleaseWrite(&volp->rw);
1338
1339                 code = cm_GetSCache(&vfid, NULL, &vscp, cm_rootUserp, &req);
1340                 if (code = 0) {
1341                     lock_ObtainWrite(&vscp->rw);
1342                     code = cm_SyncOp(vscp, NULL, cm_rootUserp, &req, PRSFS_READ,
1343                                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1344                     lock_ReleaseWrite(&vscp->rw);
1345                     if (code == 0) {
1346                         do {
1347                             code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
1348                             if (code)
1349                                 continue;
1350
1351                             rxconnp = cm_GetRxConn(connp);
1352                             code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
1353                                                          &volStat, &Name, &OfflineMsg, &MOTD);
1354                             rx_PutConnection(rxconnp);
1355                         } while (cm_Analyze(connp, cm_rootUserp, &req, &vfid, NULL, 0, NULL, NULL, NULL, code));
1356                         code = cm_MapRPCError(code, &req);
1357                     }
1358
1359                     lock_ObtainWrite(&vscp->rw);
1360                     cm_SyncOpDone(vscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1361                     lock_ReleaseWrite(&vscp->rw);
1362                     cm_ReleaseSCache(vscp);
1363                 }
1364                 lock_ObtainWrite(&volp->rw);
1365                 if (code == 0 && volStat.Online) {
1366                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
1367                     statep->state = vl_online;
1368                     *onlinep = 1;
1369                 } else if (code == CM_ERROR_NOACCESS) {
1370                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
1371                     statep->state = vl_unknown;
1372                     *onlinep = 1;
1373                 }
1374             } else if (alldown && statep->state != vl_alldown) {
1375                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1376                 statep->state = vl_alldown;
1377             }
1378         } else {
1379             lock_ReleaseRead(&cm_serverLock);
1380             if (statep->state != vl_alldown) {
1381                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1382                 statep->state = vl_alldown;
1383             }
1384         }
1385     }
1386 }
1387
1388 /* The return code is 0 if the volume is not online and
1389  * 1 if the volume is online
1390  */
1391 long
1392 cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
1393 {
1394     long code;
1395     cm_req_t req;
1396     afs_uint32 online = 0;
1397     afs_uint32 volumeUpdated = 0;
1398
1399     lock_ObtainWrite(&volp->rw);
1400
1401     if (volp->flags & CM_VOLUMEFLAG_RESET) {
1402         cm_InitReq(&req);
1403         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1404         volumeUpdated = 1;
1405     }
1406
1407     cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
1408     cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
1409     cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
1410
1411     lock_ReleaseWrite(&volp->rw);
1412     return online;
1413 }
1414
1415
1416 /*
1417  * called from the Daemon thread.
1418  * when checking the offline status, check those of the most recently used volumes first.
1419  */
1420 void cm_CheckOfflineVolumes(void)
1421 {
1422     cm_volume_t *volp;
1423     afs_int32 refCount;
1424     extern int daemon_ShutdownFlag;
1425     extern int powerStateSuspended;
1426
1427     lock_ObtainRead(&cm_volumeLock);
1428     for (volp = cm_data.volumeLRULastp;
1429          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1430          volp=(cm_volume_t *) osi_QPrev(&volp->q)) {
1431         /*
1432          * Skip volume entries that did not exist last time
1433          * the vldb was queried.  For those entries wait until
1434          * the next actual request is received for the volume
1435          * before checking its state.
1436          */
1437         if ((volp->qflags & CM_VOLUME_QFLAG_IN_HASH) &&
1438             !(volp->flags & CM_VOLUMEFLAG_NOEXIST)) {
1439             cm_GetVolume(volp);
1440             lock_ReleaseRead(&cm_volumeLock);
1441             cm_CheckOfflineVolume(volp, 0);
1442             lock_ObtainRead(&cm_volumeLock);
1443             cm_PutVolume(volp);
1444         }
1445     }
1446     lock_ReleaseRead(&cm_volumeLock);
1447 }
1448
1449
1450 static void
1451 cm_UpdateVolumeStatusInt(cm_volume_t *volp, struct cm_vol_state *statep)
1452 {
1453     enum volstatus newStatus;
1454     cm_serverRef_t *tsrp;
1455     cm_server_t *tsp;
1456     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
1457     char addr[16];
1458
1459     if (!volp || !statep) {
1460 #ifdef DEBUG
1461         DebugBreak();
1462 #endif
1463         return;
1464     }
1465
1466     lock_ObtainWrite(&cm_serverLock);
1467     for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1468         tsp = tsrp->server;
1469         sprintf(addr, "%d.%d.%d.%d",
1470                  ((tsp->addr.sin_addr.s_addr & 0xff)),
1471                  ((tsp->addr.sin_addr.s_addr & 0xff00)>> 8),
1472                  ((tsp->addr.sin_addr.s_addr & 0xff0000)>> 16),
1473                  ((tsp->addr.sin_addr.s_addr & 0xff000000)>> 24));
1474
1475         if (tsrp->status == srv_deleted) {
1476             osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s deleted",
1477                      statep->ID, osi_LogSaveString(afsd_logp,addr));
1478             continue;
1479         }
1480         if (tsp) {
1481             cm_GetServerNoLock(tsp);
1482             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
1483                 allDown = 0;
1484                 if (tsrp->status == srv_busy) {
1485                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s busy",
1486                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1487                     allOffline = 0;
1488                     someBusy = 1;
1489                 } else if (tsrp->status == srv_offline) {
1490                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s offline",
1491                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1492                     allBusy = 0;
1493                     someOffline = 1;
1494                 } else {
1495                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s online",
1496                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1497                     allOffline = 0;
1498                     allBusy = 0;
1499                 }
1500             } else {
1501                 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s down",
1502                           statep->ID, osi_LogSaveString(afsd_logp,addr));
1503             }
1504             cm_PutServerNoLock(tsp);
1505         }
1506     }
1507     lock_ReleaseWrite(&cm_serverLock);
1508
1509     osi_Log5(afsd_logp, "cm_UpdateVolumeStatusInt allDown %d allBusy %d someBusy %d someOffline %d allOffline %d",
1510              allDown, allBusy, someBusy, someOffline, allOffline);
1511
1512     if (allDown)
1513         newStatus = vl_alldown;
1514     else if (allBusy || (someBusy && someOffline))
1515         newStatus = vl_busy;
1516     else if (allOffline)
1517         newStatus = vl_offline;
1518     else
1519         newStatus = vl_online;
1520
1521     if (statep->ID && statep->state != newStatus)
1522         cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
1523
1524     statep->state = newStatus;
1525 }
1526
1527 void
1528 cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1529 {
1530
1531     if (volp->vol[RWVOL].ID == volID) {
1532         cm_UpdateVolumeStatusInt(volp, &volp->vol[RWVOL]);
1533     } else if (volp->vol[ROVOL].ID == volID) {
1534         cm_UpdateVolumeStatusInt(volp, &volp->vol[ROVOL]);
1535     } else if (volp->vol[BACKVOL].ID == volID) {
1536         cm_UpdateVolumeStatusInt(volp, &volp->vol[BACKVOL]);
1537     } else {
1538         /*
1539          * If we are called with volID == 0 then something has gone wrong.
1540          * Most likely a race occurred in the server volume list maintenance.
1541          * Since we don't know which volume's status should be updated,
1542          * just update all of them that are known to exist.  Better to be
1543          * correct than fast.
1544          */
1545         afs_uint32 volType;
1546         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1547             if (volp->vol[volType].ID != 0)
1548                 cm_UpdateVolumeStatusInt(volp, &volp->vol[volType]);
1549         }
1550     }
1551 }
1552
1553 /*
1554 ** Finds all volumes that reside on this server and reorders their
1555 ** RO list according to the changed rank of server.
1556 */
1557 void cm_ChangeRankVolume(cm_server_t *tsp)
1558 {
1559     int                 code;
1560     cm_volume_t*        volp;
1561     afs_int32 refCount;
1562
1563     /* find volumes which might have RO copy on server*/
1564     lock_ObtainRead(&cm_volumeLock);
1565     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1566     {
1567         code = 1 ;      /* assume that list is unchanged */
1568         cm_GetVolume(volp);
1569         lock_ReleaseRead(&cm_volumeLock);
1570         lock_ObtainWrite(&volp->rw);
1571
1572         if ((tsp->cellp==volp->cellp) && (volp->vol[ROVOL].serversp))
1573             code =cm_ChangeRankServer(&volp->vol[ROVOL].serversp, tsp);
1574
1575         /* this volume list was changed */
1576         if ( !code )
1577             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
1578
1579         lock_ReleaseWrite(&volp->rw);
1580         lock_ObtainRead(&cm_volumeLock);
1581         cm_PutVolume(volp);
1582     }
1583     lock_ReleaseRead(&cm_volumeLock);
1584 }
1585
1586 /* dump all volumes that have reference count > 0 to a file.
1587  * cookie is used to identify this batch for easy parsing,
1588  * and it a string provided by a caller
1589  */
1590 int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
1591 {
1592     int zilch;
1593     cm_volume_t *volp;
1594     char output[1024];
1595
1596     if (lock) {
1597         lock_ObtainRead(&cm_scacheLock);
1598         lock_ObtainRead(&cm_volumeLock);
1599     }
1600
1601     sprintf(output, "%s - dumping volumes - cm_data.currentVolumes=%d, cm_data.maxVolumes=%d\r\n",
1602             cookie, cm_data.currentVolumes, cm_data.maxVolumes);
1603     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1604
1605     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1606     {
1607         time_t t;
1608         char *srvStr = NULL;
1609         afs_uint32 srvStrRpc = TRUE;
1610         char *cbt = NULL;
1611         char *cdrot = NULL;
1612
1613         if (volp->cbServerpRO) {
1614             if (!((volp->cbServerpRO->flags & CM_SERVERFLAG_UUID) &&
1615                 UuidToString((UUID *)&volp->cbServerpRO->uuid, &srvStr) == RPC_S_OK)) {
1616                 srvStr = malloc(16);
1617                 if (srvStr != NULL)
1618                     afs_inet_ntoa_r(volp->cbServerpRO->addr.sin_addr.s_addr, srvStr);
1619                 srvStrRpc = FALSE;
1620             }
1621         }
1622         if (volp->cbExpiresRO) {
1623             t = volp->cbExpiresRO;
1624             cbt = ctime(&t);
1625             if (cbt) {
1626                 cbt = strdup(cbt);
1627                 cbt[strlen(cbt)-1] = '\0';
1628             }
1629         }
1630         if (volp->creationDateRO) {
1631             t = volp->creationDateRO;
1632             cdrot = ctime(&t);
1633             if (cdrot) {
1634                 cdrot = strdup(cdrot);
1635                 cdrot[strlen(cdrot)-1] = '\0';
1636             }
1637         }
1638
1639         sprintf(output,
1640                 "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x:%x "
1641                 "cbServerpRO='%s' cbExpiresRO='%s' creationDateRO='%s' refCount=%u\r\n",
1642                  cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID,
1643                  volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags, volp->qflags,
1644                  srvStr ? srvStr : "<none>", cbt ? cbt : "<none>", cdrot ? cdrot : "<none>",
1645                  volp->refCount);
1646         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1647
1648         if (srvStr) {
1649             if (srvStrRpc)
1650                 RpcStringFree(&srvStr);
1651             else
1652                 free(srvStr);
1653         }
1654         if (cbt)
1655             free(cbt);
1656         if (cdrot)
1657             free(cdrot);
1658     }
1659     sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
1660     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1661
1662     if (lock) {
1663         lock_ReleaseRead(&cm_volumeLock);
1664         lock_ReleaseRead(&cm_scacheLock);
1665     }
1666     return (0);
1667 }
1668
1669
1670 /*
1671  * String hash function used by SDBM project.
1672  * It was chosen because it is fast and provides
1673  * decent coverage.
1674  */
1675 afs_uint32 SDBMHash(const char * str)
1676 {
1677     afs_uint32 hash = 0;
1678     size_t i, len;
1679
1680     if (str == NULL)
1681         return 0;
1682
1683     for(i = 0, len = strlen(str); i < len; i++)
1684     {
1685         hash = str[i] + (hash << 6) + (hash << 16) - hash;
1686     }
1687
1688     return (hash & 0x7FFFFFFF);
1689 }
1690
1691 /* call with volume write-locked and mutex held */
1692 void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
1693 {
1694     int i;
1695
1696     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
1697         return;
1698
1699     i = CM_VOLUME_NAME_HASH(volp->namep);
1700
1701     volp->nameNextp = cm_data.volumeNameHashTablep[i];
1702     cm_data.volumeNameHashTablep[i] = volp;
1703     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_HASH);
1704 }
1705
1706 /* call with volume write-locked and mutex held */
1707 void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
1708 {
1709     cm_volume_t **lvolpp;
1710     cm_volume_t *tvolp;
1711     int i;
1712
1713     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1714         /* hash it out first */
1715         i = CM_VOLUME_NAME_HASH(volp->namep);
1716         for (lvolpp = &cm_data.volumeNameHashTablep[i], tvolp = cm_data.volumeNameHashTablep[i];
1717              tvolp;
1718              lvolpp = &tvolp->nameNextp, tvolp = tvolp->nameNextp) {
1719             if (tvolp == volp) {
1720                 *lvolpp = volp->nameNextp;
1721                 _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1722                 volp->nameNextp = NULL;
1723                 break;
1724             }
1725         }
1726     }
1727 }
1728
1729 /* call with volume write-locked and mutex held */
1730 void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1731 {
1732     int i;
1733     struct cm_vol_state * statep;
1734
1735     statep = cm_VolumeStateByType(volp, volType);
1736
1737     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH)
1738         return;
1739
1740     i = CM_VOLUME_ID_HASH(statep->ID);
1741
1742     switch (volType) {
1743     case RWVOL:
1744         statep->nextp = cm_data.volumeRWIDHashTablep[i];
1745         cm_data.volumeRWIDHashTablep[i] = volp;
1746         break;
1747     case ROVOL:
1748         statep->nextp = cm_data.volumeROIDHashTablep[i];
1749         cm_data.volumeROIDHashTablep[i] = volp;
1750         break;
1751     case BACKVOL:
1752         statep->nextp = cm_data.volumeBKIDHashTablep[i];
1753         cm_data.volumeBKIDHashTablep[i] = volp;
1754         break;
1755     }
1756     _InterlockedOr(&statep->qflags, CM_VOLUME_QFLAG_IN_HASH);
1757 }
1758
1759
1760 /* call with volume write-locked and mutex held */
1761 void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1762 {
1763     cm_volume_t **lvolpp;
1764     cm_volume_t *tvolp;
1765     struct cm_vol_state * statep;
1766     int i;
1767
1768     statep = cm_VolumeStateByType(volp, volType);
1769
1770     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1771         /* hash it out first */
1772         i = CM_VOLUME_ID_HASH(statep->ID);
1773
1774         switch (volType) {
1775         case RWVOL:
1776             lvolpp = &cm_data.volumeRWIDHashTablep[i];
1777             tvolp = cm_data.volumeRWIDHashTablep[i];
1778             break;
1779         case ROVOL:
1780             lvolpp = &cm_data.volumeROIDHashTablep[i];
1781             tvolp = cm_data.volumeROIDHashTablep[i];
1782             break;
1783         case BACKVOL:
1784             lvolpp = &cm_data.volumeBKIDHashTablep[i];
1785             tvolp = cm_data.volumeBKIDHashTablep[i];
1786             break;
1787         default:
1788             osi_assertx(0, "invalid volume type");
1789         }
1790         do {
1791             if (tvolp == volp) {
1792                 *lvolpp = statep->nextp;
1793                 _InterlockedAnd(&statep->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1794                 statep->nextp = NULL;
1795                 break;
1796             }
1797
1798             lvolpp = &tvolp->vol[volType].nextp;
1799             tvolp = tvolp->vol[volType].nextp;
1800         } while(tvolp);
1801     }
1802 }
1803
1804 /* must be called with cm_volumeLock write-locked! */
1805 void cm_AdjustVolumeLRU(cm_volume_t *volp)
1806 {
1807     lock_AssertWrite(&cm_volumeLock);
1808
1809     if (volp == cm_data.volumeLRUFirstp)
1810         return;
1811
1812     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1813         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1814     osi_QAddH((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1815     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1816
1817     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1818 }
1819
1820 /* must be called with cm_volumeLock write-locked! */
1821 void cm_MoveVolumeToLRULast(cm_volume_t *volp)
1822 {
1823     lock_AssertWrite(&cm_volumeLock);
1824
1825     if (volp == cm_data.volumeLRULastp)
1826         return;
1827
1828     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1829         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1830     osi_QAddT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1831     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1832
1833     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1834 }
1835
1836 /* must be called with cm_volumeLock write-locked! */
1837 void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
1838 {
1839     lock_AssertWrite(&cm_volumeLock);
1840
1841     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) {
1842         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1843         _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1844     }
1845
1846     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1847 }
1848
1849 static char * volstatus_str(enum volstatus vs)
1850 {
1851     switch (vs) {
1852     case vl_online:
1853         return "online";
1854     case vl_busy:
1855         return "busy";
1856     case vl_offline:
1857         return "offline";
1858     case vl_alldown:
1859         return "alldown";
1860     default:
1861         return "unknown";
1862     }
1863 }
1864
1865 void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
1866 {
1867     char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN]="";
1868     char *ext = "";
1869
1870     if (volID == volp->vol[RWVOL].ID)
1871         ext = "";
1872     else if (volID == volp->vol[ROVOL].ID)
1873         ext = ".readonly";
1874     else if (volID == volp->vol[BACKVOL].ID)
1875         ext = ".backup";
1876     else
1877         ext = ".nomatch";
1878     snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
1879
1880     osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
1881              osi_LogSaveString(afsd_logp, volstr), volID, volstatus_str(old), volstatus_str(new));
1882
1883     cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new);
1884 }
1885
1886 enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1887 {
1888     cm_vol_state_t * statep = cm_VolumeStateByID(volp, volID);
1889     if (statep)
1890         return statep->state;
1891     else
1892         return vl_unknown;
1893 }
1894
1895 /* Renew .readonly volume callbacks that are more than
1896  * 30 minutes old.  (A volume callback is issued for 2 hours.)
1897  */
1898 void
1899 cm_VolumeRenewROCallbacks(void)
1900 {
1901     cm_volume_t * volp;
1902     time_t minexp = time(NULL) + 90 * 60;
1903     extern int daemon_ShutdownFlag;
1904     extern int powerStateSuspended;
1905
1906     lock_ObtainRead(&cm_volumeLock);
1907     for (volp = cm_data.allVolumesp;
1908          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1909          volp=volp->allNextp) {
1910         if ( volp->cbExpiresRO > 0 && volp->cbExpiresRO < minexp) {
1911             cm_req_t      req;
1912             cm_fid_t      fid;
1913             cm_scache_t * scp;
1914
1915             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
1916
1917             cm_InitReq(&req);
1918
1919             lock_ReleaseRead(&cm_volumeLock);
1920             if (cm_GetSCache(&fid, NULL, &scp, cm_rootUserp, &req) == 0) {
1921                 lock_ObtainWrite(&scp->rw);
1922                 cm_GetCallback(scp, cm_rootUserp, &req, 1);
1923                 lock_ReleaseWrite(&scp->rw);
1924                 cm_ReleaseSCache(scp);
1925             }
1926             lock_ObtainRead(&cm_volumeLock);
1927         }
1928     }
1929     lock_ReleaseRead(&cm_volumeLock);
1930 }
1931
1932 cm_vol_state_t *
1933 cm_VolumeStateByType(cm_volume_t *volp, afs_uint32 volType)
1934 {
1935     return &volp->vol[volType];
1936 }
1937
1938 cm_vol_state_t *
1939 cm_VolumeStateByID(cm_volume_t *volp, afs_uint32 id)
1940 {
1941     cm_vol_state_t * statep = NULL;
1942
1943     if (id == volp->vol[RWVOL].ID)
1944         statep = &volp->vol[RWVOL];
1945     else if (id == volp->vol[ROVOL].ID)
1946         statep = &volp->vol[ROVOL];
1947     else if (id == volp->vol[BACKVOL].ID)
1948         statep = &volp->vol[BACKVOL];
1949
1950     return(statep);
1951 }
1952
1953 cm_vol_state_t *
1954 cm_VolumeStateByName(cm_volume_t *volp, char *volname)
1955 {
1956     size_t len = strlen(volname);
1957     cm_vol_state_t *statep;
1958
1959     if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
1960         statep = &volp->vol[ROVOL];
1961     else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
1962         statep = &volp->vol[BACKVOL];
1963     else
1964         statep = &volp->vol[RWVOL];
1965
1966     return statep;
1967 }
1968
1969 afs_int32
1970 cm_VolumeType(cm_volume_t *volp, afs_uint32 id)
1971 {
1972     if (id == volp->vol[RWVOL].ID)
1973         return(RWVOL);
1974     else if (id == volp->vol[ROVOL].ID)
1975         return(ROVOL);
1976     else if (id == volp->vol[BACKVOL].ID)
1977         return (BACKVOL);
1978
1979     return -1;
1980 }
1981
1982 LONG_PTR
1983 cm_ChecksumVolumeServerList(struct cm_fid *fidp, cm_user_t *userp, cm_req_t *reqp)
1984 {
1985     LONG_PTR cksum = 0;
1986     long code;
1987     afs_uint32 replicated;
1988     cm_serverRef_t **serverspp;
1989
1990     code = cm_GetServerList(fidp, userp, reqp, &replicated, &serverspp);
1991     if (code == 0) {
1992         cksum = cm_ChecksumServerList(*serverspp);
1993         cm_FreeServerList(serverspp, 0);
1994     }
1995     return cksum;
1996 }
1997
1998 afs_int32
1999 cm_IsVolumeReplicated(cm_fid_t *fidp)
2000 {
2001     afs_int32 replicated = 0;
2002     cm_volume_t *volp;
2003     cm_vol_state_t * volstatep;
2004
2005     volp = cm_GetVolumeByFID(fidp);
2006     if (volp) {
2007         volstatep = cm_VolumeStateByID(volp, fidp->volume);
2008         replicated = (volstatep->flags & CM_VOL_STATE_FLAG_REPLICATED);
2009         cm_PutVolume(volp);
2010     }
2011
2012     return replicated;
2013 }