66692a4f303f70ce9db40a5f45dae71c3f1c91ed
[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     if (volp->vol[RWVOL].state != rwNewstate) {
683         if (volp->vol[RWVOL].ID)
684             cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, rwNewstate);
685         volp->vol[RWVOL].state = rwNewstate;
686     }
687     if (volp->vol[ROVOL].state != roNewstate) {
688         if (volp->vol[ROVOL].ID)
689             cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, roNewstate);
690         volp->vol[ROVOL].state = roNewstate;
691     }
692     if (volp->vol[BACKVOL].state != bkNewstate) {
693         if (volp->vol[BACKVOL].ID)
694             cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, bkNewstate);
695         volp->vol[BACKVOL].state = bkNewstate;
696     }
697
698     volp->lastUpdateTime = time(NULL);
699     if (isMixed)
700         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_MIXED);
701     else
702         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_MIXED);
703
704     if (code == 0)
705         _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RESET);
706
707     _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_UPDATING_VL);
708     osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x",
709              osi_LogSaveString(afsd_logp,volp->cellp->name),
710              osi_LogSaveString(afsd_logp,volp->namep), volp->flags, code);
711     osi_Wakeup((LONG_PTR) &volp->flags);
712
713     return code;
714 }
715
716 /* Requires read or write lock on cm_volumeLock */
717 void cm_GetVolume(cm_volume_t *volp)
718 {
719     InterlockedIncrement(&volp->refCount);
720 }
721
722 cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
723 {
724     cm_volume_t *volp;
725     afs_uint32 hash;
726
727     lock_ObtainRead(&cm_volumeLock);
728     hash = CM_VOLUME_ID_HASH(fidp->volume);
729     /* The volumeID can be any one of the three types.  So we must
730      * search the hash table for all three types until we find it.
731      * We will search in the order of RO, RW, BK.
732      */
733     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
734         if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[ROVOL].ID )
735             break;
736     }
737     if (!volp) {
738         /* try RW volumes */
739         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
740             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[RWVOL].ID )
741                 break;
742         }
743     }
744     if (!volp) {
745         /* try BK volumes */
746         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
747             if ( fidp->cell == volp->cellp->cellID && fidp->volume == volp->vol[BACKVOL].ID )
748                 break;
749         }
750     }
751
752     /* hold the volume if we found it */
753     if (volp)
754         cm_GetVolume(volp);
755
756     lock_ReleaseRead(&cm_volumeLock);
757     return volp;
758 }
759
760 long cm_FindVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
761                       cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
762 {
763     cm_volume_t *volp;
764 #ifdef SEARCH_ALL_VOLUMES
765     cm_volume_t *volp2;
766 #endif
767     char volNameString[VL_MAXNAMELEN];
768     afs_uint32 hash;
769     long code = 0;
770
771     lock_ObtainRead(&cm_volumeLock);
772 #ifdef SEARCH_ALL_VOLUMES
773     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
774         if (cellp == volp->cellp &&
775              ((unsigned) volumeID == volp->vol[RWVOL].ID ||
776                (unsigned) volumeID == volp->vol[ROVOL].ID ||
777                (unsigned) volumeID == volp->vol[BACKVOL].ID))
778             break;
779     }
780
781     volp2 = volp;
782 #endif /* SEARCH_ALL_VOLUMES */
783
784     hash = CM_VOLUME_ID_HASH(volumeID);
785     /* The volumeID can be any one of the three types.  So we must
786      * search the hash table for all three types until we find it.
787      * We will search in the order of RO, RW, BK.
788      */
789     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
790         if ( cellp == volp->cellp && volumeID == volp->vol[ROVOL].ID )
791             break;
792     }
793     if (!volp) {
794         /* try RW volumes */
795         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
796             if ( cellp == volp->cellp && volumeID == volp->vol[RWVOL].ID )
797                 break;
798         }
799     }
800     if (!volp) {
801         /* try BK volumes */
802         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
803             if ( cellp == volp->cellp && volumeID == volp->vol[BACKVOL].ID )
804                 break;
805         }
806     }
807
808 #ifdef SEARCH_ALL_VOLUMES
809     osi_assertx(volp == volp2, "unexpected cm_vol_t");
810 #endif
811
812     /* hold the volume if we found it */
813     if (volp)
814         cm_GetVolume(volp);
815
816     lock_ReleaseRead(&cm_volumeLock);
817
818     /* return it held */
819     if (volp) {
820         lock_ObtainWrite(&volp->rw);
821
822         code = 0;
823         if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
824             code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
825         }
826         lock_ReleaseWrite(&volp->rw);
827         if (code == 0) {
828             *outVolpp = volp;
829
830             if (!(flags & CM_GETVOL_FLAG_NO_LRU_UPDATE)) {
831                 lock_ObtainWrite(&cm_volumeLock);
832                 cm_AdjustVolumeLRU(volp);
833                 lock_ReleaseWrite(&cm_volumeLock);
834             }
835         } else {
836             lock_ObtainRead(&cm_volumeLock);
837             cm_PutVolume(volp);
838             lock_ReleaseRead(&cm_volumeLock);
839         }
840         return code;
841     }
842
843     /* otherwise, we didn't find it so consult the VLDB */
844     sprintf(volNameString, "%u", volumeID);
845     code = cm_FindVolumeByName(cellp, volNameString, userp, reqp,
846                               flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL, outVolpp);
847
848     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
849         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
850         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
851
852         if (linkedCellp)
853             code = cm_FindVolumeByID(linkedCellp, volumeID, userp, reqp,
854                                      flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
855                                      outVolpp);
856     }
857     return code;
858 }
859
860
861 long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
862                         struct cm_user *userp, struct cm_req *reqp,
863                         afs_uint32 flags, cm_volume_t **outVolpp)
864 {
865     cm_volume_t *volp;
866 #ifdef SEARCH_ALL_VOLUMES
867     cm_volume_t *volp2;
868 #endif
869     long        code = 0;
870     char        name[VL_MAXNAMELEN];
871     size_t      len;
872     int         type;
873     afs_uint32  hash;
874
875     strncpy(name, volumeNamep, VL_MAXNAMELEN);
876     name[VL_MAXNAMELEN-1] = '\0';
877     len = strlen(name);
878
879     if (len >= 8 && strcmp(name + len - 7, ".backup") == 0) {
880         type = BACKVOL;
881         name[len - 7] = '\0';
882     } else if (len >= 10 && strcmp(name + len - 9, ".readonly") == 0) {
883         type = ROVOL;
884         name[len - 9] = '\0';
885     } else {
886         type = RWVOL;
887     }
888
889     lock_ObtainRead(&cm_volumeLock);
890 #ifdef SEARCH_ALL_VOLUMES
891     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
892         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0) {
893             break;
894         }
895     }
896     volp2 = volp;
897 #endif /* SEARCH_ALL_VOLUMES */
898
899     hash = CM_VOLUME_NAME_HASH(name);
900     for (volp = cm_data.volumeNameHashTablep[hash]; volp; volp = volp->nameNextp) {
901         if (cellp == volp->cellp && strcmp(name, volp->namep) == 0)
902             break;
903     }
904
905 #ifdef SEARCH_ALL_VOLUMES
906     osi_assertx(volp2 == volp, "unexpected cm_vol_t");
907 #endif
908
909     if (!volp && (flags & CM_GETVOL_FLAG_CREATE)) {
910         afs_uint32 volType;
911         /* otherwise, get from VLDB */
912
913         /*
914          * Change to a write lock so that we have exclusive use of
915          * the first cm_volume_t with a refCount of 0 so that we
916          * have time to increment it.
917          */
918         lock_ConvertRToW(&cm_volumeLock);
919
920         if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
921 #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
922             for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
923                 if ( volp->refCount == 0 ) {
924                     /* There is one we can re-use */
925                     break;
926                 }
927             }
928 #else
929             for ( volp = cm_data.volumeLRULastp;
930                   volp;
931                   volp = (cm_volume_t *) osi_QPrev(&volp->q))
932             {
933                 if ( volp->refCount == 0 ) {
934                     /* There is one we can re-use */
935                     break;
936                 }
937             }
938 #endif
939             if (!volp)
940                 osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
941
942             InterlockedIncrement(&volp->refCount);
943             lock_ReleaseWrite(&cm_volumeLock);
944             lock_ObtainWrite(&volp->rw);
945             lock_ObtainWrite(&cm_volumeLock);
946
947             osi_Log2(afsd_logp, "Recycling Volume %s:%s",
948                      volp->cellp->name, volp->namep);
949
950             /* The volp is removed from the LRU queue in order to
951              * prevent two threads from attempting to recycle the
952              * same object.  This volp must be re-inserted back into
953              * the LRU queue before this function exits.
954              */
955             if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
956                 cm_RemoveVolumeFromLRU(volp);
957             if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
958                 cm_RemoveVolumeFromNameHashTable(volp);
959
960             for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
961                 if (volp->vol[volType].qflags & CM_VOLUME_QFLAG_IN_HASH)
962                     cm_RemoveVolumeFromIDHashTable(volp, volType);
963                 if (volp->vol[volType].ID)
964                     cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_unknown);
965                 volp->vol[volType].ID = 0;
966                 cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
967                 lock_ReleaseWrite(&cm_volumeLock);
968                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
969                 lock_ObtainWrite(&cm_volumeLock);
970             }
971         } else {
972             volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
973             memset(volp, 0, sizeof(cm_volume_t));
974             volp->magic = CM_VOLUME_MAGIC;
975             volp->allNextp = cm_data.allVolumesp;
976             cm_data.allVolumesp = volp;
977             lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
978             lock_ReleaseWrite(&cm_volumeLock);
979             lock_ObtainWrite(&volp->rw);
980             lock_ObtainWrite(&cm_volumeLock);
981             volp->refCount = 1; /* starts off held */
982         }
983         volp->cellp = cellp;
984         strncpy(volp->namep, name, VL_MAXNAMELEN);
985         volp->namep[VL_MAXNAMELEN-1] = '\0';
986         volp->flags = CM_VOLUMEFLAG_RESET;
987         volp->lastUpdateTime = 0;
988
989         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
990             volp->vol[volType].state = vl_unknown;
991             volp->vol[volType].nextp = NULL;
992             volp->vol[volType].flags = 0;
993         }
994         volp->cbExpiresRO = 0;
995         volp->cbIssuedRO = 0;
996         volp->cbServerpRO = NULL;
997         volp->creationDateRO = 0;
998         cm_AddVolumeToNameHashTable(volp);
999         lock_ReleaseWrite(&cm_volumeLock);
1000     }
1001     else {
1002         if (volp)
1003             cm_GetVolume(volp);
1004         lock_ReleaseRead(&cm_volumeLock);
1005
1006         if (!volp)
1007             return CM_ERROR_NOSUCHVOLUME;
1008
1009         lock_ObtainWrite(&volp->rw);
1010     }
1011
1012     /* if we get here we are holding the mutex */
1013     if ((volp->flags & CM_VOLUMEFLAG_RESET) && !(flags & CM_GETVOL_FLAG_NO_RESET)) {
1014         code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1015     }
1016     lock_ReleaseWrite(&volp->rw);
1017
1018     if (code == 0 && (type == BACKVOL && volp->vol[BACKVOL].ID == 0 ||
1019                       type == ROVOL && volp->vol[ROVOL].ID == 0))
1020         code = CM_ERROR_NOSUCHVOLUME;
1021
1022     if (code == 0) {
1023         *outVolpp = volp;
1024
1025         lock_ObtainWrite(&cm_volumeLock);
1026         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1027              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1028             cm_AdjustVolumeLRU(volp);
1029         lock_ReleaseWrite(&cm_volumeLock);
1030     } else {
1031         /*
1032          * do not return it to the caller but do insert it in the LRU
1033          * otherwise it will be lost
1034          */
1035         lock_ObtainWrite(&cm_volumeLock);
1036         if (!(volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) ||
1037              (flags & CM_GETVOL_FLAG_NO_LRU_UPDATE))
1038             cm_AdjustVolumeLRU(volp);
1039         cm_PutVolume(volp);
1040         lock_ReleaseWrite(&cm_volumeLock);
1041     }
1042
1043     if (code == CM_ERROR_NOSUCHVOLUME && cellp->linkedName[0] &&
1044         !(flags & CM_GETVOL_FLAG_IGNORE_LINKED_CELL)) {
1045         cm_cell_t *linkedCellp = cm_GetCell(cellp->linkedName, flags);
1046
1047         if (linkedCellp)
1048             code = cm_FindVolumeByName(linkedCellp, volumeNamep, userp, reqp,
1049                                        flags | CM_GETVOL_FLAG_IGNORE_LINKED_CELL,
1050                                        outVolpp);
1051     }
1052     return code;
1053 }
1054
1055 /*
1056  * Only call this function in response to a VNOVOL or VMOVED error
1057  * from a file server.  Do not call it in response to CM_ERROR_NOSUCHVOLUME
1058  * as that can lead to recursive calls.
1059  */
1060 long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
1061 {
1062     cm_cell_t *cellp;
1063     cm_volume_t *volp;
1064 #ifdef SEARCH_ALL_VOLUMES
1065     cm_volume_t *volp2;
1066 #endif
1067     afs_uint32  hash;
1068     long code;
1069
1070     if (!fidp)
1071         return CM_ERROR_INVAL;
1072
1073     cellp = cm_FindCellByID(fidp->cell, 0);
1074     if (!cellp)
1075         return CM_ERROR_NOSUCHCELL;
1076
1077     /* search for the volume */
1078     lock_ObtainRead(&cm_volumeLock);
1079 #ifdef SEARCH_ALL_VOLUMES
1080     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1081         if (cellp == volp->cellp &&
1082              (fidp->volume == volp->vol[RWVOL].ID ||
1083                fidp->volume == volp->vol[ROVOL].ID ||
1084                fidp->volume == volp->vol[BACKVOL].ID))
1085             break;
1086     }
1087 #endif /* SEARCH_ALL_VOLUMES */
1088
1089     hash = CM_VOLUME_ID_HASH(fidp->volume);
1090     /* The volumeID can be any one of the three types.  So we must
1091      * search the hash table for all three types until we find it.
1092      * We will search in the order of RO, RW, BK.
1093      */
1094     for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = volp->vol[ROVOL].nextp) {
1095         if ( cellp == volp->cellp && fidp->volume == volp->vol[ROVOL].ID )
1096             break;
1097     }
1098     if (!volp) {
1099         /* try RW volumes */
1100         for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = volp->vol[RWVOL].nextp) {
1101             if ( cellp == volp->cellp && fidp->volume == volp->vol[RWVOL].ID )
1102                 break;
1103         }
1104     }
1105     if (!volp) {
1106         /* try BK volumes */
1107         for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = volp->vol[BACKVOL].nextp) {
1108             if ( cellp == volp->cellp && fidp->volume == volp->vol[BACKVOL].ID )
1109                 break;
1110         }
1111     }
1112
1113 #ifdef SEARCH_ALL_VOLUMES
1114     osi_assertx(volp == volp2, "unexpected cm_vol_t");
1115 #endif
1116     /* hold the volume if we found it */
1117     if (volp)
1118         cm_GetVolume(volp);
1119
1120     lock_ReleaseRead(&cm_volumeLock);
1121
1122     if (!volp)
1123         return CM_ERROR_NOSUCHVOLUME;
1124
1125     /* update it */
1126     cm_data.mountRootGen = time(NULL);
1127     lock_ObtainWrite(&volp->rw);
1128     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1129     volp->lastUpdateTime = 0;
1130
1131     code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
1132     lock_ReleaseWrite(&volp->rw);
1133
1134     lock_ObtainRead(&cm_volumeLock);
1135     cm_PutVolume(volp);
1136     lock_ReleaseRead(&cm_volumeLock);
1137
1138     return code;
1139 }
1140
1141 /* find the appropriate servers from a volume */
1142 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volid, cm_user_t *userp, cm_req_t *reqp, afs_uint32 *replicated)
1143 {
1144     cm_serverRef_t **serverspp;
1145     cm_serverRef_t *current;
1146     int firstTry = 1;
1147     cm_vol_state_t *volstatep = NULL;
1148
1149   start:
1150     volstatep = cm_VolumeStateByID(volp, volid);
1151
1152     lock_ObtainWrite(&cm_serverLock);
1153     if (volstatep) {
1154         if (replicated)
1155             *replicated = (volstatep->flags & CM_VOL_STATE_FLAG_REPLICATED);
1156         serverspp = &volstatep->serversp;
1157     } else {
1158         lock_ReleaseWrite(&cm_serverLock);
1159         if (firstTry) {
1160             afs_int32 code;
1161             firstTry = 0;
1162             lock_ObtainWrite(&volp->rw);
1163             _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1164             volp->lastUpdateTime = 0;
1165             code = cm_UpdateVolumeLocation(volp->cellp, userp, reqp, volp);
1166             lock_ReleaseWrite(&volp->rw);
1167             if (code == 0)
1168                 goto start;
1169         }
1170         return NULL;
1171     }
1172
1173     /*
1174      * Increment the refCount on deleted items as well.
1175      * They will be freed by cm_FreeServerList when they get to zero
1176      */
1177     for (current = *serverspp; current; current = current->next)
1178         cm_GetServerRef(current, TRUE);
1179
1180     lock_ReleaseWrite(&cm_serverLock);
1181
1182     return serverspp;
1183 }
1184
1185 void cm_PutVolume(cm_volume_t *volp)
1186 {
1187     afs_int32 refCount = InterlockedDecrement(&volp->refCount);
1188     osi_assertx(refCount >= 0, "cm_volume_t refCount underflow has occurred");
1189 }
1190
1191 /* return the read-only volume, if there is one, or the read-write volume if
1192  * not.
1193  */
1194 long cm_GetROVolumeID(cm_volume_t *volp)
1195 {
1196     long id;
1197
1198     lock_ObtainRead(&volp->rw);
1199     if (volp->vol[ROVOL].ID && !cm_IsServerListEmpty(volp->vol[ROVOL].serversp))
1200         id = volp->vol[ROVOL].ID;
1201     else
1202         id = volp->vol[RWVOL].ID;
1203     lock_ReleaseRead(&volp->rw);
1204
1205     return id;
1206 }
1207
1208 void cm_RefreshVolumes(int lifetime)
1209 {
1210     cm_volume_t *volp;
1211     afs_int32 refCount;
1212     time_t now;
1213
1214     now = time(NULL);
1215
1216     /* force mount point target updates */
1217     if (cm_data.mountRootGen + lifetime <= now)
1218         cm_data.mountRootGen = now;
1219
1220     /*
1221      * force a re-loading of volume data from the vldb
1222      * if the lifetime for the cached data has expired
1223      */
1224     lock_ObtainRead(&cm_volumeLock);
1225     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
1226         InterlockedIncrement(&volp->refCount);
1227         lock_ReleaseRead(&cm_volumeLock);
1228
1229         if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
1230             lock_ObtainWrite(&volp->rw);
1231             if (volp->flags & CM_VOLUMEFLAG_RO_MIXED) {
1232                 if (volp->lastUpdateTime + 300 <= now) {
1233                     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1234                     volp->lastUpdateTime = 0;
1235                 }
1236             } else {
1237                 if (volp->lastUpdateTime + lifetime <= now) {
1238                     _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RESET);
1239                     volp->lastUpdateTime = 0;
1240                 }
1241             }
1242             lock_ReleaseWrite(&volp->rw);
1243         }
1244
1245         lock_ObtainRead(&cm_volumeLock);
1246         refCount = InterlockedDecrement(&volp->refCount);
1247         osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1248     }
1249     lock_ReleaseRead(&cm_volumeLock);
1250 }
1251
1252 void
1253 cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
1254                            afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
1255 {
1256     cm_conn_t *connp;
1257     long code;
1258     AFSFetchVolumeStatus volStat;
1259     char *Name;
1260     char *OfflineMsg;
1261     char *MOTD;
1262     cm_req_t req;
1263     struct rx_connection * rxconnp;
1264     char volName[32];
1265     char offLineMsg[256];
1266     char motd[256];
1267     long alldown, alldeleted;
1268     cm_serverRef_t *serversp;
1269     cm_fid_t vfid;
1270     cm_scache_t *vscp = NULL;
1271
1272     Name = volName;
1273     OfflineMsg = offLineMsg;
1274     MOTD = motd;
1275
1276     if (statep->ID != 0 && (!volID || volID == statep->ID)) {
1277         /* create fid for volume root so that VNOVOL and VMOVED errors can be processed */
1278         cm_SetFid(&vfid, volp->cellp->cellID, statep->ID, 1, 1);
1279
1280         if (!statep->serversp && !(*volumeUpdatedp)) {
1281             cm_InitReq(&req);
1282             code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1283             *volumeUpdatedp = 1;
1284         }
1285
1286         lock_ObtainRead(&cm_serverLock);
1287         if (statep->serversp) {
1288             alldown = 1;
1289             alldeleted = 1;
1290             for (serversp = statep->serversp; serversp; serversp = serversp->next) {
1291                 if (serversp->status == srv_deleted)
1292                     continue;
1293
1294                 alldeleted = 0;
1295
1296                 if (!(serversp->server->flags & CM_SERVERFLAG_DOWN))
1297                     alldown = 0;
1298
1299                 if (serversp->status == srv_busy || serversp->status == srv_offline)
1300                     serversp->status = srv_not_busy;
1301             }
1302             lock_ReleaseRead(&cm_serverLock);
1303
1304             if (alldeleted && !(*volumeUpdatedp)) {
1305                 cm_InitReq(&req);
1306                 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1307                 *volumeUpdatedp = 1;
1308             }
1309
1310             if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
1311                 (!alldown && statep->state == vl_alldown)) {
1312                 cm_InitReq(&req);
1313                 req.flags |= CM_REQ_OFFLINE_VOL_CHK;
1314                 lock_ReleaseWrite(&volp->rw);
1315
1316                 code = cm_GetSCache(&vfid, NULL, &vscp, cm_rootUserp, &req);
1317                 if (code = 0) {
1318                     lock_ObtainWrite(&vscp->rw);
1319                     code = cm_SyncOp(vscp, NULL, cm_rootUserp, &req, PRSFS_READ,
1320                                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1321                     lock_ReleaseWrite(&vscp->rw);
1322                     if (code == 0) {
1323                         do {
1324                             code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
1325                             if (code)
1326                                 continue;
1327
1328                             rxconnp = cm_GetRxConn(connp);
1329                             code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
1330                                                          &volStat, &Name, &OfflineMsg, &MOTD);
1331                             rx_PutConnection(rxconnp);
1332                         } while (cm_Analyze(connp, cm_rootUserp, &req, &vfid, NULL, 0, NULL, NULL, NULL, code));
1333                         code = cm_MapRPCError(code, &req);
1334                     }
1335
1336                     lock_ObtainWrite(&vscp->rw);
1337                     cm_SyncOpDone(vscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1338                     lock_ReleaseWrite(&vscp->rw);
1339                     cm_ReleaseSCache(vscp);
1340                 }
1341                 lock_ObtainWrite(&volp->rw);
1342                 if (code == 0 && volStat.Online) {
1343                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
1344                     statep->state = vl_online;
1345                     *onlinep = 1;
1346                 } else if (code == CM_ERROR_NOACCESS) {
1347                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
1348                     statep->state = vl_unknown;
1349                     *onlinep = 1;
1350                 }
1351             } else if (alldown && statep->state != vl_alldown) {
1352                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1353                 statep->state = vl_alldown;
1354             }
1355         } else {
1356             lock_ReleaseRead(&cm_serverLock);
1357             if (statep->state != vl_alldown) {
1358                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
1359                 statep->state = vl_alldown;
1360             }
1361         }
1362     }
1363 }
1364
1365 /* The return code is 0 if the volume is not online and
1366  * 1 if the volume is online
1367  */
1368 long
1369 cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
1370 {
1371     long code;
1372     cm_req_t req;
1373     afs_uint32 online = 0;
1374     afs_uint32 volumeUpdated = 0;
1375
1376     lock_ObtainWrite(&volp->rw);
1377
1378     if (volp->flags & CM_VOLUMEFLAG_RESET) {
1379         cm_InitReq(&req);
1380         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
1381         volumeUpdated = 1;
1382     }
1383
1384     cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
1385     cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
1386     cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
1387
1388     lock_ReleaseWrite(&volp->rw);
1389     return online;
1390 }
1391
1392
1393 /*
1394  * called from the Daemon thread.
1395  * when checking the offline status, check those of the most recently used volumes first.
1396  */
1397 void cm_CheckOfflineVolumes(void)
1398 {
1399     cm_volume_t *volp;
1400     afs_int32 refCount;
1401     extern int daemon_ShutdownFlag;
1402     extern int powerStateSuspended;
1403
1404     lock_ObtainRead(&cm_volumeLock);
1405     for (volp = cm_data.volumeLRULastp;
1406          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1407          volp=(cm_volume_t *) osi_QPrev(&volp->q)) {
1408         /*
1409          * Skip volume entries that did not exist last time
1410          * the vldb was queried.  For those entries wait until
1411          * the next actual request is received for the volume
1412          * before checking its state.
1413          */
1414         if ((volp->qflags & CM_VOLUME_QFLAG_IN_HASH) &&
1415             !(volp->flags & CM_VOLUMEFLAG_NOEXIST)) {
1416             InterlockedIncrement(&volp->refCount);
1417             lock_ReleaseRead(&cm_volumeLock);
1418             cm_CheckOfflineVolume(volp, 0);
1419             lock_ObtainRead(&cm_volumeLock);
1420             refCount = InterlockedDecrement(&volp->refCount);
1421             osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1422         }
1423     }
1424     lock_ReleaseRead(&cm_volumeLock);
1425 }
1426
1427
1428 static void
1429 cm_UpdateVolumeStatusInt(cm_volume_t *volp, struct cm_vol_state *statep)
1430 {
1431     enum volstatus newStatus;
1432     cm_serverRef_t *tsrp;
1433     cm_server_t *tsp;
1434     int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
1435     char addr[16];
1436
1437     if (!volp || !statep) {
1438 #ifdef DEBUG
1439         DebugBreak();
1440 #endif
1441         return;
1442     }
1443
1444     lock_ObtainWrite(&cm_serverLock);
1445     for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1446         tsp = tsrp->server;
1447         sprintf(addr, "%d.%d.%d.%d",
1448                  ((tsp->addr.sin_addr.s_addr & 0xff)),
1449                  ((tsp->addr.sin_addr.s_addr & 0xff00)>> 8),
1450                  ((tsp->addr.sin_addr.s_addr & 0xff0000)>> 16),
1451                  ((tsp->addr.sin_addr.s_addr & 0xff000000)>> 24));
1452
1453         if (tsrp->status == srv_deleted) {
1454             osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s deleted",
1455                      statep->ID, osi_LogSaveString(afsd_logp,addr));
1456             continue;
1457         }
1458         if (tsp) {
1459             cm_GetServerNoLock(tsp);
1460             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
1461                 allDown = 0;
1462                 if (tsrp->status == srv_busy) {
1463                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s busy",
1464                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1465                     allOffline = 0;
1466                     someBusy = 1;
1467                 } else if (tsrp->status == srv_offline) {
1468                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s offline",
1469                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1470                     allBusy = 0;
1471                     someOffline = 1;
1472                 } else {
1473                     osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s online",
1474                               statep->ID, osi_LogSaveString(afsd_logp,addr));
1475                     allOffline = 0;
1476                     allBusy = 0;
1477                 }
1478             } else {
1479                 osi_Log2(afsd_logp, "cm_UpdateVolumeStatusInt volume %d server reference %s down",
1480                           statep->ID, osi_LogSaveString(afsd_logp,addr));
1481             }
1482             cm_PutServerNoLock(tsp);
1483         }
1484     }
1485     lock_ReleaseWrite(&cm_serverLock);
1486
1487     osi_Log5(afsd_logp, "cm_UpdateVolumeStatusInt allDown %d allBusy %d someBusy %d someOffline %d allOffline %d",
1488              allDown, allBusy, someBusy, someOffline, allOffline);
1489
1490     if (allDown)
1491         newStatus = vl_alldown;
1492     else if (allBusy || (someBusy && someOffline))
1493         newStatus = vl_busy;
1494     else if (allOffline)
1495         newStatus = vl_offline;
1496     else
1497         newStatus = vl_online;
1498
1499     if (statep->ID && statep->state != newStatus)
1500         cm_VolumeStatusNotification(volp, statep->ID, statep->state, newStatus);
1501
1502     statep->state = newStatus;
1503 }
1504
1505 void
1506 cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1507 {
1508
1509     if (volp->vol[RWVOL].ID == volID) {
1510         cm_UpdateVolumeStatusInt(volp, &volp->vol[RWVOL]);
1511     } else if (volp->vol[ROVOL].ID == volID) {
1512         cm_UpdateVolumeStatusInt(volp, &volp->vol[ROVOL]);
1513     } else if (volp->vol[BACKVOL].ID == volID) {
1514         cm_UpdateVolumeStatusInt(volp, &volp->vol[BACKVOL]);
1515     } else {
1516         /*
1517          * If we are called with volID == 0 then something has gone wrong.
1518          * Most likely a race occurred in the server volume list maintenance.
1519          * Since we don't know which volume's status should be updated,
1520          * just update all of them that are known to exist.  Better to be
1521          * correct than fast.
1522          */
1523         afs_uint32 volType;
1524         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
1525             if (volp->vol[volType].ID != 0)
1526                 cm_UpdateVolumeStatusInt(volp, &volp->vol[volType]);
1527         }
1528     }
1529 }
1530
1531 /*
1532 ** Finds all volumes that reside on this server and reorders their
1533 ** RO list according to the changed rank of server.
1534 */
1535 void cm_ChangeRankVolume(cm_server_t *tsp)
1536 {
1537     int                 code;
1538     cm_volume_t*        volp;
1539     afs_int32 refCount;
1540
1541     /* find volumes which might have RO copy on server*/
1542     lock_ObtainRead(&cm_volumeLock);
1543     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1544     {
1545         code = 1 ;      /* assume that list is unchanged */
1546         InterlockedIncrement(&volp->refCount);
1547         lock_ReleaseRead(&cm_volumeLock);
1548         lock_ObtainWrite(&volp->rw);
1549
1550         if ((tsp->cellp==volp->cellp) && (volp->vol[ROVOL].serversp))
1551             code =cm_ChangeRankServer(&volp->vol[ROVOL].serversp, tsp);
1552
1553         /* this volume list was changed */
1554         if ( !code )
1555             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
1556
1557         lock_ReleaseWrite(&volp->rw);
1558         lock_ObtainRead(&cm_volumeLock);
1559         refCount = InterlockedDecrement(&volp->refCount);
1560         osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
1561     }
1562     lock_ReleaseRead(&cm_volumeLock);
1563 }
1564
1565 /* dump all volumes that have reference count > 0 to a file.
1566  * cookie is used to identify this batch for easy parsing,
1567  * and it a string provided by a caller
1568  */
1569 int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
1570 {
1571     int zilch;
1572     cm_volume_t *volp;
1573     char output[1024];
1574
1575     if (lock) {
1576         lock_ObtainRead(&cm_scacheLock);
1577         lock_ObtainRead(&cm_volumeLock);
1578     }
1579
1580     sprintf(output, "%s - dumping volumes - cm_data.currentVolumes=%d, cm_data.maxVolumes=%d\r\n",
1581             cookie, cm_data.currentVolumes, cm_data.maxVolumes);
1582     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1583
1584     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
1585     {
1586         time_t t;
1587         char *srvStr = NULL;
1588         afs_uint32 srvStrRpc = TRUE;
1589         char *cbt = NULL;
1590         char *cdrot = NULL;
1591
1592         if (volp->cbServerpRO) {
1593             if (!((volp->cbServerpRO->flags & CM_SERVERFLAG_UUID) &&
1594                 UuidToString((UUID *)&volp->cbServerpRO->uuid, &srvStr) == RPC_S_OK)) {
1595                 srvStr = malloc(16);
1596                 if (srvStr != NULL)
1597                     afs_inet_ntoa_r(volp->cbServerpRO->addr.sin_addr.s_addr, srvStr);
1598                 srvStrRpc = FALSE;
1599             }
1600         }
1601         if (volp->cbExpiresRO) {
1602             t = volp->cbExpiresRO;
1603             cbt = ctime(&t);
1604             if (cbt) {
1605                 cbt = strdup(cbt);
1606                 cbt[strlen(cbt)-1] = '\0';
1607             }
1608         }
1609         if (volp->creationDateRO) {
1610             t = volp->creationDateRO;
1611             cdrot = ctime(&t);
1612             if (cdrot) {
1613                 cdrot = strdup(cdrot);
1614                 cdrot[strlen(cdrot)-1] = '\0';
1615             }
1616         }
1617
1618         sprintf(output,
1619                 "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x:%x "
1620                 "cbServerpRO='%s' cbExpiresRO='%s' creationDateRO='%s' refCount=%u\r\n",
1621                  cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID,
1622                  volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags, volp->qflags,
1623                  srvStr ? srvStr : "<none>", cbt ? cbt : "<none>", cdrot ? cdrot : "<none>",
1624                  volp->refCount);
1625         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1626
1627         if (srvStr) {
1628             if (srvStrRpc)
1629                 RpcStringFree(&srvStr);
1630             else
1631                 free(srvStr);
1632         }
1633         if (cbt)
1634             free(cbt);
1635         if (cdrot)
1636             free(cdrot);
1637     }
1638     sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
1639     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1640
1641     if (lock) {
1642         lock_ReleaseRead(&cm_volumeLock);
1643         lock_ReleaseRead(&cm_scacheLock);
1644     }
1645     return (0);
1646 }
1647
1648
1649 /*
1650  * String hash function used by SDBM project.
1651  * It was chosen because it is fast and provides
1652  * decent coverage.
1653  */
1654 afs_uint32 SDBMHash(const char * str)
1655 {
1656     afs_uint32 hash = 0;
1657     size_t i, len;
1658
1659     if (str == NULL)
1660         return 0;
1661
1662     for(i = 0, len = strlen(str); i < len; i++)
1663     {
1664         hash = str[i] + (hash << 6) + (hash << 16) - hash;
1665     }
1666
1667     return (hash & 0x7FFFFFFF);
1668 }
1669
1670 /* call with volume write-locked and mutex held */
1671 void cm_AddVolumeToNameHashTable(cm_volume_t *volp)
1672 {
1673     int i;
1674
1675     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH)
1676         return;
1677
1678     i = CM_VOLUME_NAME_HASH(volp->namep);
1679
1680     volp->nameNextp = cm_data.volumeNameHashTablep[i];
1681     cm_data.volumeNameHashTablep[i] = volp;
1682     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_HASH);
1683 }
1684
1685 /* call with volume write-locked and mutex held */
1686 void cm_RemoveVolumeFromNameHashTable(cm_volume_t *volp)
1687 {
1688     cm_volume_t **lvolpp;
1689     cm_volume_t *tvolp;
1690     int i;
1691
1692     if (volp->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1693         /* hash it out first */
1694         i = CM_VOLUME_NAME_HASH(volp->namep);
1695         for (lvolpp = &cm_data.volumeNameHashTablep[i], tvolp = cm_data.volumeNameHashTablep[i];
1696              tvolp;
1697              lvolpp = &tvolp->nameNextp, tvolp = tvolp->nameNextp) {
1698             if (tvolp == volp) {
1699                 *lvolpp = volp->nameNextp;
1700                 _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1701                 volp->nameNextp = NULL;
1702                 break;
1703             }
1704         }
1705     }
1706 }
1707
1708 /* call with volume write-locked and mutex held */
1709 void cm_AddVolumeToIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1710 {
1711     int i;
1712     struct cm_vol_state * statep;
1713
1714     statep = cm_VolumeStateByType(volp, volType);
1715
1716     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH)
1717         return;
1718
1719     i = CM_VOLUME_ID_HASH(statep->ID);
1720
1721     switch (volType) {
1722     case RWVOL:
1723         statep->nextp = cm_data.volumeRWIDHashTablep[i];
1724         cm_data.volumeRWIDHashTablep[i] = volp;
1725         break;
1726     case ROVOL:
1727         statep->nextp = cm_data.volumeROIDHashTablep[i];
1728         cm_data.volumeROIDHashTablep[i] = volp;
1729         break;
1730     case BACKVOL:
1731         statep->nextp = cm_data.volumeBKIDHashTablep[i];
1732         cm_data.volumeBKIDHashTablep[i] = volp;
1733         break;
1734     }
1735     _InterlockedOr(&statep->qflags, CM_VOLUME_QFLAG_IN_HASH);
1736 }
1737
1738
1739 /* call with volume write-locked and mutex held */
1740 void cm_RemoveVolumeFromIDHashTable(cm_volume_t *volp, afs_uint32 volType)
1741 {
1742     cm_volume_t **lvolpp;
1743     cm_volume_t *tvolp;
1744     struct cm_vol_state * statep;
1745     int i;
1746
1747     statep = cm_VolumeStateByType(volp, volType);
1748
1749     if (statep->qflags & CM_VOLUME_QFLAG_IN_HASH) {
1750         /* hash it out first */
1751         i = CM_VOLUME_ID_HASH(statep->ID);
1752
1753         switch (volType) {
1754         case RWVOL:
1755             lvolpp = &cm_data.volumeRWIDHashTablep[i];
1756             tvolp = cm_data.volumeRWIDHashTablep[i];
1757             break;
1758         case ROVOL:
1759             lvolpp = &cm_data.volumeROIDHashTablep[i];
1760             tvolp = cm_data.volumeROIDHashTablep[i];
1761             break;
1762         case BACKVOL:
1763             lvolpp = &cm_data.volumeBKIDHashTablep[i];
1764             tvolp = cm_data.volumeBKIDHashTablep[i];
1765             break;
1766         default:
1767             osi_assertx(0, "invalid volume type");
1768         }
1769         do {
1770             if (tvolp == volp) {
1771                 *lvolpp = statep->nextp;
1772                 _InterlockedAnd(&statep->qflags, ~CM_VOLUME_QFLAG_IN_HASH);
1773                 statep->nextp = NULL;
1774                 break;
1775             }
1776
1777             lvolpp = &tvolp->vol[volType].nextp;
1778             tvolp = tvolp->vol[volType].nextp;
1779         } while(tvolp);
1780     }
1781 }
1782
1783 /* must be called with cm_volumeLock write-locked! */
1784 void cm_AdjustVolumeLRU(cm_volume_t *volp)
1785 {
1786     lock_AssertWrite(&cm_volumeLock);
1787
1788     if (volp == cm_data.volumeLRUFirstp)
1789         return;
1790
1791     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1792         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1793     osi_QAddH((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1794     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1795
1796     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1797 }
1798
1799 /* must be called with cm_volumeLock write-locked! */
1800 void cm_MoveVolumeToLRULast(cm_volume_t *volp)
1801 {
1802     lock_AssertWrite(&cm_volumeLock);
1803
1804     if (volp == cm_data.volumeLRULastp)
1805         return;
1806
1807     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE)
1808         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1809     osi_QAddT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1810     _InterlockedOr(&volp->qflags, CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1811
1812     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1813 }
1814
1815 /* must be called with cm_volumeLock write-locked! */
1816 void cm_RemoveVolumeFromLRU(cm_volume_t *volp)
1817 {
1818     lock_AssertWrite(&cm_volumeLock);
1819
1820     if (volp->qflags & CM_VOLUME_QFLAG_IN_LRU_QUEUE) {
1821         osi_QRemoveHT((osi_queue_t **) &cm_data.volumeLRUFirstp, (osi_queue_t **) &cm_data.volumeLRULastp, &volp->q);
1822         _InterlockedAnd(&volp->qflags, ~CM_VOLUME_QFLAG_IN_LRU_QUEUE);
1823     }
1824
1825     osi_assertx(cm_data.volumeLRULastp != NULL, "null cm_data.volumeLRULastp");
1826 }
1827
1828 static char * volstatus_str(enum volstatus vs)
1829 {
1830     switch (vs) {
1831     case vl_online:
1832         return "online";
1833     case vl_busy:
1834         return "busy";
1835     case vl_offline:
1836         return "offline";
1837     case vl_alldown:
1838         return "alldown";
1839     default:
1840         return "unknown";
1841     }
1842 }
1843
1844 void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new)
1845 {
1846     char volstr[CELL_MAXNAMELEN + VL_MAXNAMELEN]="";
1847     char *ext = "";
1848
1849     if (volID == volp->vol[RWVOL].ID)
1850         ext = "";
1851     else if (volID == volp->vol[ROVOL].ID)
1852         ext = ".readonly";
1853     else if (volID == volp->vol[BACKVOL].ID)
1854         ext = ".backup";
1855     else
1856         ext = ".nomatch";
1857     snprintf(volstr, sizeof(volstr), "%s:%s%s", volp->cellp->name, volp->namep, ext);
1858
1859     osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)",
1860              osi_LogSaveString(afsd_logp, volstr), volID, volstatus_str(old), volstatus_str(new));
1861
1862     cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new);
1863 }
1864
1865 enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID)
1866 {
1867     cm_vol_state_t * statep = cm_VolumeStateByID(volp, volID);
1868     if (statep)
1869         return statep->state;
1870     else
1871         return vl_unknown;
1872 }
1873
1874 /* Renew .readonly volume callbacks that are more than
1875  * 30 minutes old.  (A volume callback is issued for 2 hours.)
1876  */
1877 void
1878 cm_VolumeRenewROCallbacks(void)
1879 {
1880     cm_volume_t * volp;
1881     time_t minexp = time(NULL) + 90 * 60;
1882     extern int daemon_ShutdownFlag;
1883     extern int powerStateSuspended;
1884
1885     lock_ObtainRead(&cm_volumeLock);
1886     for (volp = cm_data.allVolumesp;
1887          volp && !daemon_ShutdownFlag && !powerStateSuspended;
1888          volp=volp->allNextp) {
1889         if ( volp->cbExpiresRO > 0 && volp->cbExpiresRO < minexp) {
1890             cm_req_t      req;
1891             cm_fid_t      fid;
1892             cm_scache_t * scp;
1893
1894             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
1895
1896             cm_InitReq(&req);
1897
1898             lock_ReleaseRead(&cm_volumeLock);
1899             if (cm_GetSCache(&fid, NULL, &scp, cm_rootUserp, &req) == 0) {
1900                 lock_ObtainWrite(&scp->rw);
1901                 cm_GetCallback(scp, cm_rootUserp, &req, 1);
1902                 lock_ReleaseWrite(&scp->rw);
1903                 cm_ReleaseSCache(scp);
1904             }
1905             lock_ObtainRead(&cm_volumeLock);
1906         }
1907     }
1908     lock_ReleaseRead(&cm_volumeLock);
1909 }
1910
1911 cm_vol_state_t *
1912 cm_VolumeStateByType(cm_volume_t *volp, afs_uint32 volType)
1913 {
1914     return &volp->vol[volType];
1915 }
1916
1917 cm_vol_state_t *
1918 cm_VolumeStateByID(cm_volume_t *volp, afs_uint32 id)
1919 {
1920     cm_vol_state_t * statep = NULL;
1921
1922     if (id == volp->vol[RWVOL].ID)
1923         statep = &volp->vol[RWVOL];
1924     else if (id == volp->vol[ROVOL].ID)
1925         statep = &volp->vol[ROVOL];
1926     else if (id == volp->vol[BACKVOL].ID)
1927         statep = &volp->vol[BACKVOL];
1928
1929     return(statep);
1930 }
1931
1932 cm_vol_state_t *
1933 cm_VolumeStateByName(cm_volume_t *volp, char *volname)
1934 {
1935     size_t len = strlen(volname);
1936     cm_vol_state_t *statep;
1937
1938     if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
1939         statep = &volp->vol[ROVOL];
1940     else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
1941         statep = &volp->vol[BACKVOL];
1942     else
1943         statep = &volp->vol[RWVOL];
1944
1945     return statep;
1946 }
1947
1948 afs_int32
1949 cm_VolumeType(cm_volume_t *volp, afs_uint32 id)
1950 {
1951     if (id == volp->vol[RWVOL].ID)
1952         return(RWVOL);
1953     else if (id == volp->vol[ROVOL].ID)
1954         return(ROVOL);
1955     else if (id == volp->vol[BACKVOL].ID)
1956         return (BACKVOL);
1957
1958     return -1;
1959 }
1960
1961 LONG_PTR
1962 cm_ChecksumVolumeServerList(struct cm_fid *fidp, cm_user_t *userp, cm_req_t *reqp)
1963 {
1964     LONG_PTR cksum = 0;
1965     long code;
1966     afs_uint32 replicated;
1967     cm_serverRef_t **serverspp;
1968
1969     code = cm_GetServerList(fidp, userp, reqp, &replicated, &serverspp);
1970     if (code == 0) {
1971         cksum = cm_ChecksumServerList(*serverspp);
1972         cm_FreeServerList(serverspp, 0);
1973     }
1974     return cksum;
1975 }
1976
1977 afs_int32
1978 cm_IsVolumeReplicated(cm_fid_t *fidp)
1979 {
1980     afs_int32 replicated = 0;
1981     cm_volume_t *volp;
1982     cm_vol_state_t * volstatep;
1983
1984     volp = cm_GetVolumeByFID(fidp);
1985     if (volp) {
1986         volstatep = cm_VolumeStateByID(volp, fidp->volume);
1987         replicated = (volstatep->flags & CM_VOL_STATE_FLAG_REPLICATED);
1988         cm_PutVolume(volp);
1989     }
1990
1991     return replicated;
1992 }