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