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