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 while (tsrp = volp->rwServersp) {
59 volp->rwServersp = tsrp->next;
60 cm_PutServer(tsrp->server);
63 while (tsrp = volp->roServersp) {
64 volp->roServersp = tsrp->next;
65 cm_PutServer(tsrp->server);
68 while (tsrp = volp->bkServersp) {
69 volp->bkServersp = tsrp->next;
70 cm_PutServer(tsrp->server);
74 /* now we have volume structure locked and held; make RPC to fill it */
76 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp,
79 osi_Log1(afsd_logp, "CALL VL_GetEntryByNameO name %s",
81 code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
82 } while (cm_Analyze(connp, userp, reqp, NULL, NULL, NULL, code));
83 code = cm_MapVLRPCError(code, reqp);
86 /* decode the response */
87 lock_ObtainWrite(&cm_volumeLock);
88 if (vldbEntry.flags & VLF_RWEXISTS)
89 volp->rwID = vldbEntry.volumeId[0];
92 if (vldbEntry.flags & VLF_ROEXISTS)
93 volp->roID = vldbEntry.volumeId[1];
96 if (vldbEntry.flags & VLF_BACKEXISTS)
97 volp->bkID = vldbEntry.volumeId[2];
100 lock_ReleaseWrite(&cm_volumeLock);
101 for(i=0; i<vldbEntry.nServers; i++) {
102 /* create a server entry */
103 tflags = vldbEntry.serverFlags[i];
104 if (tflags & VLSF_DONTUSE) continue;
105 tsockAddr.sin_family = AF_INET;
106 tempAddr = htonl(vldbEntry.serverNumber[i]);
107 tsockAddr.sin_addr.s_addr = tempAddr;
108 tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
110 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
113 /* if this server was created by fs setserverprefs */
117 osi_assert(tsp != NULL);
119 /* and add it to the list(s). */
121 * Each call to cm_NewServerRef() increments the
122 * ref count of tsp. These reference will be dropped,
123 * if and when the volume is reset; see reset code
124 * earlier in this function.
126 if ((tflags & VLSF_RWVOL)
127 && (vldbEntry.flags & VLF_RWEXISTS)) {
128 tsrp = cm_NewServerRef(tsp);
129 tsrp->next = volp->rwServersp;
130 volp->rwServersp = tsrp;
132 if ((tflags & VLSF_ROVOL)
133 && (vldbEntry.flags & VLF_ROEXISTS)) {
134 tsrp = cm_NewServerRef(tsp);
135 cm_InsertServerList(&volp->roServersp, tsrp);
138 /* We don't use VLSF_BACKVOL !?! */
139 if ((tflags & VLSF_RWVOL)
140 && (vldbEntry.flags & VLF_BACKEXISTS)) {
141 tsrp = cm_NewServerRef(tsp);
142 tsrp->next = volp->bkServersp;
143 volp->bkServersp = tsrp;
145 /* Drop the reference obtained by cm_FindServer() */
152 * If the first n servers have the same ipRank, then we
153 * randomly pick one among them and move it to the beginning.
154 * We don't bother to re-order the whole list because
155 * the rest of the list is used only if the first server is
156 * down. We only do this for the RO list; we assume the other
157 * lists are length 1.
160 cm_RandomizeServer(&volp->roServersp);
166 long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
167 cm_req_t *reqp, cm_volume_t **outVolpp)
170 char volNameString[100];
173 lock_ObtainWrite(&cm_volumeLock);
174 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
175 if (cellp == volp->cellp &&
176 ((unsigned) volumeID == volp->rwID ||
177 (unsigned) volumeID == volp->roID ||
178 (unsigned) volumeID == volp->bkID))
182 /* hold the volume if we found it */
183 if (volp) volp->refCount++;
184 lock_ReleaseWrite(&cm_volumeLock);
188 lock_ObtainMutex(&volp->mx);
190 if (volp->flags & CM_VOLUMEFLAG_RESET) {
191 code = cm_UpdateVolume(cellp, userp, reqp, volp);
193 volp->flags &= ~CM_VOLUMEFLAG_RESET;
198 lock_ReleaseMutex(&volp->mx);
204 /* otherwise, we didn't find it so consult the VLDB */
205 sprintf(volNameString, "%u", volumeID);
206 code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
211 long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
212 struct cm_user *userp, struct cm_req *reqp,
213 long flags, cm_volume_t **outVolpp)
218 /* initialize this */
221 lock_ObtainWrite(&cm_volumeLock);
222 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
223 if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
228 /* otherwise, get from VLDB */
230 volp = malloc(sizeof(*volp));
231 memset(volp, 0, sizeof(*volp));
233 volp->nextp = cm_allVolumesp;
234 cm_allVolumesp = volp;
235 volp->namep = malloc(strlen(volumeNamep)+1);
236 strcpy(volp->namep, volumeNamep);
237 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
238 volp->refCount = 1; /* starts off held */
239 volp->flags |= CM_VOLUMEFLAG_RESET;
245 /* next should work since no one could have gotten ptr to this structure yet */
246 lock_ReleaseWrite(&cm_volumeLock);
247 lock_ObtainMutex(&volp->mx);
249 if (volp->flags & CM_VOLUMEFLAG_RESET) {
250 code = cm_UpdateVolume(cellp, userp, reqp, volp);
252 volp->flags &= ~CM_VOLUMEFLAG_RESET;
257 lock_ReleaseMutex(&volp->mx);
261 void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
267 cellp = cm_FindCellByID(fidp->cell);
270 /* search for the volume */
271 lock_ObtainWrite(&cm_volumeLock);
272 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
273 if (cellp == volp->cellp &&
274 (fidp->volume == volp->rwID ||
275 fidp->volume == volp->roID ||
276 fidp->volume == volp->bkID))
280 /* hold the volume if we found it */
281 if (volp) volp->refCount++;
282 lock_ReleaseWrite(&cm_volumeLock);
286 lock_ObtainMutex(&volp->mx);
287 volp->flags |= CM_VOLUMEFLAG_RESET;
288 code = cm_UpdateVolume(cellp, userp, reqp, volp);
290 volp->flags &= ~CM_VOLUMEFLAG_RESET;
291 lock_ReleaseMutex(&volp->mx);
296 /* find the appropriate servers from a volume */
297 cm_serverRef_t *cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
299 cm_serverRef_t *serversp;
301 if (volume == volp->rwID)
302 serversp = volp->rwServersp;
303 else if (volume == volp->roID)
304 serversp = volp->roServersp;
305 else if (volume == volp->bkID)
306 serversp = volp->bkServersp;
307 else osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
312 void cm_PutVolume(cm_volume_t *volp)
314 lock_ObtainWrite(&cm_volumeLock);
315 osi_assert(volp->refCount-- > 0);
316 lock_ReleaseWrite(&cm_volumeLock);
319 /* return the read-only volume, if there is one, or the read-write volume if
322 long cm_GetROVolumeID(cm_volume_t *volp)
326 lock_ObtainMutex(&volp->mx);
327 if (volp->roID && volp->roServersp)
331 lock_ReleaseMutex(&volp->mx);
336 void cm_CheckVolumes(void)
341 lock_ObtainWrite(&cm_volumeLock);
342 for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
344 lock_ReleaseWrite(&cm_volumeLock);
345 lock_ObtainMutex(&volp->mx);
347 volp->flags |= CM_VOLUMEFLAG_RESET;
349 lock_ReleaseMutex(&volp->mx);
350 lock_ObtainWrite(&cm_volumeLock);
351 osi_assert(volp->refCount-- > 0);
353 lock_ReleaseWrite(&cm_volumeLock);
355 /* We should also refresh cached mount points */
360 ** Finds all volumes that reside on this server and reorders their
361 ** RO list according to the changed rank of server.
363 void cm_ChangeRankVolume(cm_server_t *tsp)
368 /* find volumes which might have RO copy on server*/
369 lock_ObtainWrite(&cm_volumeLock);
370 for(volp = cm_allVolumesp; volp; volp=volp->nextp)
372 code = 1 ; /* assume that list is unchanged */
374 lock_ReleaseWrite(&cm_volumeLock);
375 lock_ObtainMutex(&volp->mx);
377 if ((tsp->cellp==volp->cellp) && (volp->roServersp))
378 code =cm_ChangeRankServer(&volp->roServersp, tsp);
380 /* this volume list was changed */
382 cm_RandomizeServer(&volp->roServersp);
384 lock_ReleaseMutex(&volp->mx);
385 lock_ObtainWrite(&cm_volumeLock);
386 osi_assert(volp->refCount-- > 0);
388 lock_ReleaseWrite(&cm_volumeLock);