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>
27 osi_rwlock_t cm_volumeLock;
28 cm_volume_t *cm_allVolumesp;
30 void cm_InitVolume(void)
32 static osi_once_t once;
33 if (osi_Once(&once)) {
34 lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock");
35 cm_allVolumesp = NULL;
41 * Update a volume. Caller holds volume's lock (volp->mx).
44 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:38 (JHutz)
45 * Yes, we support multihomed fileservers.
46 * Since before we got the code from IBM.
47 * But to find out about multiple addresses on a multihomed server, you need
48 * to use VL_GetEntryByNameU and VL_GetAddrsU. If you use
49 * VL_GetEntryByNameO or VL_GetEntryByNameN, the vlserver just gives you one
51 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:39 (JHutz)
52 * see src/afs/afs_volume.c, paying particular attention to
53 * afs_NewVolumeByName, afs_SetupVolume, and InstallUVolumeEntry
54 * shadow / openafs / jaltman {ANDREW.CMU.EDU} 01:40 (Jeffrey Altman)
55 * thanks. The windows client calls the 0 versions.
56 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:51 (JHutz)
58 * By not using the N versions, you only get up to 8 sites instead of 13.
59 * By not using the U versions, you don't get to know about multihomed serve
60 * shadow / openafs / jhutz@CS.CMU.EDU {ANDREW.CMU.EDU} 01:52 (JHutz)
61 * Of course, you probably want to support the older versions for backward
62 * compatibility. If you do that, you need to call the newest interface
63 * first, and fall back to successively older versions if you get
67 long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
74 struct sockaddr_in tsockAddr;
77 struct vldbentry vldbEntry;
78 struct nvldbentry nvldbEntry;
80 struct uvldbentry uvldbEntry;
86 /* clear out old bindings */
87 cm_FreeServerList(&volp->rwServersp);
88 cm_FreeServerList(&volp->roServersp);
89 cm_FreeServerList(&volp->bkServersp);
91 /* now we have volume structure locked and held; make RPC to fill it */
93 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
96 osi_Log1(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s", volp->namep);
98 code = VL_GetEntryByNameU(connp->callp, volp->namep, &uvldbEntry);
100 if ( code == RXGEN_OPCODE )
103 code = VL_GetEntryByNameN(connp->callp, volp->namep, &nvldbEntry);
106 if ( code == RXGEN_OPCODE ) {
107 code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
110 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
111 code = cm_MapVLRPCError(code, reqp);
119 afs_int32 serverNumber[NMAXNSERVERS];
120 afs_int32 serverFlags[NMAXNSERVERS];
124 flags = vldbEntry.flags;
125 nServers = vldbEntry.nServers;
126 rwID = vldbEntry.volumeId[0];
127 roID = vldbEntry.volumeId[1];
128 bkID = vldbEntry.volumeId[2];
129 for ( i=0; i<nServers; i++ ) {
130 serverFlags[i] = vldbEntry.serverFlags[i];
131 serverNumber[i] = vldbEntry.serverNumber[i];
135 flags = nvldbEntry.flags;
136 nServers = nvldbEntry.nServers;
137 rwID = nvldbEntry.volumeId[0];
138 roID = nvldbEntry.volumeId[1];
139 bkID = nvldbEntry.volumeId[2];
140 for ( i=0; i<nServers; i++ ) {
141 serverFlags[i] = nvldbEntry.serverFlags[i];
142 serverNumber[i] = nvldbEntry.serverNumber[i];
147 flags = uvldbEntry.flags;
148 nServers = uvldbEntry.nServers;
149 rwID = uvldbEntry.volumeId[0];
150 roID = uvldbEntry.volumeId[1];
151 bkID = uvldbEntry.volumeId[2];
152 for ( i=0, j=0; i<nServers && j<NMAXNSERVERS; i++ ) {
153 if ( !(uvldbEntry.serverFlags[i] & VLSERVER_FLAG_UUID) ) {
154 serverFlags[j] = uvldbEntry.serverFlags[i];
155 serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
158 afs_uint32 * addrp, nentries, code, unique;
160 ListAddrByAttributes attrs;
163 memset((char *)&attrs, 0, sizeof(attrs));
164 attrs.Mask = VLADDR_UUID;
165 attrs.uuid = uvldbEntry.serverNumber[i];
166 memset((char *)&uuid, 0, sizeof(uuid));
167 memset((char *)&addrs, 0, sizeof(addrs));
170 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
174 code = VL_GetAddrsU(connp->callp, &attrs, &uuid, &unique, &nentries, &addrs);
176 if (code == 0 && nentries == 0)
178 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
179 code = cm_MapVLRPCError(code, reqp);
183 addrp = addrs.bulkaddrs_val;
184 for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
185 serverFlags[j] = uvldbEntry.serverFlags[i];
186 serverNumber[j] = addrp[k];
189 free(addrs.bulkaddrs_val); /* This is wrong */
192 nServers = j; /* update the server count */
197 /* decode the response */
198 lock_ObtainWrite(&cm_volumeLock);
199 if (flags & VLF_RWEXISTS)
203 if (flags & VLF_ROEXISTS)
207 if (flags & VLF_BACKEXISTS)
211 lock_ReleaseWrite(&cm_volumeLock);
212 for (i=0; i<nServers; i++) {
213 /* create a server entry */
214 tflags = serverFlags[i];
215 if (tflags & VLSF_DONTUSE)
217 tsockAddr.sin_family = AF_INET;
218 tempAddr = htonl(serverNumber[i]);
219 tsockAddr.sin_addr.s_addr = tempAddr;
220 tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
222 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
225 /* if this server was created by fs setserverprefs */
229 osi_assert(tsp != NULL);
231 /* and add it to the list(s). */
233 * Each call to cm_NewServerRef() increments the
234 * ref count of tsp. These reference will be dropped,
235 * if and when the volume is reset; see reset code
236 * earlier in this function.
238 if ((tflags & VLSF_RWVOL) && (flags & VLF_RWEXISTS)) {
239 tsrp = cm_NewServerRef(tsp);
240 cm_InsertServerList(&volp->rwServersp, tsrp);
241 lock_ObtainWrite(&cm_serverLock);
242 tsrp->refCount--; /* drop allocation reference */
243 lock_ReleaseWrite(&cm_serverLock);
245 if ((tflags & VLSF_ROVOL) && (flags & VLF_ROEXISTS)) {
246 tsrp = cm_NewServerRef(tsp);
247 cm_InsertServerList(&volp->roServersp, tsrp);
248 lock_ObtainWrite(&cm_serverLock);
249 tsrp->refCount--; /* drop allocation reference */
250 lock_ReleaseWrite(&cm_serverLock);
253 /* We don't use VLSF_BACKVOL !?! */
254 if ((tflags & VLSF_RWVOL) && (flags & VLF_BACKEXISTS)) {
255 tsrp = cm_NewServerRef(tsp);
256 cm_InsertServerList(&volp->bkServersp, tsrp);
257 lock_ObtainWrite(&cm_serverLock);
258 tsrp->refCount--; /* drop allocation reference */
259 lock_ReleaseWrite(&cm_serverLock);
261 /* Drop the reference obtained by cm_FindServer() */
268 * If the first n servers have the same ipRank, then we
269 * randomly pick one among them and move it to the beginning.
270 * We don't bother to re-order the whole list because
271 * the rest of the list is used only if the first server is
272 * down. We only do this for the RO list; we assume the other
273 * lists are length 1.
276 cm_RandomizeServer(&volp->roServersp);
282 long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
283 cm_req_t *reqp, cm_volume_t **outVolpp)
286 char volNameString[100];
289 lock_ObtainWrite(&cm_volumeLock);
290 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
291 if (cellp == volp->cellp &&
292 ((unsigned) volumeID == volp->rwID ||
293 (unsigned) volumeID == volp->roID ||
294 (unsigned) volumeID == volp->bkID))
298 /* hold the volume if we found it */
301 lock_ReleaseWrite(&cm_volumeLock);
305 lock_ObtainMutex(&volp->mx);
307 if (volp->flags & CM_VOLUMEFLAG_RESET) {
308 code = cm_UpdateVolume(cellp, userp, reqp, volp);
310 volp->flags &= ~CM_VOLUMEFLAG_RESET;
315 lock_ReleaseMutex(&volp->mx);
321 /* otherwise, we didn't find it so consult the VLDB */
322 sprintf(volNameString, "%u", volumeID);
323 code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
328 long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
329 struct cm_user *userp, struct cm_req *reqp,
330 long flags, cm_volume_t **outVolpp)
335 /* initialize this */
338 lock_ObtainWrite(&cm_volumeLock);
339 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
340 if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
345 /* otherwise, get from VLDB */
347 volp = malloc(sizeof(*volp));
348 memset(volp, 0, sizeof(*volp));
350 volp->nextp = cm_allVolumesp;
351 cm_allVolumesp = volp;
352 volp->namep = malloc(strlen(volumeNamep)+1);
353 strcpy(volp->namep, volumeNamep);
354 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
355 volp->refCount = 1; /* starts off held */
356 volp->flags |= CM_VOLUMEFLAG_RESET;
362 /* next should work since no one could have gotten ptr to this structure yet */
363 lock_ReleaseWrite(&cm_volumeLock);
364 lock_ObtainMutex(&volp->mx);
366 if (volp->flags & CM_VOLUMEFLAG_RESET) {
367 code = cm_UpdateVolume(cellp, userp, reqp, volp);
369 volp->flags &= ~CM_VOLUMEFLAG_RESET;
374 lock_ReleaseMutex(&volp->mx);
378 void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
386 cellp = cm_FindCellByID(fidp->cell);
389 /* search for the volume */
390 lock_ObtainWrite(&cm_volumeLock);
391 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
392 if (cellp == volp->cellp &&
393 (fidp->volume == volp->rwID ||
394 fidp->volume == volp->roID ||
395 fidp->volume == volp->bkID))
399 /* hold the volume if we found it */
400 if (volp) volp->refCount++;
401 lock_ReleaseWrite(&cm_volumeLock);
405 lock_ObtainMutex(&volp->mx);
406 volp->flags |= CM_VOLUMEFLAG_RESET;
408 /* Mark the volume to be updated but don't update it now.
409 * This function is called only from within cm_Analyze
410 * when cm_ConnByMServers has failed with all servers down
411 * The problem is that cm_UpdateVolume is going to call
412 * cm_ConnByMServers which may cause a recursive chain
413 * of calls each returning a retry on failure.
414 * Instead, set the flag so the next time the volume is
415 * accessed by Name or ID the UpdateVolume call will
418 code = cm_UpdateVolume(cellp, userp, reqp, volp);
420 volp->flags &= ~CM_VOLUMEFLAG_RESET;
422 lock_ReleaseMutex(&volp->mx);
427 /* find the appropriate servers from a volume */
428 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
430 cm_serverRef_t **serverspp;
431 cm_serverRef_t *current;;
433 lock_ObtainWrite(&cm_serverLock);
435 if (volume == volp->rwID)
436 serverspp = &volp->rwServersp;
437 else if (volume == volp->roID)
438 serverspp = &volp->roServersp;
439 else if (volume == volp->bkID)
440 serverspp = &volp->bkServersp;
442 osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
444 for (current = *serverspp; current; current = current->next)
447 lock_ReleaseWrite(&cm_serverLock);
452 void cm_PutVolume(cm_volume_t *volp)
454 lock_ObtainWrite(&cm_volumeLock);
455 osi_assert(volp->refCount-- > 0);
456 lock_ReleaseWrite(&cm_volumeLock);
459 /* return the read-only volume, if there is one, or the read-write volume if
462 long cm_GetROVolumeID(cm_volume_t *volp)
466 lock_ObtainMutex(&volp->mx);
467 if (volp->roID && volp->roServersp)
471 lock_ReleaseMutex(&volp->mx);
476 void cm_CheckVolumes(void)
481 lock_ObtainWrite(&cm_volumeLock);
482 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
484 lock_ReleaseWrite(&cm_volumeLock);
485 lock_ObtainMutex(&volp->mx);
487 volp->flags |= CM_VOLUMEFLAG_RESET;
489 lock_ReleaseMutex(&volp->mx);
490 lock_ObtainWrite(&cm_volumeLock);
491 osi_assert(volp->refCount-- > 0);
493 lock_ReleaseWrite(&cm_volumeLock);
495 /* We should also refresh cached mount points */
499 ** Finds all volumes that reside on this server and reorders their
500 ** RO list according to the changed rank of server.
502 void cm_ChangeRankVolume(cm_server_t *tsp)
507 /* find volumes which might have RO copy on server*/
508 lock_ObtainWrite(&cm_volumeLock);
509 for(volp = cm_allVolumesp; volp; volp=volp->nextp)
511 code = 1 ; /* assume that list is unchanged */
513 lock_ReleaseWrite(&cm_volumeLock);
514 lock_ObtainMutex(&volp->mx);
516 if ((tsp->cellp==volp->cellp) && (volp->roServersp))
517 code =cm_ChangeRankServer(&volp->roServersp, tsp);
519 /* this volume list was changed */
521 cm_RandomizeServer(&volp->roServersp);
523 lock_ReleaseMutex(&volp->mx);
524 lock_ObtainWrite(&cm_volumeLock);
525 osi_assert(volp->refCount-- > 0);
527 lock_ReleaseWrite(&cm_volumeLock);