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