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