bebdae1e4605e4ec6743a35d9bc1cbeb08c999dc
[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
17     ("$Header$");
18
19 #include "afs/stds.h"
20 #include "afs/sysincludes.h"    /* Standard vendor system headers */
21 #include "afsincludes.h"        /* Afs-based standard headers */
22 #include "afs/afs_stats.h"      /* afs statistics */
23 #include "afs/afs_osi.h"
24
25 /* Local variables. */
26 afs_rwlock_t afs_xcell;         /* Export for cmdebug peeking at locks */
27
28 /*
29  * AFSDB implementation:
30  *
31  * afs_StopAFSDB: terminate the AFSDB handler, used on shutdown
32  * afs_AFSDBHandler: entry point for user-space AFSDB request handler
33  * afs_GetCellHostsAFSDB: query the AFSDB handler and wait for response
34  * afs_LookupAFSDB: look up AFSDB for given cell name and create locally
35  */
36
37 #ifdef AFS_AFSDB_ENV
38 static afs_rwlock_t afsdb_client_lock;  /* Serializes client requests */
39 static char afsdb_handler_running;      /* Protected by GLOCK */
40 static char afsdb_handler_shutdown;     /* Protected by GLOCK */
41
42 static struct {
43     afs_rwlock_t lock;
44     char pending;
45     char complete;
46     char *cellname;
47     afs_int32 *cellhosts;
48     int *timeout;
49     char **realname;
50 } afsdb_req;
51
52 void
53 afs_StopAFSDB()
54 {
55     if (afsdb_handler_running) {
56         afs_osi_Wakeup(&afsdb_req);
57     } else {
58         afsdb_handler_shutdown = 1;
59         afs_termState = AFSOP_STOP_RXEVENT;
60     }
61 }
62
63 int
64 afs_AFSDBHandler(char *acellName, int acellNameLen, afs_int32 * kernelMsg)
65 {
66     if (afsdb_handler_shutdown)
67         return -2;
68     afsdb_handler_running = 1;
69
70     ObtainSharedLock(&afsdb_req.lock, 683);
71     if (afsdb_req.pending) {
72         int i, hostCount;
73
74         UpgradeSToWLock(&afsdb_req.lock, 684);
75         hostCount = kernelMsg[0];
76         *afsdb_req.timeout = kernelMsg[1];
77         if (*afsdb_req.timeout)
78             *afsdb_req.timeout += osi_Time();
79         *afsdb_req.realname = afs_strdup(acellName);
80
81         for (i = 0; i < MAXCELLHOSTS; i++) {
82             if (i >= hostCount)
83                 afsdb_req.cellhosts[i] = 0;
84             else
85                 afsdb_req.cellhosts[i] = kernelMsg[2 + i];
86         }
87
88         /* Request completed, wake up the relevant thread */
89         afsdb_req.pending = 0;
90         afsdb_req.complete = 1;
91         afs_osi_Wakeup(&afsdb_req);
92         ConvertWToSLock(&afsdb_req.lock);
93     }
94     ConvertSToRLock(&afsdb_req.lock);
95
96     /* Wait for a request */
97     while (afsdb_req.pending == 0 && afs_termState != AFSOP_STOP_AFSDB) {
98         ReleaseReadLock(&afsdb_req.lock);
99         afs_osi_Sleep(&afsdb_req);
100         ObtainReadLock(&afsdb_req.lock);
101     }
102
103     /* Check if we're shutting down */
104     if (afs_termState == AFSOP_STOP_AFSDB) {
105         ReleaseReadLock(&afsdb_req.lock);
106
107         /* Inform anyone waiting for us that we're going away */
108         afsdb_handler_shutdown = 1;
109         afsdb_handler_running = 0;
110         afs_osi_Wakeup(&afsdb_req);
111
112         afs_termState = AFSOP_STOP_RXEVENT;
113         afs_osi_Wakeup(&afs_termState);
114         return -2;
115     }
116
117     /* Return the lookup request to userspace */
118     strncpy(acellName, afsdb_req.cellname, acellNameLen);
119     ReleaseReadLock(&afsdb_req.lock);
120     return 0;
121 }
122
123 static int
124 afs_GetCellHostsAFSDB(char *acellName, afs_int32 * acellHosts, int *timeout,
125                       char **realName)
126 {
127     AFS_ASSERT_GLOCK();
128     if (!afsdb_handler_running)
129         return ENOENT;
130
131     ObtainWriteLock(&afsdb_client_lock, 685);
132     ObtainWriteLock(&afsdb_req.lock, 686);
133
134     *acellHosts = 0;
135     afsdb_req.cellname = afs_strdup(acellName);
136     afsdb_req.cellhosts = acellHosts;
137     afsdb_req.timeout = timeout;
138     afsdb_req.realname = realName;
139
140     afsdb_req.complete = 0;
141     afsdb_req.pending = 1;
142     afs_osi_Wakeup(&afsdb_req);
143     ConvertWToRLock(&afsdb_req.lock);
144
145     while (afsdb_handler_running && !afsdb_req.complete) {
146         ReleaseReadLock(&afsdb_req.lock);
147         afs_osi_Sleep(&afsdb_req);
148         ObtainReadLock(&afsdb_req.lock);
149     };
150
151     afs_osi_FreeStr(afsdb_req.cellname);
152     ReleaseReadLock(&afsdb_req.lock);
153     ReleaseWriteLock(&afsdb_client_lock);
154
155     if (*acellHosts)
156         return 0;
157     else
158         return ENOENT;
159 }
160 #endif
161
162 void
163 afs_LookupAFSDB(char *acellName)
164 {
165 #ifdef AFS_AFSDB_ENV
166     afs_int32 *cellHosts;
167     char **realName=NULL;
168     int code;
169     int *timeout=NULL;
170
171     if(!(cellHosts = afs_osi_Alloc(MAXCELLHOSTS * sizeof(afs_int32))))
172         goto done;
173
174     if(!(realName = afs_osi_Alloc(sizeof(char *))))
175         goto done;
176     *realName = NULL;
177
178     if(!(timeout = afs_osi_Alloc(sizeof(int))))
179         goto done;
180
181     code = afs_GetCellHostsAFSDB(acellName, cellHosts, timeout, realName);
182     if (code)
183         goto done;
184     code = afs_NewCell(*realName, cellHosts, CNoSUID, NULL, 0, 0, *timeout);
185     if (code && code != EEXIST)
186         goto done;
187
188     /* If we found an alias, create it */
189     if (afs_strcasecmp(acellName, *realName))
190         afs_NewCellAlias(acellName, *realName);
191
192   done:
193     if(timeout)
194         afs_osi_Free(timeout, sizeof(int));
195     if (realName && *realName)
196         afs_osi_FreeStr(*realName);
197     if(realName)
198         afs_osi_Free(realName, sizeof(char *));
199     if(cellHosts)
200         afs_osi_Free(cellHosts, MAXCELLHOSTS * sizeof(afs_int32));
201 #endif
202 }
203
204 /*
205  * Cell name-to-ID mapping
206  *
207  * afs_cellname_new: create a new cell name, optional cell number
208  * afs_cellname_lookup_id: look up a cell name
209  * afs_cellname_lookup_name: look up a cell number
210  * afs_cellname_ref: note that this cell name was referenced somewhere
211  * afs_cellname_init: load the list of cells from given inode
212  * afs_cellname_write: write in-kernel list of cells to disk
213  */
214
215 struct cell_name *afs_cellname_head;    /* Export for kdump */
216 static ino_t afs_cellname_inode;
217 static int afs_cellname_inode_set;
218 static int afs_cellname_dirty;
219 static afs_int32 afs_cellnum_next;
220
221 static struct cell_name *
222 afs_cellname_new(char *name, afs_int32 cellnum)
223 {
224     struct cell_name *cn;
225
226     if (cellnum == 0)
227         cellnum = afs_cellnum_next;
228
229     cn = (struct cell_name *)afs_osi_Alloc(sizeof(*cn));
230     cn->next = afs_cellname_head;
231     cn->cellnum = cellnum;
232     cn->cellname = afs_strdup(name);
233     cn->used = 0;
234     afs_cellname_head = cn;
235
236     if (cellnum >= afs_cellnum_next)
237         afs_cellnum_next = cellnum + 1;
238
239     return cn;
240 }
241
242 static struct cell_name *
243 afs_cellname_lookup_id(afs_int32 cellnum)
244 {
245     struct cell_name *cn;
246
247     for (cn = afs_cellname_head; cn; cn = cn->next)
248         if (cn->cellnum == cellnum)
249             return cn;
250
251     return NULL;
252 }
253
254 static struct cell_name *
255 afs_cellname_lookup_name(char *name)
256 {
257     struct cell_name *cn;
258
259     for (cn = afs_cellname_head; cn; cn = cn->next)
260         if (strcmp(cn->cellname, name) == 0)
261             return cn;
262
263     return NULL;
264 }
265
266 static void
267 afs_cellname_ref(struct cell_name *cn)
268 {
269     if (!cn->used) {
270         cn->used = 1;
271         afs_cellname_dirty = 1;
272     }
273 }
274
275 int
276 afs_cellname_init(ino_t inode, int lookupcode)
277 {
278     struct osi_file *tfile;
279     int cc, off = 0;
280
281     ObtainWriteLock(&afs_xcell, 692);
282
283     afs_cellnum_next = 1;
284     afs_cellname_dirty = 0;
285
286     if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
287         ReleaseWriteLock(&afs_xcell);
288         return 0;
289     }
290     if (lookupcode) {
291         ReleaseWriteLock(&afs_xcell);
292         return lookupcode;
293     }
294
295     tfile = osi_UFSOpen(inode);
296     if (!tfile) {
297         ReleaseWriteLock(&afs_xcell);
298         return EIO;
299     }
300
301     afs_cellname_inode = inode;
302     afs_cellname_inode_set = 1;
303
304     while (1) {
305         afs_int32 cellnum, clen, magic;
306         struct cell_name *cn;
307         char *cellname;
308
309         cc = afs_osi_Read(tfile, off, &magic, sizeof(magic));
310         if (cc != sizeof(magic))
311             break;
312         if (magic != AFS_CELLINFO_MAGIC)
313             break;
314         off += cc;
315
316         cc = afs_osi_Read(tfile, off, &cellnum, sizeof(cellnum));
317         if (cc != sizeof(cellnum))
318             break;
319         off += cc;
320
321         cc = afs_osi_Read(tfile, off, &clen, sizeof(clen));
322         if (cc != sizeof(clen))
323             break;
324         off += cc;
325
326         cellname = afs_osi_Alloc(clen + 1);
327         if (!cellname)
328             break;
329
330         cc = afs_osi_Read(tfile, off, cellname, clen);
331         if (cc != clen) {
332             afs_osi_Free(cellname, clen + 1);
333             break;
334         }
335         off += cc;
336         cellname[clen] = '\0';
337
338         if (afs_cellname_lookup_name(cellname)
339             || afs_cellname_lookup_id(cellnum)) {
340             afs_osi_Free(cellname, clen + 1);
341             break;
342         }
343
344         cn = afs_cellname_new(cellname, cellnum);
345         afs_osi_Free(cellname, clen + 1);
346     }
347
348     osi_UFSClose(tfile);
349     ReleaseWriteLock(&afs_xcell);
350     return 0;
351 }
352
353 int
354 afs_cellname_write(void)
355 {
356     struct osi_file *tfile;
357     struct cell_name *cn;
358     int off;
359
360     if (!afs_cellname_dirty || !afs_cellname_inode_set)
361         return 0;
362     if (afs_initState != 300)
363         return 0;
364
365     ObtainWriteLock(&afs_xcell, 693);
366     afs_cellname_dirty = 0;
367     off = 0;
368     tfile = osi_UFSOpen(afs_cellname_inode);
369     if (!tfile) {
370         ReleaseWriteLock(&afs_xcell);
371         return EIO;
372     }
373
374     for (cn = afs_cellname_head; cn; cn = cn->next) {
375         afs_int32 magic, cellnum, clen;
376         int cc;
377
378         if (!cn->used)
379             continue;
380
381         magic = AFS_CELLINFO_MAGIC;
382         cc = afs_osi_Write(tfile, off, &magic, sizeof(magic));
383         if (cc != sizeof(magic))
384             break;
385         off += cc;
386
387         cellnum = cn->cellnum;
388         cc = afs_osi_Write(tfile, off, &cellnum, sizeof(cellnum));
389         if (cc != sizeof(cellnum))
390             break;
391         off += cc;
392
393         clen = strlen(cn->cellname);
394         cc = afs_osi_Write(tfile, off, &clen, sizeof(clen));
395         if (cc != sizeof(clen))
396             break;
397         off += cc;
398
399         cc = afs_osi_Write(tfile, off, cn->cellname, clen);
400         if (cc != clen)
401             break;
402         off += clen;
403     }
404
405     osi_UFSClose(tfile);
406     ReleaseWriteLock(&afs_xcell);
407     return 0;
408 }
409
410 /*
411  * Cell alias implementation
412  *
413  * afs_FindCellAlias: look up cell alias by alias name
414  * afs_GetCellAlias: get cell alias by index (starting at 0)
415  * afs_PutCellAlias: put back a cell alias returned by Find or Get
416  * afs_NewCellAlias: create new cell alias entry
417  */
418
419 struct cell_alias *afs_cellalias_head;  /* Export for kdump */
420 static afs_int32 afs_cellalias_index;
421 static int afs_CellOrAliasExists_nl(char *aname);       /* Forward declaration */
422
423 static struct cell_alias *
424 afs_FindCellAlias(char *alias)
425 {
426     struct cell_alias *tc;
427
428     for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
429         if (!strcmp(alias, tc->alias))
430             break;
431     return tc;
432 }
433
434 struct cell_alias *
435 afs_GetCellAlias(int index)
436 {
437     struct cell_alias *tc;
438
439     ObtainReadLock(&afs_xcell);
440     for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
441         if (tc->index == index)
442             break;
443     ReleaseReadLock(&afs_xcell);
444
445     return tc;
446 }
447
448 void
449 afs_PutCellAlias(struct cell_alias *a)
450 {
451     return;
452 }
453
454 afs_int32
455 afs_NewCellAlias(char *alias, char *cell)
456 {
457     struct cell_alias *tc;
458
459     ObtainSharedLock(&afs_xcell, 681);
460     if (afs_CellOrAliasExists_nl(alias)) {
461         ReleaseSharedLock(&afs_xcell);
462         return EEXIST;
463     }
464
465     UpgradeSToWLock(&afs_xcell, 682);
466     tc = (struct cell_alias *)afs_osi_Alloc(sizeof(struct cell_alias));
467     tc->alias = afs_strdup(alias);
468     tc->cell = afs_strdup(cell);
469     tc->next = afs_cellalias_head;
470     tc->index = afs_cellalias_index++;
471     afs_cellalias_head = tc;
472     ReleaseWriteLock(&afs_xcell);
473
474     afs_DynrootInvalidate();
475     return 0;
476 }
477
478 /*
479  * Actual cell list implementation
480  *
481  * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
482  * afs_RefreshCell: look up cell information in AFSDB if timeout expired
483  *
484  * afs_TraverseCells: execute a callback for each existing cell
485  * afs_TraverseCells_nl: same as above except without locking afs_xcell
486  * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
487  *
488  * afs_FindCellByName: return a cell with a given name, if it exists
489  * afs_FindCellByName_nl: same as above, without locking afs_xcell
490  * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
491  * afs_GetCell: return a cell with a given cell number
492  * afs_GetCellStale: same as GetCell, but does not try to refresh the data
493  * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
494  *
495  * afs_GetPrimaryCell: return the primary cell, if any
496  * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
497  * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
498  * afs_SetPrimaryCell: set the primary cell name to the given cell name
499  *
500  * afs_NewCell: create or update a cell entry
501  */
502
503 struct afs_q CellLRU;           /* Export for kdump */
504 static char *afs_thiscell;
505 afs_int32 afs_cellindex;        /* Export for kdump */
506
507 static void
508 afs_UpdateCellLRU(struct cell *c)
509 {
510     ObtainWriteLock(&afs_xcell, 100);
511     QRemove(&c->lruq);
512     QAdd(&CellLRU, &c->lruq);
513     ReleaseWriteLock(&afs_xcell);
514 }
515
516 static void
517 afs_RefreshCell(struct cell *ac)
518 {
519     if (ac->states & CNoAFSDB)
520         return;
521     if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
522         afs_LookupAFSDB(ac->cellName);
523 }
524
525 static void *
526 afs_TraverseCells_nl(void *(*cb) (struct cell *, void *), void *arg)
527 {
528     struct afs_q *cq, *tq;
529     struct cell *tc;
530     void *ret = NULL;
531
532     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
533         tc = QTOC(cq);
534
535         /* This is assuming that a NULL return is acceptable. */
536         if (cq) {
537             tq = QNext(cq);
538         } else {
539             return NULL;
540         }
541
542         ret = cb(tc, arg);
543         if (ret)
544             break;
545     }
546
547     return ret;
548 }
549
550 void *
551 afs_TraverseCells(void *(*cb) (struct cell *, void *), void *arg)
552 {
553     void *ret;
554
555     ObtainReadLock(&afs_xcell);
556     ret = afs_TraverseCells_nl(cb, arg);
557     ReleaseReadLock(&afs_xcell);
558
559     return ret;
560 }
561
562 static void *
563 afs_choose_cell_by_name(struct cell *cell, void *arg)
564 {
565     if (!arg) {
566         /* Safety net */
567         return cell;
568     } else {
569         return strcmp(cell->cellName, (char *)arg) ? NULL : cell;
570     }
571 }
572
573 static void *
574 afs_choose_cell_by_num(struct cell *cell, void *arg)
575 {
576     return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
577 }
578
579 static void *
580 afs_choose_cell_by_index(struct cell *cell, void *arg)
581 {
582     return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
583 }
584
585 static struct cell *
586 afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
587 {
588     return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
589 }
590
591 static struct cell *
592 afs_FindCellByName(char *acellName, afs_int32 locktype)
593 {
594     return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
595 }
596
597 struct cell *
598 afs_GetCellByName(char *acellName, afs_int32 locktype)
599 {
600     struct cell *tc;
601
602     tc = afs_FindCellByName(acellName, locktype);
603     if (!tc) {
604         afs_LookupAFSDB(acellName);
605         tc = afs_FindCellByName(acellName, locktype);
606     }
607     if (tc) {
608         afs_cellname_ref(tc->cnamep);
609         afs_UpdateCellLRU(tc);
610         afs_RefreshCell(tc);
611     }
612
613     return tc;
614 }
615
616 struct cell *
617 afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
618 {
619     struct cell *tc;
620     struct cell_name *cn;
621
622     tc = afs_GetCellStale(cellnum, locktype);
623     if (tc) {
624         afs_RefreshCell(tc);
625     } else {
626         ObtainReadLock(&afs_xcell);
627         cn = afs_cellname_lookup_id(cellnum);
628         ReleaseReadLock(&afs_xcell);
629         if (cn)
630             tc = afs_GetCellByName(cn->cellname, locktype);
631     }
632     return tc;
633 }
634
635 struct cell *
636 afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
637 {
638     struct cell *tc;
639
640     tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
641     if (tc) {
642         afs_cellname_ref(tc->cnamep);
643         afs_UpdateCellLRU(tc);
644     }
645     return tc;
646 }
647
648 struct cell *
649 afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
650 {
651     struct cell *tc;
652
653     tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
654     if (tc)
655         afs_UpdateCellLRU(tc);
656     return tc;
657 }
658
659 struct cell *
660 afs_GetPrimaryCell(afs_int32 locktype)
661 {
662     return afs_GetCellByName(afs_thiscell, locktype);
663 }
664
665 int
666 afs_IsPrimaryCell(struct cell *cell)
667 {
668     /* Simple safe checking */
669     if (!cell) {
670         return 0;
671     } else if (!afs_thiscell) {
672         /* This is simply a safety net to avoid seg faults especially when
673          * using a user-space library.  afs_SetPrimaryCell() should be set
674          * prior to this call. */
675         afs_SetPrimaryCell(cell->cellName);
676         return 1;
677     } else {
678         return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
679     }
680 }
681
682 int
683 afs_IsPrimaryCellNum(afs_int32 cellnum)
684 {
685     struct cell *tc;
686     int primary = 0;
687
688     tc = afs_GetCellStale(cellnum, READ_LOCK);
689     if (tc) {
690         primary = afs_IsPrimaryCell(tc);
691         afs_PutCell(tc, READ_LOCK);
692     }
693
694     return primary;
695 }
696
697 afs_int32
698 afs_SetPrimaryCell(char *acellName)
699 {
700     ObtainWriteLock(&afs_xcell, 691);
701     if (afs_thiscell)
702         afs_osi_FreeStr(afs_thiscell);
703     afs_thiscell = afs_strdup(acellName);
704     ReleaseWriteLock(&afs_xcell);
705     return 0;
706 }
707
708 afs_int32
709 afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
710             char *linkedcname, u_short fsport, u_short vlport, int timeout)
711 {
712     struct cell *tc, *tcl = 0;
713     afs_int32 i, newc = 0, code = 0;
714
715     AFS_STATCNT(afs_NewCell);
716
717     ObtainWriteLock(&afs_xcell, 103);
718
719     tc = afs_FindCellByName_nl(acellName, READ_LOCK);
720     if (tc) {
721         aflags &= ~CNoSUID;
722     } else {
723         tc = (struct cell *)afs_osi_Alloc(sizeof(struct cell));
724         memset((char *)tc, 0, sizeof(*tc));
725         tc->cellName = afs_strdup(acellName);
726         tc->fsport = AFS_FSPORT;
727         tc->vlport = AFS_VLPORT;
728         RWLOCK_INIT(&tc->lock, "cell lock");
729         newc = 1;
730         if (afs_thiscell && !strcmp(acellName, afs_thiscell))
731             aflags &= ~CNoSUID;
732     }
733     ObtainWriteLock(&tc->lock, 688);
734
735     /* If the cell we've found has the correct name but no timeout,
736      * and we're called with a non-zero timeout, bail out:  never
737      * override static configuration entries with AFSDB ones.
738      * One exception: if the original cell entry had no servers,
739      * it must get servers from AFSDB.
740      */
741     if (timeout && !tc->timeout && tc->cellHosts[0]) {
742         code = EEXIST;          /* This code is checked for in afs_LookupAFSDB */
743         goto bad;
744     }
745
746     /* we don't want to keep pinging old vlservers which were down,
747      * since they don't matter any more.  It's easier to do this than
748      * to remove the server from its various hash tables. */
749     for (i = 0; i < MAXCELLHOSTS; i++) {
750         if (!tc->cellHosts[i])
751             break;
752         tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
753         tc->cellHosts[i]->flags |= SRVR_ISGONE;
754     }
755
756     if (fsport)
757         tc->fsport = fsport;
758     if (vlport)
759         tc->vlport = vlport;
760
761     if (aflags & CLinkedCell) {
762         if (!linkedcname) {
763             code = EINVAL;
764             goto bad;
765         }
766         tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
767         if (!tcl) {
768             code = ENOENT;
769             goto bad;
770         }
771         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
772             tcl->lcellp->lcellp = (struct cell *)0;
773             tcl->lcellp->states &= ~CLinkedCell;
774         }
775         tc->lcellp = tcl;
776         tcl->lcellp = tc;
777     }
778     tc->states |= aflags;
779     tc->timeout = timeout;
780
781     memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
782     for (i = 0; i < MAXCELLHOSTS; i++) {
783         struct server *ts;
784         afs_uint32 temp = acellHosts[i];
785         if (!temp)
786             break;
787         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
788         ts->cell = tc;
789         ts->flags &= ~SRVR_ISGONE;
790         tc->cellHosts[i] = ts;
791         afs_PutServer(ts, WRITE_LOCK);
792     }
793     afs_SortServers(tc->cellHosts, MAXCELLHOSTS);       /* randomize servers */
794
795     if (newc) {
796         struct cell_name *cn;
797
798         cn = afs_cellname_lookup_name(acellName);
799         if (!cn)
800             cn = afs_cellname_new(acellName, 0);
801
802         tc->cnamep = cn;
803         tc->cellNum = cn->cellnum;
804         tc->cellIndex = afs_cellindex++;
805         afs_stats_cmperf.numCellsVisible++;
806         QAdd(&CellLRU, &tc->lruq);
807     }
808
809     ReleaseWriteLock(&tc->lock);
810     ReleaseWriteLock(&afs_xcell);
811     afs_PutCell(tc, 0);
812     afs_DynrootInvalidate();
813     return 0;
814
815   bad:
816     if (newc) {
817         afs_osi_FreeStr(tc->cellName);
818         afs_osi_Free(tc, sizeof(struct cell));
819     }
820     ReleaseWriteLock(&tc->lock);
821     ReleaseWriteLock(&afs_xcell);
822     return code;
823 }
824
825 /*
826  * Miscellaneous stuff
827  *
828  * afs_CellInit: perform whatever initialization is necessary
829  * shutdown_cell: called on shutdown, should deallocate memory, etc
830  * afs_RemoveCellEntry: remove a server from a cell's server list
831  * afs_CellOrAliasExists: check if the given name exists as a cell or alias
832  * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
833  * afs_CellNumValid: check if a cell number is valid (also set the used flag)
834  */
835
836 void
837 afs_CellInit()
838 {
839     RWLOCK_INIT(&afs_xcell, "afs_xcell");
840 #ifdef AFS_AFSDB_ENV
841     RWLOCK_INIT(&afsdb_client_lock, "afsdb_client_lock");
842     RWLOCK_INIT(&afsdb_req.lock, "afsdb_req.lock");
843 #endif
844     QInit(&CellLRU);
845
846     afs_cellindex = 0;
847     afs_cellalias_index = 0;
848 }
849
850 void
851 shutdown_cell()
852 {
853     struct afs_q *cq, *tq;
854     struct cell *tc;
855
856     RWLOCK_INIT(&afs_xcell, "afs_xcell");
857
858     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
859         tc = QTOC(cq);
860         tq = QNext(cq);
861         if (tc->cellName)
862             afs_osi_FreeStr(tc->cellName);
863         afs_osi_Free(tc, sizeof(struct cell));
864     }
865     QInit(&CellLRU);
866
867 {
868     struct cell_name *cn = afs_cellname_head;
869
870     while (cn) {
871         struct cell_name *next = cn->next;
872
873         afs_osi_FreeStr(cn->cellname);
874         afs_osi_Free(cn, sizeof(struct cell_name));
875         cn = next;
876     }
877 }
878 }
879
880 void
881 afs_RemoveCellEntry(struct server *srvp)
882 {
883     struct cell *tc;
884     afs_int32 j, k;
885
886     tc = srvp->cell;
887     if (!tc)
888         return;
889
890     /* Remove the server structure from the cell list - if there */
891     ObtainWriteLock(&tc->lock, 200);
892     for (j = k = 0; j < MAXCELLHOSTS; j++) {
893         if (!tc->cellHosts[j])
894             break;
895         if (tc->cellHosts[j] != srvp) {
896             tc->cellHosts[k++] = tc->cellHosts[j];
897         }
898     }
899     if (k == 0) {
900         /* What do we do if we remove the last one? */
901     }
902     for (; k < MAXCELLHOSTS; k++) {
903         tc->cellHosts[k] = 0;
904     }
905     ReleaseWriteLock(&tc->lock);
906 }
907
908 static int
909 afs_CellOrAliasExists_nl(char *aname)
910 {
911     struct cell *c;
912     struct cell_alias *ca;
913
914     c = afs_FindCellByName_nl(aname, READ_LOCK);
915     if (c) {
916         afs_PutCell(c, READ_LOCK);
917         return 1;
918     }
919
920     ca = afs_FindCellAlias(aname);
921     if (ca) {
922         afs_PutCellAlias(ca);
923         return 1;
924     }
925
926     return 0;
927 }
928
929 int
930 afs_CellOrAliasExists(char *aname)
931 {
932     int ret;
933
934     ObtainReadLock(&afs_xcell);
935     ret = afs_CellOrAliasExists_nl(aname);
936     ReleaseReadLock(&afs_xcell);
937
938     return ret;
939 }
940
941 int
942 afs_CellNumValid(afs_int32 cellnum)
943 {
944     struct cell_name *cn;
945
946     ObtainReadLock(&afs_xcell);
947     cn = afs_cellname_lookup_id(cellnum);
948     ReleaseReadLock(&afs_xcell);
949     if (cn) {
950         cn->used = 1;
951         return 1;
952     } else {
953         return 0;
954     }
955 }