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