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