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).
43 long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
50 struct sockaddr_in tsockAddr;
53 struct vldbentry vldbEntry; /* don't use NVLDB yet; they're not common */
57 /* clear out old bindings */
58 cm_FreeServerList(&volp->rwServersp);
59 cm_FreeServerList(&volp->roServersp);
60 cm_FreeServerList(&volp->bkServersp);
62 /* now we have volume structure locked and held; make RPC to fill it */
64 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp,
67 osi_Log1(afsd_logp, "CALL VL_GetEntryByNameO name %s",
69 code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
70 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
71 code = cm_MapVLRPCError(code, reqp);
74 /* decode the response */
75 lock_ObtainWrite(&cm_volumeLock);
76 if (vldbEntry.flags & VLF_RWEXISTS)
77 volp->rwID = vldbEntry.volumeId[0];
80 if (vldbEntry.flags & VLF_ROEXISTS)
81 volp->roID = vldbEntry.volumeId[1];
84 if (vldbEntry.flags & VLF_BACKEXISTS)
85 volp->bkID = vldbEntry.volumeId[2];
88 lock_ReleaseWrite(&cm_volumeLock);
89 for(i=0; i<vldbEntry.nServers; i++) {
90 /* create a server entry */
91 tflags = vldbEntry.serverFlags[i];
92 if (tflags & VLSF_DONTUSE) continue;
93 tsockAddr.sin_family = AF_INET;
94 tempAddr = htonl(vldbEntry.serverNumber[i]);
95 tsockAddr.sin_addr.s_addr = tempAddr;
96 tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
98 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
101 /* if this server was created by fs setserverprefs */
105 osi_assert(tsp != NULL);
107 /* and add it to the list(s). */
109 * Each call to cm_NewServerRef() increments the
110 * ref count of tsp. These reference will be dropped,
111 * if and when the volume is reset; see reset code
112 * earlier in this function.
114 if ((tflags & VLSF_RWVOL)
115 && (vldbEntry.flags & VLF_RWEXISTS)) {
116 tsrp = cm_NewServerRef(tsp);
117 cm_InsertServerList(&volp->rwServersp, tsrp);
118 lock_ObtainWrite(&cm_serverLock);
119 tsrp->refCount--; /* drop allocation reference */
120 lock_ReleaseWrite(&cm_serverLock);
122 if ((tflags & VLSF_ROVOL)
123 && (vldbEntry.flags & VLF_ROEXISTS)) {
124 tsrp = cm_NewServerRef(tsp);
125 cm_InsertServerList(&volp->roServersp, tsrp);
126 lock_ObtainWrite(&cm_serverLock);
127 tsrp->refCount--; /* drop allocation reference */
128 lock_ReleaseWrite(&cm_serverLock);
131 /* We don't use VLSF_BACKVOL !?! */
132 if ((tflags & VLSF_RWVOL)
133 && (vldbEntry.flags & VLF_BACKEXISTS)) {
134 tsrp = cm_NewServerRef(tsp);
135 cm_InsertServerList(&volp->bkServersp, tsrp);
136 lock_ObtainWrite(&cm_serverLock);
137 tsrp->refCount--; /* drop allocation reference */
138 lock_ReleaseWrite(&cm_serverLock);
140 /* Drop the reference obtained by cm_FindServer() */
147 * If the first n servers have the same ipRank, then we
148 * randomly pick one among them and move it to the beginning.
149 * We don't bother to re-order the whole list because
150 * the rest of the list is used only if the first server is
151 * down. We only do this for the RO list; we assume the other
152 * lists are length 1.
155 cm_RandomizeServer(&volp->roServersp);
161 long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
162 cm_req_t *reqp, cm_volume_t **outVolpp)
165 char volNameString[100];
168 lock_ObtainWrite(&cm_volumeLock);
169 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
170 if (cellp == volp->cellp &&
171 ((unsigned) volumeID == volp->rwID ||
172 (unsigned) volumeID == volp->roID ||
173 (unsigned) volumeID == volp->bkID))
177 /* hold the volume if we found it */
178 if (volp) volp->refCount++;
179 lock_ReleaseWrite(&cm_volumeLock);
183 lock_ObtainMutex(&volp->mx);
185 if (volp->flags & CM_VOLUMEFLAG_RESET) {
186 code = cm_UpdateVolume(cellp, userp, reqp, volp);
188 volp->flags &= ~CM_VOLUMEFLAG_RESET;
193 lock_ReleaseMutex(&volp->mx);
199 /* otherwise, we didn't find it so consult the VLDB */
200 sprintf(volNameString, "%u", volumeID);
201 code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
206 long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
207 struct cm_user *userp, struct cm_req *reqp,
208 long flags, cm_volume_t **outVolpp)
213 /* initialize this */
216 lock_ObtainWrite(&cm_volumeLock);
217 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
218 if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
223 /* otherwise, get from VLDB */
225 volp = malloc(sizeof(*volp));
226 memset(volp, 0, sizeof(*volp));
228 volp->nextp = cm_allVolumesp;
229 cm_allVolumesp = volp;
230 volp->namep = malloc(strlen(volumeNamep)+1);
231 strcpy(volp->namep, volumeNamep);
232 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
233 volp->refCount = 1; /* starts off held */
234 volp->flags |= CM_VOLUMEFLAG_RESET;
240 /* next should work since no one could have gotten ptr to this structure yet */
241 lock_ReleaseWrite(&cm_volumeLock);
242 lock_ObtainMutex(&volp->mx);
244 if (volp->flags & CM_VOLUMEFLAG_RESET) {
245 code = cm_UpdateVolume(cellp, userp, reqp, volp);
247 volp->flags &= ~CM_VOLUMEFLAG_RESET;
252 lock_ReleaseMutex(&volp->mx);
256 void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
264 cellp = cm_FindCellByID(fidp->cell);
267 /* search for the volume */
268 lock_ObtainWrite(&cm_volumeLock);
269 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
270 if (cellp == volp->cellp &&
271 (fidp->volume == volp->rwID ||
272 fidp->volume == volp->roID ||
273 fidp->volume == volp->bkID))
277 /* hold the volume if we found it */
278 if (volp) volp->refCount++;
279 lock_ReleaseWrite(&cm_volumeLock);
283 lock_ObtainMutex(&volp->mx);
284 volp->flags |= CM_VOLUMEFLAG_RESET;
286 /* Mark the volume to be updated but don't update it now.
287 * This function is called only from within cm_Analyze
288 * when cm_ConnByMServers has failed with all servers down
289 * The problem is that cm_UpdateVolume is going to call
290 * cm_ConnByMServers which may cause a recursive chain
291 * of calls each returning a retry on failure.
292 * Instead, set the flag so the next time the volume is
293 * accessed by Name or ID the UpdateVolume call will
296 code = cm_UpdateVolume(cellp, userp, reqp, volp);
298 volp->flags &= ~CM_VOLUMEFLAG_RESET;
300 lock_ReleaseMutex(&volp->mx);
305 /* find the appropriate servers from a volume */
306 cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
308 cm_serverRef_t **serverspp;
309 cm_serverRef_t *current;;
311 lock_ObtainWrite(&cm_serverLock);
313 if (volume == volp->rwID)
314 serverspp = &volp->rwServersp;
315 else if (volume == volp->roID)
316 serverspp = &volp->roServersp;
317 else if (volume == volp->bkID)
318 serverspp = &volp->bkServersp;
319 else osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
321 for (current = *serverspp; current; current = current->next)
324 lock_ReleaseWrite(&cm_serverLock);
329 void cm_PutVolume(cm_volume_t *volp)
331 lock_ObtainWrite(&cm_volumeLock);
332 osi_assert(volp->refCount-- > 0);
333 lock_ReleaseWrite(&cm_volumeLock);
336 /* return the read-only volume, if there is one, or the read-write volume if
339 long cm_GetROVolumeID(cm_volume_t *volp)
343 lock_ObtainMutex(&volp->mx);
344 if (volp->roID && volp->roServersp)
348 lock_ReleaseMutex(&volp->mx);
353 void cm_CheckVolumes(void)
358 lock_ObtainWrite(&cm_volumeLock);
359 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
361 lock_ReleaseWrite(&cm_volumeLock);
362 lock_ObtainMutex(&volp->mx);
364 volp->flags |= CM_VOLUMEFLAG_RESET;
366 lock_ReleaseMutex(&volp->mx);
367 lock_ObtainWrite(&cm_volumeLock);
368 osi_assert(volp->refCount-- > 0);
370 lock_ReleaseWrite(&cm_volumeLock);
372 /* We should also refresh cached mount points */
377 ** Finds all volumes that reside on this server and reorders their
378 ** RO list according to the changed rank of server.
380 void cm_ChangeRankVolume(cm_server_t *tsp)
385 /* find volumes which might have RO copy on server*/
386 lock_ObtainWrite(&cm_volumeLock);
387 for(volp = cm_allVolumesp; volp; volp=volp->nextp)
389 code = 1 ; /* assume that list is unchanged */
391 lock_ReleaseWrite(&cm_volumeLock);
392 lock_ObtainMutex(&volp->mx);
394 if ((tsp->cellp==volp->cellp) && (volp->roServersp))
395 code =cm_ChangeRankServer(&volp->roServersp, tsp);
397 /* this volume list was changed */
399 cm_RandomizeServer(&volp->roServersp);
401 lock_ReleaseMutex(&volp->mx);
402 lock_ObtainWrite(&cm_volumeLock);
403 osi_assert(volp->refCount-- > 0);
405 lock_ReleaseWrite(&cm_volumeLock);