Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / afsd / cm_volume.c
1 /* 
2  * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
3  *
4  * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5  * LICENSED MATERIALS - PROPERTY OF IBM
6  *
7  *
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <string.h>
15 #include <malloc.h>
16 #include <winsock2.h>
17 #include <nb30.h>
18 #include <osi.h>
19 #include <rx/rx.h>
20
21 #include "afsd.h"
22
23 osi_rwlock_t cm_volumeLock;
24 cm_volume_t *cm_allVolumesp;
25
26 void cm_InitVolume(void)
27 {
28         static osi_once_t once;
29         if (osi_Once(&once)) {
30                 lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock");
31                 cm_allVolumesp = NULL;
32                 osi_EndOnce(&once);
33         }
34 }
35
36 /*
37  * Update a volume.  Caller holds volume's lock (volp->mx).
38  */
39 long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
40         cm_volume_t *volp)
41 {
42         cm_conn_t *connp;
43         int i;
44         cm_serverRef_t *tsrp;
45         cm_server_t *tsp;
46         struct sockaddr_in tsockAddr;
47         long tflags;
48         u_long tempAddr;
49         struct vldbentry vldbEntry;     /* don't use NVLDB yet; they're not common */
50         int ROcount = 0;
51         long code;
52
53         /* clear out old bindings */
54         while (tsrp = volp->rwServersp) {
55                 volp->rwServersp = tsrp->next;
56                 cm_PutServer(tsrp->server);
57                 free(tsrp);
58         }
59         while (tsrp = volp->roServersp) {
60                 volp->roServersp = tsrp->next;
61                 cm_PutServer(tsrp->server);
62                 free(tsrp);
63         }
64         while (tsrp = volp->bkServersp) {
65                 volp->bkServersp = tsrp->next;
66                 cm_PutServer(tsrp->server);
67                 free(tsrp);
68         }
69
70         /* now we have volume structure locked and held; make RPC to fill it */
71         do {
72                 code = cm_ConnByMServers(cellp->vlServersp, userp, reqp,
73                                          &connp);
74                 if (code) continue;
75                 osi_Log1(afsd_logp, "CALL VL_GetEntryByNameO name %s",
76                          volp->namep);
77                 code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
78         } while (cm_Analyze(connp, userp, reqp, NULL, NULL, NULL, code));
79         code = cm_MapVLRPCError(code, reqp);
80
81         if (code == 0) {
82                 /* decode the response */
83                 lock_ObtainWrite(&cm_volumeLock);
84                 if (vldbEntry.flags & VLF_RWEXISTS)
85                         volp->rwID = vldbEntry.volumeId[0];
86                 else
87                         volp->rwID = 0;
88                 if (vldbEntry.flags & VLF_ROEXISTS)
89                         volp->roID = vldbEntry.volumeId[1];
90                 else
91                         volp->roID = 0;
92                 if (vldbEntry.flags & VLF_BACKEXISTS)
93                         volp->bkID = vldbEntry.volumeId[2];
94                 else
95                         volp->bkID = 0;
96                 lock_ReleaseWrite(&cm_volumeLock);
97                 for(i=0; i<vldbEntry.nServers; i++) {
98                         /* create a server entry */
99                         tflags = vldbEntry.serverFlags[i];
100                         if (tflags & VLSF_DONTUSE) continue;
101                         tsockAddr.sin_family = AF_INET;
102                         tempAddr = htonl(vldbEntry.serverNumber[i]);
103                         tsockAddr.sin_addr.s_addr = tempAddr;
104                         tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
105                         if (!tsp)
106                                 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
107                                                    cellp);
108
109                         /* if this server was created by fs setserverprefs */
110                         if ( !tsp->cellp ) 
111                                 tsp->cellp = cellp;
112
113                         osi_assert(tsp != NULL);
114                         
115                         /* and add it to the list(s). */
116                         /*
117                          * Each call to cm_NewServerRef() increments the
118                          * ref count of tsp.  These reference will be dropped,
119                          * if and when the volume is reset; see reset code
120                          * earlier in this function.
121                          */
122                         if ((tflags & VLSF_RWVOL)
123                             && (vldbEntry.flags & VLF_RWEXISTS)) {
124                                 tsrp = cm_NewServerRef(tsp);
125                                 tsrp->next = volp->rwServersp;
126                                 volp->rwServersp = tsrp;
127                         }
128                         if ((tflags & VLSF_ROVOL)
129                             && (vldbEntry.flags & VLF_ROEXISTS)) {
130                                 tsrp = cm_NewServerRef(tsp);
131                                 cm_InsertServerList(&volp->roServersp, tsrp);
132                                 ROcount++;
133                         }
134                         /* We don't use VLSF_BACKVOL !?! */
135                         if ((tflags & VLSF_RWVOL)
136                             && (vldbEntry.flags & VLF_BACKEXISTS)) {
137                                 tsrp = cm_NewServerRef(tsp);
138                                 tsrp->next = volp->bkServersp;
139                                 volp->bkServersp = tsrp;
140                         }
141                         /* Drop the reference obtained by cm_FindServer() */
142                         cm_PutServer(tsp);
143                 }
144
145                 /*
146                  * Randomize RO list
147                  *
148                  * If the first n servers have the same ipRank, then we 
149                  * randomly pick one among them and move it to the beginning.
150                  * We don't bother to re-order the whole list because
151                  * the rest of the list is used only if the first server is
152                  * down.  We only do this for the RO list; we assume the other
153                  * lists are length 1.
154                  */
155                 if (ROcount > 1) {
156                         cm_RandomizeServer(&volp->roServersp);
157                 }
158         }
159         return code;
160 }
161
162 long cm_GetVolumeByID(cm_cell_t *cellp, long volumeID, cm_user_t *userp,
163         cm_req_t *reqp, cm_volume_t **outVolpp)
164 {
165         cm_volume_t *volp;
166         char volNameString[100];
167         long code;
168
169         lock_ObtainWrite(&cm_volumeLock);
170         for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
171                 if (cellp == volp->cellp &&
172                         ((unsigned) volumeID == volp->rwID ||
173                          (unsigned) volumeID == volp->roID ||
174                          (unsigned) volumeID == volp->bkID))
175                                 break;
176         }
177
178         /* hold the volume if we found it */
179         if (volp) volp->refCount++;
180         lock_ReleaseWrite(&cm_volumeLock);
181         
182         /* return it held */
183         if (volp) {
184                 lock_ObtainMutex(&volp->mx);
185         
186                 if (volp->flags & CM_VOLUMEFLAG_RESET) {
187                         code = cm_UpdateVolume(cellp, userp, reqp, volp);
188                         if (code == 0) {
189                                 volp->flags &= ~CM_VOLUMEFLAG_RESET;
190                         }
191                 }
192                 else
193                         code = 0;
194                 lock_ReleaseMutex(&volp->mx);
195                 if (code == 0)
196                         *outVolpp = volp;
197                 return code;
198         }
199         
200         /* otherwise, we didn't find it so consult the VLDB */
201         sprintf(volNameString, "%u", volumeID);
202         code = cm_GetVolumeByName(cellp, volNameString, userp, reqp,
203                                   0, outVolpp);
204         return code;
205 }
206
207 long cm_GetVolumeByName(struct cm_cell *cellp, char *volumeNamep,
208         struct cm_user *userp, struct cm_req *reqp,
209         long flags, cm_volume_t **outVolpp)
210 {
211         cm_volume_t *volp;
212         long code;
213         
214         /* initialize this */
215         code = 0;
216
217         lock_ObtainWrite(&cm_volumeLock);
218         for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
219                 if (cellp == volp->cellp && strcmp(volumeNamep, volp->namep) == 0) {
220                         break;
221                 }
222         }
223         
224         /* otherwise, get from VLDB */
225         if (!volp) {
226                 volp = malloc(sizeof(*volp));
227                 memset(volp, 0, sizeof(*volp));
228                 volp->cellp = cellp;
229                 volp->nextp = cm_allVolumesp;
230                 cm_allVolumesp = volp;
231                 volp->namep = malloc(strlen(volumeNamep)+1);
232                 strcpy(volp->namep, volumeNamep);
233                 lock_InitializeMutex(&volp->mx, "cm_volume_t mutex");
234                 volp->refCount = 1;     /* starts off held */
235                 volp->flags |= CM_VOLUMEFLAG_RESET;
236         }
237         else {
238                 volp->refCount++;
239         }
240         
241         /* next should work since no one could have gotten ptr to this structure yet */
242         lock_ReleaseWrite(&cm_volumeLock);
243         lock_ObtainMutex(&volp->mx);
244         
245         if (volp->flags & CM_VOLUMEFLAG_RESET) {
246                 code = cm_UpdateVolume(cellp, userp, reqp, volp);
247                 if (code == 0)
248                         volp->flags &= ~CM_VOLUMEFLAG_RESET;
249         }
250
251         if (code == 0)
252                 *outVolpp = volp;
253         lock_ReleaseMutex(&volp->mx);
254         return code;
255 }
256
257 void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
258 {
259         cm_cell_t *cellp;
260         cm_volume_t *volp;
261         long code;
262
263         cellp = cm_FindCellByID(fidp->cell);
264         if (!cellp) return;
265
266         /* search for the volume */
267         lock_ObtainWrite(&cm_volumeLock);
268         for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
269                 if (cellp == volp->cellp &&
270                         (fidp->volume == volp->rwID ||
271                          fidp->volume == volp->roID ||
272                          fidp->volume == volp->bkID))
273                                 break;
274         }
275
276         /* hold the volume if we found it */
277         if (volp) volp->refCount++;
278         lock_ReleaseWrite(&cm_volumeLock);
279
280         /* update it */
281         cm_mountRootGen++;
282         lock_ObtainMutex(&volp->mx);
283         volp->flags |= CM_VOLUMEFLAG_RESET;
284         code = cm_UpdateVolume(cellp, userp, reqp, volp);
285         if (code == 0)
286                 volp->flags &= ~CM_VOLUMEFLAG_RESET;
287         lock_ReleaseMutex(&volp->mx);
288
289         cm_PutVolume(volp);
290 }
291
292 /* find the appropriate servers from a volume */
293 cm_serverRef_t *cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
294 {
295         cm_serverRef_t *serversp;
296
297         if (volume == volp->rwID)
298                 serversp = volp->rwServersp;
299         else if (volume == volp->roID)
300                 serversp = volp->roServersp;
301         else if (volume == volp->bkID)
302                 serversp = volp->bkServersp;
303         else osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
304         
305         return serversp;
306 }
307
308 void cm_PutVolume(cm_volume_t *volp)
309 {
310         lock_ObtainWrite(&cm_volumeLock);
311         osi_assert(volp->refCount-- > 0);
312         lock_ReleaseWrite(&cm_volumeLock);
313 }
314
315 /* return the read-only volume, if there is one, or the read-write volume if
316  * not.
317  */
318 long cm_GetROVolumeID(cm_volume_t *volp)
319 {
320         long id;
321
322         lock_ObtainMutex(&volp->mx);
323         if (volp->roID && volp->roServersp)
324                 id = volp->roID;
325         else
326                 id = volp->rwID;
327         lock_ReleaseMutex(&volp->mx);
328
329         return id;
330 }
331
332 void cm_CheckVolumes(void)
333 {
334         cm_volume_t *volp;
335
336         cm_mountRootGen++;
337         lock_ObtainWrite(&cm_volumeLock);
338         for(volp = cm_allVolumesp; volp; volp=volp->nextp) {
339                 volp->refCount++;
340                 lock_ReleaseWrite(&cm_volumeLock);
341                 lock_ObtainMutex(&volp->mx);
342
343                 volp->flags |= CM_VOLUMEFLAG_RESET;
344
345                 lock_ReleaseMutex(&volp->mx);
346                 lock_ObtainWrite(&cm_volumeLock);
347                 osi_assert(volp->refCount-- > 0);
348         }
349         lock_ReleaseWrite(&cm_volumeLock);
350
351         /* We should also refresh cached mount points */
352
353 }
354
355 /*
356 ** Finds all volumes that reside on this server and reorders their
357 ** RO list according to the changed rank of server.
358 */
359 void cm_ChangeRankVolume(cm_server_t       *tsp)
360 {
361         int             code;
362         cm_volume_t*    volp;
363
364         /* find volumes which might have RO copy on server*/
365         lock_ObtainWrite(&cm_volumeLock);
366         for(volp = cm_allVolumesp; volp; volp=volp->nextp)
367         {
368                 code = 1 ;      /* assume that list is unchanged */
369                 volp->refCount++;
370                 lock_ReleaseWrite(&cm_volumeLock);
371                 lock_ObtainMutex(&volp->mx);
372
373                 if ((tsp->cellp==volp->cellp) && (volp->roServersp))
374                     code =cm_ChangeRankServer(&volp->roServersp, tsp);
375
376                 /* this volume list was changed */
377                 if ( !code )
378                         cm_RandomizeServer(&volp->roServersp);
379
380                 lock_ReleaseMutex(&volp->mx);
381                 lock_ObtainWrite(&cm_volumeLock);
382                 osi_assert(volp->refCount-- > 0);
383         }
384         lock_ReleaseWrite(&cm_volumeLock);
385 }