cell-alias-support-fix-memory-leak-20011010
[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 <afsconfig.h>
14 #include "../afs/param.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 /* Handler waiting for request from client */
56 static char afs_AfsdbHandlerWait;
57 /* Client waiting for handler to become available or finish request */
58 static char afs_AfsdbLookupWait;
59
60 /* Set to 1 when we've seen the userspace AFSDB process at least once */
61 char afs_AfsdbHandlerPresent = 0;
62 /* Set to 1 when there is a client interacting with the AFSDB handler.
63  * Protects the in and out variables below.  Protected by GLOCK. */
64 char afs_AfsdbHandlerInuse = 0;
65 /* Set to 1 when AFSDB has been shut down */
66 char afs_AfsdbHandlerShutdown = 0;
67
68 /* Input to handler from the client: cell name to look up */
69 char *afs_AfsdbHandler_CellName;
70 /* Outputs from handler to client: cell hosts, TTL, and real cell name */
71 afs_int32 *afs_AfsdbHandler_CellHosts;
72 int *afs_AfsdbHandler_Timeout;
73 char **afs_AfsdbHandler_RealName;
74
75 /* Client sets ReqPending to 1 whenever it queues a request for it */
76 char afs_AfsdbHandler_ReqPending = 0;
77 /* Handler sets Completed to 1 when it completes the client request */
78 char afs_AfsdbHandler_Completed = 0;
79
80
81 static struct cell *afs_GetCellByName_int();
82
83 int afs_strcasecmp(s1, s2)
84     register char *s1, *s2;
85 {
86     while (*s1 && *s2) {
87         register char c1, c2;
88
89         c1 = *s1++;
90         c2 = *s2++;
91         if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
92         if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
93         if (c1 != c2)
94             return c1-c2;
95     }
96
97     return *s1 - *s2;
98 }
99
100
101 #ifdef AFS_AFSDB_ENV
102 void afs_StopAfsdb()
103 {
104     if (afs_AfsdbHandlerPresent) {
105         afs_osi_Wakeup(&afs_AfsdbHandlerWait);
106     } else {
107         afs_AfsdbHandlerShutdown = 1;
108         afs_termState = AFSOP_STOP_RXEVENT;
109     }
110 }
111
112 int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
113     char *acellName;
114     int acellNameLen;
115     afs_int32 *kernelMsg;
116 {
117     /* afs_syscall_call() has already grabbed the global lock */
118
119     if (afs_AfsdbHandlerShutdown) return -2;
120     afs_AfsdbHandlerPresent = 1;
121
122     if (afs_AfsdbHandler_ReqPending) {
123         int i, hostCount;
124
125         hostCount = kernelMsg[0];
126         *afs_AfsdbHandler_Timeout = kernelMsg[1];
127         if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
128
129         *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
130         strcpy(*afs_AfsdbHandler_RealName, acellName);
131
132         for (i=0; i<MAXCELLHOSTS; i++) {
133             if (i >= hostCount)
134                 afs_AfsdbHandler_CellHosts[i] = 0;
135             else
136                 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
137         }
138
139         /* Request completed, wake up the relevant thread */
140         afs_AfsdbHandler_ReqPending = 0;
141         afs_AfsdbHandler_Completed = 1;
142         afs_osi_Wakeup(&afs_AfsdbLookupWait);
143     }
144
145     /* Wait for a request */
146     while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
147         afs_osi_Sleep(&afs_AfsdbHandlerWait);
148
149     /* Check if we're shutting down */
150     if (afs_termState == AFSOP_STOP_AFSDB) {
151         /* Inform anyone waiting for us that we're going away */
152         afs_AfsdbHandlerShutdown = 1;
153         afs_AfsdbHandlerPresent = 0;
154         afs_osi_Wakeup(&afs_AfsdbLookupWait);
155
156         afs_termState = AFSOP_STOP_RXEVENT;
157         afs_osi_Wakeup(&afs_termState);
158         return -2;
159     }
160
161     /* Copy the requested cell name into the request buffer */
162     strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
163
164     /* Return the lookup request to userspace */    
165     return 0;
166 }
167 #endif
168
169
170 int afs_GetCellHostsFromDns(acellName, acellHosts, timeout, realName)
171     char *acellName;
172     afs_int32 *acellHosts;
173     int *timeout;
174     char **realName;
175 {
176 #ifdef AFS_AFSDB_ENV
177     char grab_glock = 0;
178
179     if (!afs_AfsdbHandlerPresent) return ENOENT;
180
181     /* Initialize host list to empty in case the handler is gone */
182     *acellHosts = 0;
183
184     if (!ISAFS_GLOCK()) {
185         grab_glock = 1;
186         AFS_GLOCK();
187     }
188
189     /* Wait until the AFSDB handler is available, and grab it */
190     while (afs_AfsdbHandlerInuse)
191         afs_osi_Sleep(&afs_AfsdbLookupWait);
192     afs_AfsdbHandlerInuse = 1;
193
194     /* Set up parameters for the handler */
195     afs_AfsdbHandler_CellName = acellName;
196     afs_AfsdbHandler_CellHosts = acellHosts;
197     afs_AfsdbHandler_Timeout = timeout;
198     afs_AfsdbHandler_RealName = realName;
199
200     /* Wake up the AFSDB handler */
201     afs_AfsdbHandler_Completed = 0;
202     afs_AfsdbHandler_ReqPending = 1;
203     afs_osi_Wakeup(&afs_AfsdbHandlerWait);
204
205     /* Wait for the handler to get back to us with the reply */
206     while (afs_AfsdbHandlerPresent && !afs_AfsdbHandler_Completed)
207         afs_osi_Sleep(&afs_AfsdbLookupWait);
208
209     /* Release the AFSDB handler and wake up others waiting for it */
210     afs_AfsdbHandlerInuse = 0;
211     afs_osi_Wakeup(&afs_AfsdbLookupWait);
212
213     if (grab_glock) AFS_GUNLOCK();
214
215     if (*acellHosts) return 0;
216     return ENOENT;
217 #else
218     return ENOENT;
219 #endif
220 }
221
222
223 void afs_RefreshCell(tc)
224     register struct cell *tc;
225 {
226     afs_int32 cellHosts[MAXCELLHOSTS];
227     char *realName = NULL;
228     int timeout;
229
230     /* Don't need to do anything if no timeout or it's not expired */
231     if (!tc->timeout || tc->timeout > osi_Time()) return;
232
233     if (afs_GetCellHostsFromDns(tc->cellName, cellHosts, &timeout, &realName))
234         /* In case of lookup failure, keep old data */
235         goto done;
236
237     /* Refresh the DB servers for the real cell; other values stay the same. */
238     afs_NewCell(realName, cellHosts, 0, (char *) 0, 0, 0, timeout, (char *) 0);
239
240     /* If this is an alias, update the alias entry too */
241     if (afs_strcasecmp(tc->cellName, realName))
242         afs_NewCell(tc->cellName, 0, CAlias, (char *) 0, 0, 0,
243                     timeout, realName);
244
245 done:
246     if (realName)
247         afs_osi_Free(realName, strlen(realName) + 1);
248 }
249
250
251 struct cell *afs_GetCellByName_Dns(acellName, locktype)
252     register char *acellName;
253     afs_int32 locktype;
254 {
255     afs_int32 cellHosts[MAXCELLHOSTS];
256     char *realName = NULL;
257     int timeout;
258
259     if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
260         goto bad;
261     if (afs_NewCell(realName, cellHosts, CNoSUID, (char *) 0, 0, 0,
262                     timeout, (char *) 0))
263         goto bad;
264
265     /* If this is an alias, create an entry for it too */
266     if (afs_strcasecmp(acellName, realName)) {
267         if (afs_NewCell(acellName, 0, CAlias, (char *) 0, 0, 0,
268                         timeout, realName))
269             goto bad;
270     }
271
272     if (realName)
273         afs_osi_Free(realName, strlen(realName) + 1);
274     return afs_GetCellByName_int(acellName, locktype, 0);
275
276 bad:
277     if (realName)
278         afs_osi_Free(realName, strlen(realName) + 1);
279     return (struct cell *) 0;
280 }
281
282
283 static struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
284     register char *acellName;
285     afs_int32 locktype;
286     char trydns;
287 {
288     register struct cell *tc;
289     register struct afs_q *cq, *tq;
290
291     AFS_STATCNT(afs_GetCellByName);
292     ObtainWriteLock(&afs_xcell,100);
293     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
294         tc = QTOC(cq); tq = QNext(cq);
295         if (!afs_strcasecmp(tc->cellName, acellName)) {
296             QRemove(&tc->lruq);
297             QAdd(&CellLRU, &tc->lruq);
298             ReleaseWriteLock(&afs_xcell);
299             afs_RefreshCell(tc);
300             if (tc->states & CAlias) {
301                 tc = tc->alias;
302                 afs_RefreshCell(tc);
303             }
304             return tc;
305         }
306     }
307     ReleaseWriteLock(&afs_xcell);
308     return trydns ? afs_GetCellByName_Dns(acellName, locktype)
309                   : (struct cell *) 0;
310
311 } /*afs_GetCellByName_int*/
312
313
314 struct cell *afs_GetCellByName(acellName, locktype)
315     register char *acellName;
316     afs_int32 locktype;
317 {
318     return afs_GetCellByName_int(acellName, locktype, 1);
319
320 } /*afs_GetCellByName*/
321
322
323 struct cell *afs_GetCell(acell, locktype)
324     register afs_int32 acell;
325     afs_int32 locktype;
326 {
327     register struct cell *tc;
328     register struct afs_q *cq, *tq;
329
330     AFS_STATCNT(afs_GetCell);
331     if (acell == 1 && afs_rootcell) return afs_rootcell;
332     ObtainWriteLock(&afs_xcell,101);
333     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
334         tc = QTOC(cq); tq = QNext(cq);
335         if (tc->cell == acell) {
336             QRemove(&tc->lruq);
337             QAdd(&CellLRU, &tc->lruq);
338             ReleaseWriteLock(&afs_xcell);
339             afs_RefreshCell(tc);
340             return tc;
341         }
342     }
343     ReleaseWriteLock(&afs_xcell);
344     return (struct cell *) 0;
345
346 } /*afs_GetCell*/
347
348
349 struct cell *afs_GetCellByIndex(cellindex, locktype)
350     register afs_int32 cellindex;
351     afs_int32 locktype;
352 {
353     register struct cell *tc;
354     register struct afs_q *cq, *tq;
355
356     AFS_STATCNT(afs_GetCellByIndex);
357     ObtainWriteLock(&afs_xcell,102);
358     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
359         tc = QTOC(cq); tq = QNext(cq);
360         if (tc->cellIndex == cellindex) {
361             QRemove(&tc->lruq);
362             QAdd(&CellLRU, &tc->lruq);
363             ReleaseWriteLock(&afs_xcell);
364             afs_RefreshCell(tc);
365             return tc;
366         }
367     }
368     ReleaseWriteLock(&afs_xcell);
369     return (struct cell *) 0;
370
371 } /*afs_GetCellByIndex*/
372
373
374 afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout, aliasFor)
375     int aflags;
376     char *acellName;
377     register afs_int32 *acellHosts;
378     char *linkedcname;
379     u_short fsport, vlport;
380     int timeout;
381     char *aliasFor;
382 {
383     register struct cell *tc, *tcl=0;
384     register afs_int32 i, newc=0, code=0;
385     register struct afs_q *cq, *tq;
386
387     AFS_STATCNT(afs_NewCell);
388     if (!(aflags & CAlias) && *acellHosts == 0)
389         /* need >= one host to gen cell # */
390         return EINVAL;
391
392     ObtainWriteLock(&afs_xcell,103);
393
394     /* Find the cell and mark its servers as not down but gone */
395     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
396         tc = QTOC(cq); tq = QNext(cq);
397         if (afs_strcasecmp(tc->cellName, acellName) == 0) {
398             /* if the cell we've found has the correct name but no timeout,
399              * and we're called with a non-zero timeout, bail out:  never
400              * override static configuration entries with AFSDB ones. */
401             if (timeout && !tc->timeout) {
402                 ReleaseWriteLock(&afs_xcell);
403                 return 0;
404             }
405             /* we don't want to keep pinging old vlservers which were down,
406              * since they don't matter any more.  It's easier to do this than
407              * to remove the server from its various hash tables. */
408             for (i=0; i<MAXCELLHOSTS; i++) {
409                 if (!tc->cellHosts[i]) break;
410                 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
411                 tc->cellHosts[i]->flags |= SRVR_ISGONE;
412             }
413             break;
414         }
415     }
416
417     if (cq != &CellLRU) {
418         aflags &= ~CNoSUID;
419     }
420     else {
421         tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
422         QAdd(&CellLRU, &tc->lruq);                      /* put in lruq */
423         tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
424         strcpy(tc->cellName, acellName);
425         tc->cellIndex = afs_cellindex++;
426         if (aflags & CPrimary) {
427             extern int afs_rootCellIndex;
428             tc->cell = 1;       /* primary cell is always 1 */
429             afs_rootcell = tc;
430             afs_rootCellIndex = tc->cellIndex;
431         } else {
432             tc->cell = afs_nextCellNum++;
433         }
434         tc->states = 0;
435         tc->lcellp = (struct cell *)0;
436         tc->fsport = (fsport ? fsport : AFS_FSPORT);
437         tc->vlport = (vlport ? vlport : AFS_VLPORT);
438         afs_stats_cmperf.numCellsVisible++;
439         newc++;
440     }
441
442     if (aflags & CLinkedCell) {
443         if (!linkedcname) {
444             code = EINVAL;
445             goto bad;
446         }
447         for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
448             tcl = QTOC(cq); tq = QNext(cq);
449             if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
450                 break;
451             }
452             tcl = 0;
453         }
454         if (!tcl) {
455             code = ENOENT;
456             goto bad;
457         }
458         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
459             tcl->lcellp->lcellp = (struct cell *)0;
460             tcl->lcellp->states &= ~CLinkedCell;
461         }
462         tc->lcellp = tcl;
463         tcl->lcellp = tc;
464     }
465     tc->states |= aflags;
466     tc->timeout = timeout;
467  
468     memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
469     if (aflags & CAlias) {
470         struct cell *tca = NULL;
471
472         if (!aliasFor) {
473             code = EINVAL;
474             goto bad;
475         }
476         for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
477             tca = QTOC(cq); tq = QNext(cq);
478             if (!afs_strcasecmp(tca->cellName, aliasFor))
479                 break;
480         }
481         if (!tca) {
482             code = ENOENT;
483             goto bad;
484         }
485         tc->alias = tca;
486         goto done;
487     }
488
489     for (i=0; i<MAXCELLHOSTS; i++) {
490         struct server *ts;
491         afs_uint32 temp = acellHosts[i];
492         if (!temp) break;
493         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
494         ts->cell = tc;
495         ts->flags &= ~SRVR_ISGONE;
496         tc->cellHosts[i] = ts;
497         afs_PutServer(ts, WRITE_LOCK);
498     }
499     afs_SortServers(tc->cellHosts, MAXCELLHOSTS);       /* randomize servers */
500 done:
501     ReleaseWriteLock(&afs_xcell);
502     return 0;
503 bad:
504     if (newc) {
505         QRemove(&tc->lruq);
506         afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
507         afs_osi_Free((char *)tc, sizeof(struct cell));
508     }
509     ReleaseWriteLock(&afs_xcell);
510     return code;
511
512 } /*afs_NewCell*/
513
514 afs_RemoveCellEntry(struct server *srvp)
515 {
516   struct cell *tc;
517   afs_int32 j, k;
518
519   tc = srvp->cell;
520   if (!tc) return;
521
522   /* Remove the server structure from the cell list - if there */
523   ObtainWriteLock(&afs_xcell,200);
524   for (j=k=0; j<MAXCELLHOSTS; j++) {
525      if (!tc->cellHosts[j]) break;
526      if (tc->cellHosts[j] != srvp) {
527         tc->cellHosts[k++] = tc->cellHosts[j];
528      }
529   }
530   if (k == 0) {
531      /* What do we do if we remove the last one? */
532   }
533   for (; k<MAXCELLHOSTS; k++) {
534      tc->cellHosts[k] = 0;
535   }
536   ReleaseWriteLock(&afs_xcell);
537 }
538