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