9b3fd9a176cea1c2e3af3eb83b4c3eb2d59f915b
[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 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 = (struct cell_name *)afs_osi_Alloc(sizeof(*cn));
233     cn->next = afs_cellname_head;
234     cn->cellnum = cellnum;
235     cn->cellname = afs_strdup(name);
236     cn->used = 0;
237     afs_cellname_head = cn;
238
239     if (cellnum >= afs_cellnum_next)
240         afs_cellnum_next = cellnum + 1;
241
242     return cn;
243 }
244
245 /*!
246  * Look up a cell name by id.
247  * \param cellnum
248  * \return
249  */
250 static struct cell_name *
251 afs_cellname_lookup_id(afs_int32 cellnum)
252 {
253     struct cell_name *cn;
254
255     for (cn = afs_cellname_head; cn; cn = cn->next)
256         if (cn->cellnum == cellnum)
257             return cn;
258
259     return NULL;
260 }
261
262 /*!
263  * Look up a cell name.
264  * \param name Cell name.
265  * \return
266  */
267 static struct cell_name *
268 afs_cellname_lookup_name(char *name)
269 {
270     struct cell_name *cn;
271
272     for (cn = afs_cellname_head; cn; cn = cn->next)
273         if (strcmp(cn->cellname, name) == 0)
274             return cn;
275
276     return NULL;
277 }
278
279 /*!
280  * Note that this cell name was referenced somewhere.
281  * \param  cn
282  */
283 static void
284 afs_cellname_ref(struct cell_name *cn)
285 {
286     if (!cn->used) {
287         cn->used = 1;
288         afs_cellname_dirty = 1;
289     }
290 }
291
292 /*!
293  * \brief Load the list of cells from given inode.
294  * \param inode Source inode.
295  * \param lookupcode
296  * \return 0 for success. < 0 for error.
297  */
298 int
299 afs_cellname_init(afs_dcache_id_t *inode, int lookupcode)
300 {
301     struct osi_file *tfile;
302     int cc, off = 0;
303
304     ObtainWriteLock(&afs_xcell, 692);
305
306     afs_cellnum_next = 1;
307     afs_cellname_dirty = 0;
308
309     if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
310         ReleaseWriteLock(&afs_xcell);
311         return 0;
312     }
313     if (lookupcode) {
314         ReleaseWriteLock(&afs_xcell);
315         return lookupcode;
316     }
317
318     tfile = osi_UFSOpen(inode);
319     if (!tfile) {
320         ReleaseWriteLock(&afs_xcell);
321         return EIO;
322     }
323
324     afs_copy_inode(&afs_cellname_inode, inode);
325     afs_cellname_inode_set = 1;
326
327     while (1) {
328         afs_int32 cellnum, clen, magic;
329         struct cell_name *cn;
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         cn = 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 = (struct cell_alias *)afs_osi_Alloc(sizeof(struct cell_alias));
515     tc->alias = afs_strdup(alias);
516     tc->cell = afs_strdup(cell);
517     tc->next = afs_cellalias_head;
518     tc->index = afs_cellalias_index++;
519     afs_cellalias_head = tc;
520     ReleaseWriteLock(&afs_xcell);
521
522     afs_DynrootInvalidate();
523     return 0;
524 }
525
526 /*
527  * Actual cell list implementation
528  *
529  * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
530  * afs_RefreshCell: look up cell information in AFSDB if timeout expired
531  *
532  * afs_TraverseCells: execute a callback for each existing cell
533  * afs_TraverseCells_nl: same as above except without locking afs_xcell
534  * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
535  *
536  * afs_FindCellByName: return a cell with a given name, if it exists
537  * afs_FindCellByName_nl: same as above, without locking afs_xcell
538  * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
539  * afs_GetCell: return a cell with a given cell number
540  * afs_GetCellStale: same as GetCell, but does not try to refresh the data
541  * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
542  *
543  * afs_GetPrimaryCell: return the primary cell, if any
544  * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
545  * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
546  * afs_SetPrimaryCell: set the primary cell name to the given cell name
547  *
548  * afs_NewCell: create or update a cell entry
549  */
550
551 struct afs_q CellLRU;           /* Export for kdump */
552 static char *afs_thiscell = NULL;
553 afs_int32 afs_cellindex;        /* Export for kdump */
554
555 /*!
556  * Bump given cell up to the front of the LRU queue.
557  * \param c Cell to set.
558  */
559 static void
560 afs_UpdateCellLRU(struct cell *c)
561 {
562     ObtainWriteLock(&afs_xcell, 100);
563     QRemove(&c->lruq);
564     QAdd(&CellLRU, &c->lruq);
565     ReleaseWriteLock(&afs_xcell);
566 }
567
568 /*!
569  * Look up cell information in AFSDB if timeout expired
570  * \param ac Cell to be refreshed.
571  * \return
572  */
573 static void
574 afs_RefreshCell(struct cell *ac)
575 {
576     if (ac->states & CNoAFSDB)
577         return;
578     if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
579         afs_LookupAFSDB(ac->cellName);
580 }
581
582 /*!
583  * Execute a callback for each existing cell, without a lock on afs_xcell.
584  * Iterate on CellLRU, and execute a callback for each cell until given arguments are met.
585  * \see afs_TraverseCells
586  * \param cb Traversal callback for each cell.
587  * \param arg Callback arguments.
588  * \return Found data or NULL.
589  */
590 static void *
591 afs_TraverseCells_nl(void *(*cb) (struct cell *, void *), void *arg)
592 {
593     struct afs_q *cq, *tq;
594     struct cell *tc;
595     void *ret = NULL;
596
597     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
598         tc = QTOC(cq);
599
600         /* This is assuming that a NULL return is acceptable. */
601         if (cq) {
602             tq = QNext(cq);
603         } else {
604             return NULL;
605         }
606
607         ret = cb(tc, arg);
608         if (ret)
609             break;
610     }
611
612     return ret;
613 }
614
615 /*!
616  * Execute a callback for each existing cell, with a lock on afs_xcell.
617  * \see afs_TraverseCells_nl
618  * \param cb Traversal callback for each cell.
619  * \param arg
620  * \return Found data or NULL.
621  */
622 void *
623 afs_TraverseCells(void *(*cb) (struct cell *, void *), void *arg)
624 {
625     void *ret;
626
627     ObtainReadLock(&afs_xcell);
628     ret = afs_TraverseCells_nl(cb, arg);
629     ReleaseReadLock(&afs_xcell);
630
631     return ret;
632 }
633
634 /*!
635  * Useful traversal callback: Match by name.
636  * \param cell
637  * \param arg Cell name (compared with cell->cellName).
638  * \return Returns found cell or NULL.
639  */
640 static void *
641 afs_choose_cell_by_name(struct cell *cell, void *arg)
642 {
643     if (!arg) {
644         /* Safety net */
645         return cell;
646     } else {
647         return strcmp(cell->cellName, (char *)arg) ? NULL : cell;
648     }
649 }
650
651 /*!
652  * Useful traversal callback: Match by handle.
653  * \param cell
654  * \param arg Cell handle (compared with cell->cellHandle).
655  * \return Returns found cell or NULL.
656  */
657 static void *
658 afs_choose_cell_by_handle(struct cell *cell, void *arg)
659 {
660     if (!arg) {
661         /* Safety net */
662         return cell;
663     } else {
664         return memcmp(cell->cellHandle, (char *)arg, 16) ? NULL : cell;
665     }
666 }
667
668 /*!
669  * Useful traversal callback: Match by cell number.
670  * \param cell
671  * \param arg Cell number (compared with cell->cellNum).
672  * \return Returns found cell or NULL.
673  */
674 static void *
675 afs_choose_cell_by_num(struct cell *cell, void *arg)
676 {
677     return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
678 }
679
680 /*!
681  * Useful traversal callback: Match by index.
682  * \param cell
683  * \param arg Cell index (compared with cell->cellIndex).
684  * \return Returns found cell or NULL.
685  */
686 static void *
687 afs_choose_cell_by_index(struct cell *cell, void *arg)
688 {
689     return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
690 }
691
692 /*!
693  * Return a cell with a given name, if it exists. No lock version.
694  * Does not check AFSDB.
695  * \param acellName Cell name.
696  * \param locktype Type of lock to be used (not used).
697  * \return
698  */
699 static struct cell *
700 afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
701 {
702     return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
703 }
704
705 /*!
706  * Return a cell with a given name, if it exists.It uses locks.
707  * Does not check AFSDB.
708  * \param acellName Cell name.
709  * \param locktype Type of lock to be used.
710  * \return
711  */
712 static struct cell *
713 afs_FindCellByName(char *acellName, afs_int32 locktype)
714 {
715     return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
716 }
717
718 /*!
719  * Same as FindCellByName but tries AFSDB if not found.
720  * \param acellName Cell name.
721  * \param locktype Type of lock to be used.
722  * \return
723  */
724 struct cell *
725 afs_GetCellByName(char *acellName, afs_int32 locktype)
726 {
727     struct cell *tc;
728
729     tc = afs_FindCellByName(acellName, locktype);
730     if (!tc) {
731         afs_LookupAFSDB(acellName);
732         tc = afs_FindCellByName(acellName, locktype);
733     }
734     if (tc) {
735         afs_cellname_ref(tc->cnamep);
736         afs_UpdateCellLRU(tc);
737         afs_RefreshCell(tc);
738     }
739
740     return tc;
741 }
742
743 /*!
744  * Return a cell with a given cell number.
745  * \param cellnum Cell number.
746  * \param locktype Lock to be used.
747  * \return
748  */
749 struct cell *
750 afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
751 {
752     struct cell *tc;
753     struct cell_name *cn;
754
755     tc = afs_GetCellStale(cellnum, locktype);
756     if (tc) {
757         afs_RefreshCell(tc);
758     } else {
759         ObtainReadLock(&afs_xcell);
760         cn = afs_cellname_lookup_id(cellnum);
761         ReleaseReadLock(&afs_xcell);
762         if (cn)
763             tc = afs_GetCellByName(cn->cellname, locktype);
764     }
765     return tc;
766 }
767
768 /*!
769  * Same as GetCell, but does not try to refresh the data.
770  * \param cellnum Cell number.
771  * \param locktype What lock should be used.
772  * \return
773  */
774 struct cell *
775 afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
776 {
777     struct cell *tc;
778
779     tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
780     if (tc) {
781         afs_cellname_ref(tc->cnamep);
782         afs_UpdateCellLRU(tc);
783     }
784     return tc;
785 }
786
787 /*!
788  * Return a cell with a given index number (starting at 0). Update CellLRU as well.
789  * \param index
790  * \param locktype Type of lock used.
791  * \return
792  */
793 struct cell *
794 afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
795 {
796     struct cell *tc;
797
798     tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
799     if (tc)
800         afs_UpdateCellLRU(tc);
801     return tc;
802 }
803
804 /*!
805  * Return a cell with a given handle..
806  * \param index
807  * \param locktype Type of lock used.
808  * \return
809  */
810 struct cell *
811 afs_GetCellByHandle(void *handle, afs_int32 locktype)
812 {
813     struct cell *tc;
814
815     tc = afs_TraverseCells(&afs_choose_cell_by_handle, handle);
816     if (tc)
817         afs_UpdateCellLRU(tc);
818     return tc;
819 }
820
821 /*!
822  * Return primary cell, if any.
823  * \param locktype Type of lock used.
824  * \return
825  */
826 struct cell *
827 afs_GetPrimaryCell(afs_int32 locktype)
828 {
829     return afs_GetCellByName(afs_thiscell, locktype);
830 }
831
832 /*!
833  * Returns true if the given cell is the primary cell.
834  * \param cell
835  * \return
836  */
837 int
838 afs_IsPrimaryCell(struct cell *cell)
839 {
840     /* Simple safe checking */
841     if (!cell) {
842         return 0;
843     } else if (!afs_thiscell) {
844         /* This is simply a safety net to avoid seg faults especially when
845          * using a user-space library.  afs_SetPrimaryCell() should be set
846          * prior to this call. */
847         afs_SetPrimaryCell(cell->cellName);
848         return 1;
849     } else {
850         return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
851     }
852 }
853
854 /*!
855  * Returns afs_IsPrimaryCell(afs_GetCell(cellnum)).
856  * \param cellnum
857  * \return
858  */
859 int
860 afs_IsPrimaryCellNum(afs_int32 cellnum)
861 {
862     struct cell *tc;
863     int primary = 0;
864
865     tc = afs_GetCellStale(cellnum, READ_LOCK);
866     if (tc) {
867         primary = afs_IsPrimaryCell(tc);
868         afs_PutCell(tc, READ_LOCK);
869     }
870
871     return primary;
872 }
873
874 /*!
875  * Set the primary cell name to the given cell name.
876  * \param acellName Cell name.
877  * \return 0 for success, < 0 for error.
878  */
879 afs_int32
880 afs_SetPrimaryCell(char *acellName)
881 {
882     ObtainWriteLock(&afs_xcell, 691);
883     if (afs_thiscell)
884         afs_osi_FreeStr(afs_thiscell);
885     afs_thiscell = afs_strdup(acellName);
886     ReleaseWriteLock(&afs_xcell);
887     return 0;
888 }
889
890 /*!
891  * Create or update a cell entry.
892  * \param acellName Name of cell.
893  * \param acellHosts Array of hosts that this cell has.
894  * \param aflags Cell flags.
895  * \param linkedcname
896  * \param fsport File server port.
897  * \param vlport Volume server port.
898  * \param timeout Cell timeout value, 0 means static AFSDB entry.
899  * \return
900  */
901 afs_int32
902 afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
903             char *linkedcname, u_short fsport, u_short vlport, int timeout)
904 {
905     struct cell *tc, *tcl = 0;
906     afs_int32 i, newc = 0, code = 0;
907
908     AFS_STATCNT(afs_NewCell);
909
910     ObtainWriteLock(&afs_xcell, 103);
911
912     tc = afs_FindCellByName_nl(acellName, READ_LOCK);
913     if (tc) {
914         aflags &= ~CNoSUID;
915     } else {
916         tc = (struct cell *)afs_osi_Alloc(sizeof(struct cell));
917         memset(tc, 0, sizeof(*tc));
918         tc->cellName = afs_strdup(acellName);
919         tc->fsport = AFS_FSPORT;
920         tc->vlport = AFS_VLPORT;
921         AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName));
922         AFS_RWLOCK_INIT(&tc->lock, "cell lock");
923         newc = 1;
924         aflags |= CNoSUID;
925     }
926     ObtainWriteLock(&tc->lock, 688);
927
928     /* If the cell we've found has the correct name but no timeout,
929      * and we're called with a non-zero timeout, bail out:  never
930      * override static configuration entries with AFSDB ones.
931      * One exception: if the original cell entry had no servers,
932      * it must get servers from AFSDB.
933      */
934     if (timeout && !tc->timeout && tc->cellHosts[0]) {
935         code = EEXIST;          /* This code is checked for in afs_LookupAFSDB */
936         goto bad;
937     }
938
939     /* we don't want to keep pinging old vlservers which were down,
940      * since they don't matter any more.  It's easier to do this than
941      * to remove the server from its various hash tables. */
942     for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
943         if (!tc->cellHosts[i])
944             break;
945         tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
946         tc->cellHosts[i]->flags |= SRVR_ISGONE;
947     }
948
949     if (fsport)
950         tc->fsport = fsport;
951     if (vlport)
952         tc->vlport = vlport;
953
954     if (aflags & CLinkedCell) {
955         if (!linkedcname) {
956             code = EINVAL;
957             goto bad;
958         }
959         tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
960         if (!tcl) {
961             code = ENOENT;
962             goto bad;
963         }
964         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
965             tcl->lcellp->lcellp = (struct cell *)0;
966             tcl->lcellp->states &= ~CLinkedCell;
967         }
968         tc->lcellp = tcl;
969         tcl->lcellp = tc;
970     }
971     tc->states |= aflags;
972     tc->timeout = timeout;
973
974     memset(tc->cellHosts, 0, sizeof(tc->cellHosts));
975     for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
976         /* Get server for each host and link this cell in.*/
977         struct server *ts;
978         afs_uint32 temp = acellHosts[i];
979         if (!temp)
980             break;
981         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
982         ts->cell = tc;
983         ts->flags &= ~SRVR_ISGONE;
984         /* Set the server as a host of the new cell. */
985         tc->cellHosts[i] = ts;
986         afs_PutServer(ts, WRITE_LOCK);
987     }
988     afs_SortServers(tc->cellHosts, AFS_MAXCELLHOSTS);   /* randomize servers */
989
990     /* New cell: Build and add to LRU cell queue. */
991     if (newc) {
992         struct cell_name *cn;
993
994         cn = afs_cellname_lookup_name(acellName);
995         if (!cn)
996             cn = afs_cellname_new(acellName, 0);
997
998         tc->cnamep = cn;
999         tc->cellNum = cn->cellnum;
1000         tc->cellIndex = afs_cellindex++;
1001         afs_stats_cmperf.numCellsVisible++;
1002         QAdd(&CellLRU, &tc->lruq);
1003     }
1004
1005     ReleaseWriteLock(&tc->lock);
1006     ReleaseWriteLock(&afs_xcell);
1007     afs_PutCell(tc, 0);
1008     if (!(aflags & CHush))
1009         afs_DynrootInvalidate();
1010     return 0;
1011
1012   bad:
1013     if (newc) {
1014         afs_osi_FreeStr(tc->cellName);
1015         afs_osi_Free(tc, sizeof(struct cell));
1016     }
1017     ReleaseWriteLock(&tc->lock);
1018     ReleaseWriteLock(&afs_xcell);
1019     return code;
1020 }
1021
1022 /*
1023  * Miscellaneous stuff
1024  *
1025  * afs_CellInit: perform whatever initialization is necessary
1026  * shutdown_cell: called on shutdown, should deallocate memory, etc
1027  * afs_RemoveCellEntry: remove a server from a cell's server list
1028  * afs_CellOrAliasExists: check if the given name exists as a cell or alias
1029  * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
1030  * afs_CellNumValid: check if a cell number is valid (also set the used flag)
1031  */
1032
1033 /*!
1034  * Perform whatever initialization is necessary.
1035  */
1036 void
1037 afs_CellInit(void)
1038 {
1039     static char CellInit_done = 0;
1040
1041     if (CellInit_done)
1042         return;
1043
1044     CellInit_done = 1;
1045
1046     AFS_RWLOCK_INIT(&afs_xcell, "afs_xcell");
1047     AFS_RWLOCK_INIT(&afsdb_client_lock, "afsdb_client_lock");
1048     AFS_RWLOCK_INIT(&afsdb_req_lock, "afsdb_req_lock");
1049     QInit(&CellLRU);
1050
1051     afs_cellindex = 0;
1052     afs_cellalias_index = 0;
1053 }
1054
1055 /*!
1056  * Called on shutdown, should deallocate memory, etc.
1057  */
1058 void
1059 shutdown_cell(void)
1060 {
1061     struct afs_q *cq, *tq;
1062     struct cell *tc;
1063
1064 #ifdef AFS_CACHE_VNODE_PATH
1065     if (cacheDiskType != AFS_FCACHE_TYPE_MEM) {
1066         afs_osi_FreeStr(afs_cellname_inode.ufs);
1067     }
1068 #endif
1069     AFS_RWLOCK_INIT(&afs_xcell, "afs_xcell");
1070
1071     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1072         tc = QTOC(cq);
1073         tq = QNext(cq);
1074         if (tc->cellName)
1075             afs_osi_FreeStr(tc->cellName);
1076         afs_osi_Free(tc, sizeof(struct cell));
1077     }
1078     QInit(&CellLRU);
1079
1080 {
1081     struct cell_name *cn = afs_cellname_head;
1082
1083     while (cn) {
1084         struct cell_name *next = cn->next;
1085
1086         afs_osi_FreeStr(cn->cellname);
1087         afs_osi_Free(cn, sizeof(struct cell_name));
1088         cn = next;
1089     }
1090 }
1091 }
1092
1093 /*!
1094  * Remove a server from a cell's server list.
1095  * \param srvp Server to be removed.
1096  * \return
1097  */
1098 void
1099 afs_RemoveCellEntry(struct server *srvp)
1100 {
1101     struct cell *tc;
1102     afs_int32 j, k;
1103
1104     tc = srvp->cell;
1105     if (!tc)
1106         return;
1107
1108     /* Remove the server structure from the cell list - if there */
1109     ObtainWriteLock(&tc->lock, 200);
1110     for (j = k = 0; j < AFS_MAXCELLHOSTS; j++) {
1111         if (!tc->cellHosts[j])
1112             break;
1113         if (tc->cellHosts[j] != srvp) {
1114             tc->cellHosts[k++] = tc->cellHosts[j];
1115         }
1116     }
1117     if (k == 0) {
1118         /* What do we do if we remove the last one? */
1119     }
1120     for (; k < AFS_MAXCELLHOSTS; k++) {
1121         tc->cellHosts[k] = 0;
1122     }
1123     ReleaseWriteLock(&tc->lock);
1124 }
1125
1126 /*!
1127  * Check if the given name exists as a cell or alias. Does not lock afs_xcell.
1128  * \param aname
1129  * \return
1130  */
1131 static int
1132 afs_CellOrAliasExists_nl(char *aname)
1133 {
1134     struct cell *c;
1135     struct cell_alias *ca;
1136
1137     c = afs_FindCellByName_nl(aname, READ_LOCK);
1138     if (c) {
1139         afs_PutCell(c, READ_LOCK);
1140         return 1;
1141     }
1142
1143     ca = afs_FindCellAlias(aname);
1144     if (ca) {
1145         afs_PutCellAlias(ca);
1146         return 1;
1147     }
1148
1149     return 0;
1150 }
1151
1152 /*!
1153  * Check if the given name exists as a cell or alias. Locks afs_xcell.
1154  * \param aname
1155  * \return
1156  */
1157 int
1158 afs_CellOrAliasExists(char *aname)
1159 {
1160     int ret;
1161
1162     ObtainReadLock(&afs_xcell);
1163     ret = afs_CellOrAliasExists_nl(aname);
1164     ReleaseReadLock(&afs_xcell);
1165
1166     return ret;
1167 }
1168
1169 /*!
1170  * Check if a cell number is valid (also set the used flag).
1171  * \param cellnum
1172  * \return 1 - true, 0 - false
1173  */
1174 int
1175 afs_CellNumValid(afs_int32 cellnum)
1176 {
1177     struct cell_name *cn;
1178
1179     ObtainReadLock(&afs_xcell);
1180     cn = afs_cellname_lookup_id(cellnum);
1181     ReleaseReadLock(&afs_xcell);
1182     if (cn) {
1183         cn->used = 1;
1184         return 1;
1185     } else {
1186         return 0;
1187     }
1188 }