afsconfig-and-rcsid-all-around-20010705
[openafs.git] / src / afs / afs_cell.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Implements:
12  */
13 #include "../afs/param.h"       /* Should be always first */
14 #include <afsconfig.h>
15
16 RCSID("$Header$");
17
18 #include "../afs/stds.h"
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
20
21 #if !defined(UKERNEL)
22 #include <net/if.h>
23 #include <netinet/in.h>
24
25 #ifdef AFS_SGI62_ENV
26 #include "../h/hashing.h"
27 #endif
28 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
29 #include <netinet/in_var.h>
30 #endif /* ! ASF_HPUX110_ENV */
31 #endif /* !defined(UKERNEL) */
32
33 #include "../afs/afsincludes.h" /* Afs-based standard headers */
34 #include "../afs/afs_stats.h"   /* afs statistics */
35
36 #if     defined(AFS_SUN56_ENV)
37 #include <inet/led.h>
38 #include <inet/common.h>
39 #if     defined(AFS_SUN58_ENV)
40 #include <netinet/ip6.h>
41 #endif
42 #include <inet/ip.h>
43 #endif
44
45 /* Exported variables */
46 afs_rwlock_t afs_xcell;                 /* allocation lock for cells */
47 struct afs_q CellLRU;
48 afs_int32 afs_cellindex=0;
49 afs_uint32 afs_nextCellNum = 0x100;
50
51
52 /* Local variables. */
53 struct cell *afs_rootcell = 0;
54
55 static char afs_AfsdbHandlerWait;
56 static char afs_AfsdbLookupWait;
57
58 char afs_AfsdbHandlerPresent = 0;
59 char afs_AfsdbHandlerInuse = 0;
60
61 char *afs_AfsdbHandler_CellName;
62 afs_int32 *afs_AfsdbHandler_CellHosts;
63 int *afs_AfsdbHandler_Timeout;
64
65 char afs_AfsdbHandler_ReqPending;
66 char afs_AfsdbHandler_Completed;
67
68
69 struct cell *afs_GetCellByName_int();
70
71 int afs_strcasecmp(s1, s2)
72     register char *s1, *s2;
73 {
74     while (*s1 && *s2) {
75         register char c1, c2;
76
77         c1 = *s1++;
78         c2 = *s2++;
79         if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
80         if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
81         if (c1 != c2)
82             return c1-c2;
83     }
84
85     return *s1 - *s2;
86 }
87
88
89 #ifdef AFS_AFSDB_ENV
90 int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
91     char *acellName;
92     int acellNameLen;
93     afs_int32 *kernelMsg;
94 {
95     /* afs_syscall_call() has already grabbed the global lock */
96
97     afs_AfsdbHandlerPresent = 1;
98
99     if (afs_AfsdbHandler_ReqPending) {
100         int i, hostCount;
101
102         hostCount = kernelMsg[0];
103         *afs_AfsdbHandler_Timeout = kernelMsg[1];
104         if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
105
106         for (i=0; i<MAXCELLHOSTS; i++) {
107             if (i >= hostCount)
108                 afs_AfsdbHandler_CellHosts[i] = 0;
109             else
110                 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
111         }
112
113         /* Request completed, wake up the relevant thread */
114         afs_AfsdbHandler_ReqPending = 0;
115         afs_AfsdbHandler_Completed = 1;
116         afs_osi_Wakeup(&afs_AfsdbLookupWait);
117     }
118
119     /* Wait for a request */
120     while (afs_AfsdbHandler_ReqPending == 0)
121         afs_osi_Sleep(&afs_AfsdbHandlerWait);
122
123     /* Copy the requested cell name into the request buffer */
124     strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
125
126     /* Return the lookup request to userspace */    
127     return 0;
128 }
129 #endif
130
131
132 int afs_GetCellHostsFromDns(acellName, acellHosts, timeout)
133     char *acellName;
134     afs_int32 *acellHosts;
135     int *timeout;
136 {
137 #ifdef AFS_AFSDB_ENV
138     char grab_glock = 0;
139
140     if (!afs_AfsdbHandlerPresent) return ENOENT;
141
142     if (!ISAFS_GLOCK()) {
143         grab_glock = 1;
144         AFS_GLOCK();
145     }
146
147     /* Wait until the AFSDB handler is available, and grab it */
148     while (afs_AfsdbHandlerInuse)
149         afs_osi_Sleep(&afs_AfsdbLookupWait);
150     afs_AfsdbHandlerInuse = 1;
151
152     /* Set up parameters for the handler */
153     afs_AfsdbHandler_CellName = acellName;
154     afs_AfsdbHandler_CellHosts = acellHosts;
155     afs_AfsdbHandler_Timeout = timeout;
156
157     /* Wake up the AFSDB handler */
158     afs_AfsdbHandler_Completed = 0;
159     afs_AfsdbHandler_ReqPending = 1;
160     afs_osi_Wakeup(&afs_AfsdbHandlerWait);
161
162     /* Wait for the handler to get back to us with the reply */
163     while (!afs_AfsdbHandler_Completed)
164         afs_osi_Sleep(&afs_AfsdbLookupWait);
165
166     /* Release the AFSDB handler and wake up others waiting for it */
167     afs_AfsdbHandlerInuse = 0;
168     afs_osi_Wakeup(&afs_AfsdbLookupWait);
169
170     if (grab_glock) AFS_GUNLOCK();
171
172     if (*acellHosts) return 0;
173     return ENOENT;
174 #else
175     return ENOENT;
176 #endif
177 }
178
179
180 void afs_RefreshCell(tc)
181     register struct cell *tc;
182 {
183     afs_int32 acellHosts[MAXCELLHOSTS];
184     int timeout;
185
186     /* Don't need to do anything if no timeout or it's not expired */
187     if (!tc->timeout || tc->timeout > osi_Time()) return;
188
189     if (!afs_GetCellHostsFromDns(tc->cellName, acellHosts, &timeout)) {
190         afs_NewCell(tc->cellName, acellHosts, tc->states,
191                     tc->lcellp ? tc->lcellp->cellName : (char *) 0,
192                     tc->fsport, tc->vlport, timeout);
193     }
194
195     /* In case of a DNS failure, keep old cell data.. */
196     return;
197 }
198
199
200 struct cell *afs_GetCellByName_Dns(acellName, locktype)
201     register char *acellName;
202     afs_int32 locktype;
203 {
204     afs_int32 acellHosts[MAXCELLHOSTS];
205     int timeout;
206
207     if (afs_GetCellHostsFromDns(acellName, acellHosts, &timeout))
208         return (struct cell *) 0;
209     if (afs_NewCell(acellName, acellHosts, CNoSUID, (char *) 0, 0, 0, timeout))
210         return (struct cell *) 0;
211
212     return afs_GetCellByName_int(acellName, locktype, 0);
213 }
214
215
216 struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
217     register char *acellName;
218     afs_int32 locktype;
219     char trydns;
220 {
221     register struct cell *tc;
222     register struct afs_q *cq, *tq;
223
224     AFS_STATCNT(afs_GetCellByName);
225     ObtainWriteLock(&afs_xcell,100);
226     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
227         tc = QTOC(cq); tq = QNext(cq);
228         if (!afs_strcasecmp(tc->cellName, acellName)) {
229             QRemove(&tc->lruq);
230             QAdd(&CellLRU, &tc->lruq);
231             ReleaseWriteLock(&afs_xcell);
232             afs_RefreshCell(tc);
233             return tc;
234         }
235     }
236     ReleaseWriteLock(&afs_xcell);
237     return trydns ? afs_GetCellByName_Dns(acellName, locktype)
238                   : (struct cell *) 0;
239
240 } /*afs_GetCellByName_int*/
241
242
243 struct cell *afs_GetCellByName(acellName, locktype)
244     register char *acellName;
245     afs_int32 locktype;
246 {
247     return afs_GetCellByName_int(acellName, locktype, 1);
248
249 } /*afs_GetCellByName*/
250
251
252 struct cell *afs_GetCell(acell, locktype)
253     register afs_int32 acell;
254     afs_int32 locktype;
255 {
256     register struct cell *tc;
257     register struct afs_q *cq, *tq;
258
259     AFS_STATCNT(afs_GetCell);
260     if (acell == 1 && afs_rootcell) return afs_rootcell;
261     ObtainWriteLock(&afs_xcell,101);
262     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
263         tc = QTOC(cq); tq = QNext(cq);
264         if (tc->cell == acell) {
265             QRemove(&tc->lruq);
266             QAdd(&CellLRU, &tc->lruq);
267             ReleaseWriteLock(&afs_xcell);
268             afs_RefreshCell(tc);
269             return tc;
270         }
271     }
272     ReleaseWriteLock(&afs_xcell);
273     return (struct cell *) 0;
274
275 } /*afs_GetCell*/
276
277
278 struct cell *afs_GetCellByIndex(cellindex, locktype)
279     register afs_int32 cellindex;
280     afs_int32 locktype;
281 {
282     register struct cell *tc;
283     register struct afs_q *cq, *tq;
284
285     AFS_STATCNT(afs_GetCellByIndex);
286     ObtainWriteLock(&afs_xcell,102);
287     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
288         tc = QTOC(cq); tq = QNext(cq);
289         if (tc->cellIndex == cellindex) {
290             QRemove(&tc->lruq);
291             QAdd(&CellLRU, &tc->lruq);
292             ReleaseWriteLock(&afs_xcell);
293             afs_RefreshCell(tc);
294             return tc;
295         }
296     }
297     ReleaseWriteLock(&afs_xcell);
298     return (struct cell *) 0;
299
300 } /*afs_GetCellByIndex*/
301
302
303 afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout)
304     int aflags;
305     char *acellName;
306     register afs_int32 *acellHosts;
307     char *linkedcname;
308     u_short fsport, vlport;
309     int timeout;
310 {
311     register struct cell *tc, *tcl=0;
312     register afs_int32 i, newc=0, code=0;
313     register struct afs_q *cq, *tq;
314
315     AFS_STATCNT(afs_NewCell);
316     if (*acellHosts == 0)
317         /* need >= one host to gen cell # */
318         return EINVAL;
319
320     ObtainWriteLock(&afs_xcell,103);
321
322     /* Find the cell and mark its servers as not down but gone */
323     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
324         tc = QTOC(cq); tq = QNext(cq);
325         if (afs_strcasecmp(tc->cellName, acellName) == 0) {
326             /* we don't want to keep pinging old vlservers which were down,
327              * since they don't matter any more.  It's easier to do this than
328              * to remove the server from its various hash tables. */
329             for (i=0; i<MAXCELLHOSTS; i++) {
330                 if (!tc->cellHosts[i]) break;
331                 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
332                 tc->cellHosts[i]->flags |= SRVR_ISGONE;
333             }
334             break;
335         }
336     }
337
338     if (cq != &CellLRU) {
339         aflags &= ~CNoSUID;
340     }
341     else {
342         tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
343         QAdd(&CellLRU, &tc->lruq);                      /* put in lruq */
344         tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
345         strcpy(tc->cellName, acellName);
346         tc->cellIndex = afs_cellindex++;
347         if (aflags & CPrimary) {
348             extern int afs_rootCellIndex;
349             tc->cell = 1;       /* primary cell is always 1 */
350             afs_rootcell = tc;
351             afs_rootCellIndex = tc->cellIndex;
352         } else {
353             tc->cell = afs_nextCellNum++;
354         }
355         tc->states = 0;
356         tc->lcellp = (struct cell *)0;
357         tc->fsport = (fsport ? fsport : AFS_FSPORT);
358         tc->vlport = (vlport ? vlport : AFS_VLPORT);
359         afs_stats_cmperf.numCellsVisible++;
360         newc++;
361     }
362
363     if (aflags & CLinkedCell) {
364         if (!linkedcname) {
365             code = EINVAL;
366             goto bad;
367         }
368         for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
369             tcl = QTOC(cq); tq = QNext(cq);
370             if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
371                 break;
372             }
373             tcl = 0;
374         }
375         if (!tcl) {
376             code = ENOENT;
377             goto bad;
378         }
379         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
380             tcl->lcellp->lcellp = (struct cell *)0;
381             tcl->lcellp->states &= ~CLinkedCell;
382         }
383         tc->lcellp = tcl;
384         tcl->lcellp = tc;
385     }
386     tc->states |= aflags;
387     tc->timeout = timeout;
388  
389     bzero((char *)tc->cellHosts, sizeof(tc->cellHosts));
390     for (i=0; i<MAXCELLHOSTS; i++) {
391         struct server *ts;
392         afs_uint32 temp = acellHosts[i];
393         if (!temp) break;
394         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
395         ts->cell = tc;
396         ts->flags &= ~SRVR_ISGONE;
397         tc->cellHosts[i] = ts;
398         afs_PutServer(ts, WRITE_LOCK);
399     }
400     afs_SortServers(tc->cellHosts, MAXCELLHOSTS);       /* randomize servers */
401     ReleaseWriteLock(&afs_xcell);
402     return 0;
403 bad:
404     if (newc) {
405         QRemove(&tc->lruq);
406         afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
407         afs_osi_Free((char *)tc, sizeof(struct cell));
408     }
409     ReleaseWriteLock(&afs_xcell);
410     return code;
411
412 } /*afs_NewCell*/
413
414 afs_RemoveCellEntry(struct server *srvp)
415 {
416   struct cell *tc;
417   afs_int32 j, k;
418
419   tc = srvp->cell;
420   if (!tc) return;
421
422   /* Remove the server structure from the cell list - if there */
423   ObtainWriteLock(&afs_xcell,200);
424   for (j=k=0; j<MAXCELLHOSTS; j++) {
425      if (!tc->cellHosts[j]) break;
426      if (tc->cellHosts[j] != srvp) {
427         tc->cellHosts[k++] = tc->cellHosts[j];
428      }
429   }
430   if (k == 0) {
431      /* What do we do if we remove the last one? */
432   }
433   for (; k<MAXCELLHOSTS; k++) {
434      tc->cellHosts[k] = 0;
435   }
436   ReleaseWriteLock(&afs_xcell);
437 }
438