2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
18 #include <sys/socket.h>
26 osi_rwlock_t cm_volumeLock;
29 cm_ValidateVolume(void)
34 for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->nextp, count++) {
35 if ( volp->magic != CM_VOLUME_MAGIC ) {
36 afsi_log("cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC");
37 fprintf(stderr, "cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC\n");
40 if ( volp->cellp && volp->cellp->magic != CM_CELL_MAGIC ) {
41 afsi_log("cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC");
42 fprintf(stderr, "cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC\n");
45 if ( volp->nextp && volp->nextp->magic != CM_VOLUME_MAGIC ) {
46 afsi_log("cm_ValidateVolume failure: volp->nextp->magic != CM_VOLUME_MAGIC");
47 fprintf(stderr, "cm_ValidateVolume failure: volp->nextp->magic != CM_VOLUME_MAGIC\n");
50 if ( count != 0 && volp == cm_data.allVolumesp ||
51 count > cm_data.maxVolumes ) {
52 afsi_log("cm_ValidateVolume failure: cm_data.allVolumep loop detected");
53 fprintf(stderr, "cm_ValidateVolume failure: cm_data.allVolumep loop detected\n");
58 if ( count != cm_data.currentVolumes ) {
59 afsi_log("cm_ValidateVolume failure: count != cm_data.currentVolumes");
60 fprintf(stderr, "cm_ValidateVolume failure: count != cm_data.currentVolumes\n");
68 cm_ShutdownVolume(void)
72 for (volp = cm_data.allVolumesp; volp; volp=volp->nextp)
73 lock_FinalizeMutex(&volp->mx);
78 void cm_InitVolume(int newFile, long maxVols)
80 static osi_once_t once;
82 if (osi_Once(&once)) {
83 lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock");
86 cm_data.allVolumesp = NULL;
87 cm_data.currentVolumes = 0;
88 cm_data.maxVolumes = maxVols;
92 for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
93 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
94 volp->flags |= CM_VOLUMEFLAG_RESET;
95 volp->rwServersp = NULL;
96 volp->roServersp = NULL;
97 volp->bkServersp = NULL;
105 * Update a volume. Caller holds volume's lock (volp->mx).
108 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:38 (JHutz)
109 * Yes, we support multihomed fileservers.
110 * Since before we got the code from IBM.
111 * But to find out about multiple addresses on a multihomed server, you need
112 * to use VL_GetEntryByNameU and VL_GetAddrsU. If you use
113 * VL_GetEntryByNameO or VL_GetEntryByNameN, the vlserver just gives you one
114 * address per server.
115 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:39 (JHutz)
116 * see src/afs/afs_volume.c, paying particular attention to
117 * afs_NewVolumeByName, afs_SetupVolume, and InstallUVolumeEntry
118 * shadow / openafs / jaltman {ANDREW.CMU.EDU} 01:40 (Jeffrey Altman)
119 * thanks. The windows client calls the 0 versions.
120 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:51 (JHutz)
122 * By not using the N versions, you only get up to 8 sites instead of 13.
123 * By not using the U versions, you don't get to know about multihomed serve
124 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:52 (JHutz)
125 * Of course, you probably want to support the older versions for backward
126 * compatibility. If you do that, you need to call the newest interface
127 * first, and fall back to successively older versions if you get
131 long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
136 cm_serverRef_t *tsrp;
138 struct sockaddr_in tsockAddr;
141 struct vldbentry vldbEntry;
142 struct nvldbentry nvldbEntry;
144 struct uvldbentry uvldbEntry;
150 /* clear out old bindings */
151 if (volp->rwServersp)
152 cm_FreeServerList(&volp->rwServersp);
153 if (volp->roServersp)
154 cm_FreeServerList(&volp->roServersp);
155 if (volp->bkServersp)
156 cm_FreeServerList(&volp->bkServersp);
158 #ifdef AFS_FREELANCE_CLIENT
159 if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && atoi(volp->namep)==AFS_FAKE_ROOT_VOL_ID )
161 memset(&vldbEntry, 0, sizeof(vldbEntry));
162 vldbEntry.flags |= VLF_RWEXISTS;
163 vldbEntry.volumeId[0] = AFS_FAKE_ROOT_VOL_ID;
169 /* now we have volume structure locked and held; make RPC to fill it */
170 osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, volp->namep);
172 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
176 code = VL_GetEntryByNameU(connp->callp, volp->namep, &uvldbEntry);
178 if ( code == RXGEN_OPCODE )
181 code = VL_GetEntryByNameN(connp->callp, volp->namep, &nvldbEntry);
184 if ( code == RXGEN_OPCODE ) {
185 code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
188 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
189 code = cm_MapVLRPCError(code, reqp);
191 osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
192 volp->cellp->name, volp->namep, code);
194 osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS",
195 volp->cellp->name, volp->namep);
203 afs_int32 serverNumber[NMAXNSERVERS];
204 afs_int32 serverFlags[NMAXNSERVERS];
208 flags = vldbEntry.flags;
209 nServers = vldbEntry.nServers;
210 rwID = vldbEntry.volumeId[0];
211 roID = vldbEntry.volumeId[1];
212 bkID = vldbEntry.volumeId[2];
213 for ( i=0; i<nServers; i++ ) {
214 serverFlags[i] = vldbEntry.serverFlags[i];
215 serverNumber[i] = vldbEntry.serverNumber[i];
219 flags = nvldbEntry.flags;
220 nServers = nvldbEntry.nServers;
221 rwID = nvldbEntry.volumeId[0];
222 roID = nvldbEntry.volumeId[1];
223 bkID = nvldbEntry.volumeId[2];
224 for ( i=0; i<nServers; i++ ) {
225 serverFlags[i] = nvldbEntry.serverFlags[i];
226 serverNumber[i] = nvldbEntry.serverNumber[i];
231 flags = uvldbEntry.flags;
232 nServers = uvldbEntry.nServers;
233 rwID = uvldbEntry.volumeId[0];
234 roID = uvldbEntry.volumeId[1];
235 bkID = uvldbEntry.volumeId[2];
236 for ( i=0, j=0; i<nServers && j<NMAXNSERVERS; i++ ) {
237 if ( !(uvldbEntry.serverFlags[i] & VLSERVER_FLAG_UUID) ) {
238 serverFlags[j] = uvldbEntry.serverFlags[i];
239 serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
242 afs_uint32 * addrp, nentries, code, unique;
244 ListAddrByAttributes attrs;
247 memset((char *)&attrs, 0, sizeof(attrs));
248 attrs.Mask = VLADDR_UUID;
249 attrs.uuid = uvldbEntry.serverNumber[i];
250 memset((char *)&uuid, 0, sizeof(uuid));
251 memset((char *)&addrs, 0, sizeof(addrs));
254 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
258 code = VL_GetAddrsU(connp->callp, &attrs, &uuid, &unique, &nentries, &addrs);
260 if (code == 0 && nentries == 0)
262 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
263 code = cm_MapVLRPCError(code, reqp);
267 addrp = addrs.bulkaddrs_val;
268 for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
269 serverFlags[j] = uvldbEntry.serverFlags[i];
270 serverNumber[j] = addrp[k];
273 free(addrs.bulkaddrs_val); /* This is wrong */
276 nServers = j; /* update the server count */
281 /* decode the response */
282 lock_ObtainWrite(&cm_volumeLock);
283 if (flags & VLF_RWEXISTS)
287 if (flags & VLF_ROEXISTS)
291 if (flags & VLF_BACKEXISTS)
295 lock_ReleaseWrite(&cm_volumeLock);
296 for (i=0; i<nServers; i++) {
297 /* create a server entry */
298 tflags = serverFlags[i];
299 if (tflags & VLSF_DONTUSE)
301 tsockAddr.sin_family = AF_INET;
302 tempAddr = htonl(serverNumber[i]);
303 tsockAddr.sin_addr.s_addr = tempAddr;
304 tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
306 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
309 /* if this server was created by fs setserverprefs */
313 osi_assert(tsp != NULL);
315 /* and add it to the list(s). */
317 * Each call to cm_NewServerRef() increments the
318 * ref count of tsp. These reference will be dropped,
319 * if and when the volume is reset; see reset code
320 * earlier in this function.
322 if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
323 tsrp = cm_NewServerRef(tsp);
324 cm_InsertServerList(&volp->rwServersp, tsrp);
325 lock_ObtainWrite(&cm_serverLock);
326 tsrp->refCount--; /* drop allocation reference */
327 lock_ReleaseWrite(&cm_serverLock);
329 if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS)) {
330 tsrp = cm_NewServerRef(tsp);
331 cm_InsertServerList(&volp->roServersp, tsrp);
332 lock_ObtainWrite(&cm_serverLock);
333 tsrp->refCount--; /* drop allocation reference */
334 lock_ReleaseWrite(&cm_serverLock);
337 /* We don't use VLSF_BACKVOL !?! */
338 if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
339 tsrp = cm_NewServerRef(tsp);
340 cm_InsertServerList(&volp->bkServersp, tsrp);
341 lock_ObtainWrite(&cm_serverLock);
342 tsrp->refCount--; /* drop allocation reference */
343 lock_ReleaseWrite(&cm_serverLock);
345 /* Drop the reference obtained by cm_FindServer() */
352 * If the first n servers have the same ipRank, then we
353 * randomly pick one among them and move it to the beginning.
354 * We don't bother to re-order the whole list because
355 * the rest of the list is used only if the first server is
356 * down. We only do this for the RO list; we assume the other
357 * lists are length 1.
360 cm_RandomizeServer(&volp->roServersp);
366 long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
367 cm_req_t *reqp, cm_volume_t **outVolpp)
370 char volNameString[100];
373 lock_ObtainWrite(&cm_volumeLock);
374 for(volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
375 if (cellp == volp->cellp &&
376 ((unsigned) volumeID == volp->rwID ||
377 (unsigned) volumeID == volp->roID ||
378 (unsigned) volumeID == volp->bkID))
382 /* hold the volume if we found it */
385 lock_ReleaseWrite(&cm_volumeLock);
389 lock_ObtainMutex(&volp->mx);
391 if (volp->flags & CM_VOLUMEFLAG_RESET) {
392 code = cm_UpdateVolume(cellp, userp, reqp, volp);
394 volp->flags &= ~CM_VOLUMEFLAG_RESET;
399 lock_ReleaseMutex(&volp->mx);
405 /* otherwise, we didn't find it so consult the VLDB */
406 sprintf(volNameString, "%u", volumeID);
407 code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
412 long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
413 struct cm_user *userp, struct cm_req *reqp,
414 long flags, cm_volume_t **outVolpp)
419 /* initialize this */
422 lock_ObtainWrite(&cm_volumeLock);
423 for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
424 if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
429 /* otherwise, get from VLDB */
431 if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
432 for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
433 if ( volp->refCount == 0 ) {
434 /* There is one we can re-use */
438 osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
442 volp->rwID = volp->roID = volp->bkID = 0;
443 volp->dotdotFid.cell = 0;
444 volp->dotdotFid.volume = 0;
445 volp->dotdotFid.unique = 0;
446 volp->dotdotFid.vnode = 0;
448 volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
449 memset(volp, 0, sizeof(cm_volume_t));
450 volp->magic = CM_VOLUME_MAGIC;
451 volp->nextp = cm_data.allVolumesp;
452 cm_data.allVolumesp = volp;
453 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
456 strncpy(volp->namep, volumeNamep, VL_MAXNAMELEN);
457 volp->namep[VL_MAXNAMELEN-1] = '\0';
458 volp->refCount = 1; /* starts off held */
459 volp->flags = CM_VOLUMEFLAG_RESET;
465 /* next should work since no one could have gotten ptr to this structure yet */
466 lock_ReleaseWrite(&cm_volumeLock);
467 lock_ObtainMutex(&volp->mx);
469 if (volp->flags & CM_VOLUMEFLAG_RESET) {
470 code = cm_UpdateVolume(cellp, userp, reqp, volp);
472 volp->flags &= ~CM_VOLUMEFLAG_RESET;
477 lock_ReleaseMutex(&volp->mx);
481 void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
488 cellp = cm_FindCellByID(fidp->cell);
491 /* search for the volume */
492 lock_ObtainWrite(&cm_volumeLock);
493 for(volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
494 if (cellp == volp->cellp &&
495 (fidp->volume == volp->rwID ||
496 fidp->volume == volp->roID ||
497 fidp->volume == volp->bkID))
501 /* hold the volume if we found it */
502 if (volp) volp->refCount++;
503 lock_ReleaseWrite(&cm_volumeLock);
506 cm_data.mountRootGen = time(NULL);
507 lock_ObtainMutex(&volp->mx);
508 volp->flags |= CM_VOLUMEFLAG_RESET;
510 /* Mark the volume to be updated but don't update it now.
511 * This function is called only from within cm_Analyze
512 * when cm_ConnByMServers has failed with all servers down
513 * The problem is that cm_UpdateVolume is going to call
514 * cm_ConnByMServers which may cause a recursive chain
515 * of calls each returning a retry on failure.
516 * Instead, set the flag so the next time the volume is
517 * accessed by Name or ID the UpdateVolume call will
520 code = cm_UpdateVolume(cellp, userp, reqp, volp);
522 volp->flags &= ~CM_VOLUMEFLAG_RESET;
524 lock_ReleaseMutex(&volp->mx);
529 /* find the appropriate servers from a volume */
530 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
532 cm_serverRef_t **serverspp;
533 cm_serverRef_t *current;;
535 lock_ObtainWrite(&cm_serverLock);
537 if (volume == volp->rwID)
538 serverspp = &volp->rwServersp;
539 else if (volume == volp->roID)
540 serverspp = &volp->roServersp;
541 else if (volume == volp->bkID)
542 serverspp = &volp->bkServersp;
544 osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
546 for (current = *serverspp; current; current = current->next)
549 lock_ReleaseWrite(&cm_serverLock);
554 void cm_PutVolume(cm_volume_t *volp)
556 lock_ObtainWrite(&cm_volumeLock);
557 osi_assert(volp->refCount-- > 0);
558 lock_ReleaseWrite(&cm_volumeLock);
561 /* return the read-only volume, if there is one, or the read-write volume if
564 long cm_GetROVolumeID(cm_volume_t *volp)
568 lock_ObtainMutex(&volp->mx);
569 if (volp->roID && volp->roServersp)
573 lock_ReleaseMutex(&volp->mx);
578 void cm_CheckVolumes(void)
582 cm_data.mountRootGen = time(NULL);
583 lock_ObtainWrite(&cm_volumeLock);
584 for (volp = cm_data.allVolumesp; volp; volp=volp->nextp) {
586 lock_ReleaseWrite(&cm_volumeLock);
587 lock_ObtainMutex(&volp->mx);
589 volp->flags |= CM_VOLUMEFLAG_RESET;
591 lock_ReleaseMutex(&volp->mx);
592 lock_ObtainWrite(&cm_volumeLock);
593 osi_assert(volp->refCount-- > 0);
595 lock_ReleaseWrite(&cm_volumeLock);
597 /* We should also refresh cached mount points */
601 ** Finds all volumes that reside on this server and reorders their
602 ** RO list according to the changed rank of server.
604 void cm_ChangeRankVolume(cm_server_t *tsp)
609 /* find volumes which might have RO copy on server*/
610 lock_ObtainWrite(&cm_volumeLock);
611 for(volp = cm_data.allVolumesp; volp; volp=volp->nextp)
613 code = 1 ; /* assume that list is unchanged */
615 lock_ReleaseWrite(&cm_volumeLock);
616 lock_ObtainMutex(&volp->mx);
618 if ((tsp->cellp==volp->cellp) && (volp->roServersp))
619 code =cm_ChangeRankServer(&volp->roServersp, tsp);
621 /* this volume list was changed */
623 cm_RandomizeServer(&volp->roServersp);
625 lock_ReleaseMutex(&volp->mx);
626 lock_ObtainWrite(&cm_volumeLock);
627 osi_assert(volp->refCount-- > 0);
629 lock_ReleaseWrite(&cm_volumeLock);