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