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