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