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