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