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