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