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