amd64-linux-port-20030428
[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) 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()
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); tq = QNext(cq);
492         ret = cb(tc, arg);
493         if (ret) break;
494     }
495
496     return ret;
497 }
498
499 void *afs_TraverseCells(void *(*cb)(struct cell *, void *), void *arg)
500 {
501     void *ret;
502
503     ObtainReadLock(&afs_xcell);
504     ret = afs_TraverseCells_nl(cb, arg);
505     ReleaseReadLock(&afs_xcell);
506
507     return ret;
508 }
509
510 static void *afs_choose_cell_by_name(struct cell *cell, void *arg)
511 {
512     return strcmp(cell->cellName, (char *) arg) ? NULL : cell;
513 }
514
515 static void *afs_choose_cell_by_num(struct cell *cell, void *arg)
516 {
517     return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
518 }
519
520 static void *afs_choose_cell_by_index(struct cell *cell, void *arg)
521 {
522     return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
523 }
524
525 static struct cell *afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
526 {
527     return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
528 }
529
530 static struct cell *afs_FindCellByName(char *acellName, afs_int32 locktype)
531 {
532     return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
533 }
534
535 struct cell *afs_GetCellByName(char *acellName, afs_int32 locktype)
536 {
537     struct cell *tc;
538
539     tc = afs_FindCellByName(acellName, locktype);
540     if (!tc) {
541         afs_LookupAFSDB(acellName);
542         tc = afs_FindCellByName(acellName, locktype);
543     }
544     if (tc) {
545         afs_cellname_ref(tc->cnamep);
546         afs_UpdateCellLRU(tc);
547         afs_RefreshCell(tc);
548     }
549
550     return tc;
551 }
552
553 struct cell *afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
554 {
555     struct cell *tc;
556     struct cell_name *cn;
557
558     tc = afs_GetCellStale(cellnum, locktype);
559     if (tc) {
560         afs_RefreshCell(tc);
561     } else {
562         ObtainReadLock(&afs_xcell);
563         cn = afs_cellname_lookup_id(cellnum);
564         ReleaseReadLock(&afs_xcell);
565         if (cn)
566             tc = afs_GetCellByName(cn->cellname, locktype);
567     }
568     return tc;
569 }
570
571 struct cell *afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
572 {
573     struct cell *tc;
574
575     tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
576     if (tc) {
577         afs_cellname_ref(tc->cnamep);
578         afs_UpdateCellLRU(tc);
579     }
580     return tc;
581 }
582
583 struct cell *afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
584 {
585     struct cell *tc;
586
587     tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
588     if (tc)
589         afs_UpdateCellLRU(tc);
590     return tc;
591 }
592
593 struct cell *afs_GetPrimaryCell(afs_int32 locktype)
594 {
595     return afs_GetCellByName(afs_thiscell, locktype);
596 }
597
598 int afs_IsPrimaryCell(struct cell *cell)
599 {
600     return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
601 }
602
603 int afs_IsPrimaryCellNum(afs_int32 cellnum)
604 {
605     struct cell *tc;
606     int primary = 0;
607
608     tc = afs_GetCellStale(cellnum, READ_LOCK);
609     if (tc) {
610         primary = afs_IsPrimaryCell(tc);
611         afs_PutCell(tc, READ_LOCK);
612     }
613
614     return primary;
615 }
616
617 afs_int32 afs_SetPrimaryCell(char *acellName)
618 {
619     ObtainWriteLock(&afs_xcell, 691);
620     if (afs_thiscell)
621         afs_osi_FreeStr(afs_thiscell);
622     afs_thiscell = afs_strdup(acellName);
623     ReleaseWriteLock(&afs_xcell);
624     return 0;
625 }
626
627 afs_int32 afs_NewCell(char *acellName, afs_int32 *acellHosts, int aflags,
628         char *linkedcname, u_short fsport, u_short vlport, int timeout)
629 {
630     struct cell *tc, *tcl=0;
631     afs_int32 i, newc=0, code=0;
632
633     AFS_STATCNT(afs_NewCell);
634
635     ObtainWriteLock(&afs_xcell, 103);
636
637     tc = afs_FindCellByName_nl(acellName, READ_LOCK);
638     if (tc) {
639         aflags &= ~CNoSUID;
640     } else {
641         tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
642         memset((char *) tc, 0, sizeof(*tc));
643         tc->cellName = afs_strdup(acellName);
644         tc->fsport = AFS_FSPORT;
645         tc->vlport = AFS_VLPORT;
646         RWLOCK_INIT(&tc->lock, "cell lock");
647         newc = 1;
648         if (afs_thiscell && !strcmp(acellName, afs_thiscell))
649             aflags &= ~CNoSUID;
650     }
651     ObtainWriteLock(&tc->lock, 688);
652
653     /* If the cell we've found has the correct name but no timeout,
654      * and we're called with a non-zero timeout, bail out:  never
655      * override static configuration entries with AFSDB ones.
656      * One exception: if the original cell entry had no servers,
657      * it must get servers from AFSDB.
658      */
659     if (timeout && !tc->timeout && tc->cellHosts[0]) {
660         code = EINVAL;
661         goto bad;
662     }
663
664     /* we don't want to keep pinging old vlservers which were down,
665      * since they don't matter any more.  It's easier to do this than
666      * to remove the server from its various hash tables. */
667     for (i=0; i<MAXCELLHOSTS; i++) {
668         if (!tc->cellHosts[i]) break;
669         tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
670         tc->cellHosts[i]->flags |= SRVR_ISGONE;
671     }
672
673     if (fsport) tc->fsport = fsport;
674     if (vlport) tc->vlport = vlport;
675
676     if (aflags & CLinkedCell) {
677         if (!linkedcname) {
678             code = EINVAL;
679             goto bad;
680         }
681         tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
682         if (!tcl) {
683             code = ENOENT;
684             goto bad;
685         }
686         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
687             tcl->lcellp->lcellp = (struct cell *)0;
688             tcl->lcellp->states &= ~CLinkedCell;
689         }
690         tc->lcellp = tcl;
691         tcl->lcellp = tc;
692     }
693     tc->states |= aflags;
694     tc->timeout = timeout;
695
696     memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
697     for (i=0; i<MAXCELLHOSTS; i++) {
698         struct server *ts;
699         afs_uint32 temp = acellHosts[i];
700         if (!temp) break;
701         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
702         ts->cell = tc;
703         ts->flags &= ~SRVR_ISGONE;
704         tc->cellHosts[i] = ts;
705         afs_PutServer(ts, WRITE_LOCK);
706     }
707     afs_SortServers(tc->cellHosts, MAXCELLHOSTS);       /* randomize servers */
708
709     if (newc) {
710         struct cell_name *cn;
711
712         cn = afs_cellname_lookup_name(acellName);
713         if (!cn)
714             cn = afs_cellname_new(acellName, 0);
715
716         tc->cnamep = cn;
717         tc->cellNum = cn->cellnum;
718         tc->cellIndex = afs_cellindex++;
719         afs_stats_cmperf.numCellsVisible++;
720         QAdd(&CellLRU, &tc->lruq);
721     }
722
723     ReleaseWriteLock(&tc->lock);
724     ReleaseWriteLock(&afs_xcell);
725     afs_PutCell(tc, 0);
726     afs_DynrootInvalidate();
727     return 0;
728
729 bad:
730     if (newc) {
731         afs_osi_FreeStr(tc->cellName);
732         afs_osi_Free(tc, sizeof(struct cell));
733     }
734     ReleaseWriteLock(&tc->lock);
735     ReleaseWriteLock(&afs_xcell);
736     return code;
737 }
738
739 /*
740  * Miscellaneous stuff
741  *
742  * afs_CellInit: perform whatever initialization is necessary
743  * shutdown_cell: called on shutdown, should deallocate memory, etc
744  * afs_RemoveCellEntry: remove a server from a cell's server list
745  * afs_CellOrAliasExists: check if the given name exists as a cell or alias
746  * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
747  * afs_CellNumValid: check if a cell number is valid (also set the used flag)
748  */
749
750 void afs_CellInit()
751 {
752     RWLOCK_INIT(&afs_xcell, "afs_xcell");
753 #ifdef AFS_AFSDB_ENV
754     RWLOCK_INIT(&afsdb_req.lock, "afsdb_req.lock");
755 #endif
756     QInit(&CellLRU);
757
758     afs_cellindex = 0;
759     afs_cellalias_index = 0;
760 }
761
762 void shutdown_cell()
763 {
764     struct afs_q *cq, *tq;
765     struct cell *tc;
766
767     RWLOCK_INIT(&afs_xcell, "afs_xcell");
768
769     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
770         tc = QTOC(cq); tq = QNext(cq);
771         if (tc->cellName) afs_osi_FreeStr(tc->cellName);
772         afs_osi_Free(tc, sizeof(struct cell));
773     }
774     QInit(&CellLRU);
775 }
776
777 void afs_RemoveCellEntry(struct server *srvp)
778 {
779     struct cell *tc;
780     afs_int32 j, k;
781
782     tc = srvp->cell;
783     if (!tc) return;
784
785     /* Remove the server structure from the cell list - if there */
786     ObtainWriteLock(&tc->lock, 200);
787     for (j=k=0; j<MAXCELLHOSTS; j++) {
788         if (!tc->cellHosts[j]) break;
789         if (tc->cellHosts[j] != srvp) {
790             tc->cellHosts[k++] = tc->cellHosts[j];
791         }
792     }
793     if (k == 0) {
794         /* What do we do if we remove the last one? */
795     }
796     for (; k<MAXCELLHOSTS; k++) {
797         tc->cellHosts[k] = 0;
798     }
799     ReleaseWriteLock(&tc->lock);
800 }
801
802 static int afs_CellOrAliasExists_nl(char *aname)
803 {
804     struct cell *c;
805     struct cell_alias *ca;
806
807     c = afs_FindCellByName_nl(aname, READ_LOCK);
808     if (c) {
809         afs_PutCell(c, READ_LOCK);
810         return 1;
811     }
812
813     ca = afs_FindCellAlias(aname);
814     if (ca) {
815         afs_PutCellAlias(ca);
816         return 1;
817     }
818
819     return 0;
820 }
821
822 int afs_CellOrAliasExists(char *aname)
823 {
824     int ret;
825
826     ObtainReadLock(&afs_xcell);
827     ret = afs_CellOrAliasExists_nl(aname);
828     ReleaseReadLock(&afs_xcell);
829
830     return ret;
831 }
832
833 int afs_CellNumValid(afs_int32 cellnum)
834 {
835     struct cell_name *cn;
836
837     ObtainReadLock(&afs_xcell);
838     cn = afs_cellname_lookup_id(cellnum);
839     ReleaseReadLock(&afs_xcell);
840     if (cn) {
841         cn->used = 1;
842         return 1;
843     } else {
844         return 0;
845     }
846 }