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