2 * Copyright 2000, International Business Machines Corporation and others.
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
13 #include <afsconfig.h>
14 #include "../afs/param.h"
18 #include "../afs/stds.h"
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
20 #include "../afs/afsincludes.h" /* Afs-based standard headers */
21 #include "../afs/afs_stats.h" /* afs statistics */
22 #include "../afs/afs_osi.h"
24 /* Local variables. */
25 afs_rwlock_t afs_xcell; /* Export for cmdebug peeking at locks */
28 * AFSDB implementation:
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
37 static afs_rwlock_t afsdb_client_lock; /* Serializes client requests */
38 static char afsdb_handler_running; /* Protected by GLOCK */
39 static char afsdb_handler_shutdown; /* Protected by GLOCK */
53 if (afsdb_handler_running) {
54 afs_osi_Wakeup(&afsdb_req);
56 afsdb_handler_shutdown = 1;
57 afs_termState = AFSOP_STOP_RXEVENT;
61 int afs_AFSDBHandler(char *acellName, int acellNameLen, afs_int32 *kernelMsg)
63 if (afsdb_handler_shutdown) return -2;
64 afsdb_handler_running = 1;
66 ObtainSharedLock(&afsdb_req.lock, 683);
67 if (afsdb_req.pending) {
70 UpgradeSToWLock(&afsdb_req.lock, 684);
71 hostCount = kernelMsg[0];
72 *afsdb_req.timeout = kernelMsg[1];
73 if (*afsdb_req.timeout) *afsdb_req.timeout += osi_Time();
74 *afsdb_req.realname = afs_strdup(acellName);
76 for (i=0; i<MAXCELLHOSTS; i++) {
78 afsdb_req.cellhosts[i] = 0;
80 afsdb_req.cellhosts[i] = kernelMsg[2+i];
83 /* Request completed, wake up the relevant thread */
84 afsdb_req.pending = 0;
85 afsdb_req.complete = 1;
86 afs_osi_Wakeup(&afsdb_req);
87 ConvertWToSLock(&afsdb_req.lock);
89 ConvertSToRLock(&afsdb_req.lock);
91 /* Wait for a request */
92 while (afsdb_req.pending == 0 && afs_termState != AFSOP_STOP_AFSDB) {
93 ReleaseReadLock(&afsdb_req.lock);
94 afs_osi_Sleep(&afsdb_req);
95 ObtainReadLock(&afsdb_req.lock);
98 /* Check if we're shutting down */
99 if (afs_termState == AFSOP_STOP_AFSDB) {
100 ReleaseReadLock(&afsdb_req.lock);
102 /* Inform anyone waiting for us that we're going away */
103 afsdb_handler_shutdown = 1;
104 afsdb_handler_running = 0;
105 afs_osi_Wakeup(&afsdb_req);
107 afs_termState = AFSOP_STOP_RXEVENT;
108 afs_osi_Wakeup(&afs_termState);
112 /* Return the lookup request to userspace */
113 strncpy(acellName, afsdb_req.cellname, acellNameLen);
114 ReleaseReadLock(&afsdb_req.lock);
118 static int afs_GetCellHostsAFSDB(char *acellName, afs_int32 *acellHosts,
119 int *timeout, char **realName)
122 if (!afsdb_handler_running) return ENOENT;
124 ObtainWriteLock(&afsdb_client_lock, 685);
125 ObtainWriteLock(&afsdb_req.lock, 686);
128 afsdb_req.cellname = acellName;
129 afsdb_req.cellhosts = acellHosts;
130 afsdb_req.timeout = timeout;
131 afsdb_req.realname = realName;
133 afsdb_req.complete = 0;
134 afsdb_req.pending = 1;
135 afs_osi_Wakeup(&afsdb_req);
136 ConvertWToRLock(&afsdb_req.lock);
138 while (afsdb_handler_running && !afsdb_req.complete) {
139 ReleaseReadLock(&afsdb_req.lock);
140 afs_osi_Sleep(&afsdb_req);
141 ObtainReadLock(&afsdb_req.lock);
143 ReleaseReadLock(&afsdb_req.lock);
144 ReleaseWriteLock(&afsdb_client_lock);
153 void afs_LookupAFSDB(char *acellName)
156 afs_int32 cellHosts[MAXCELLHOSTS];
157 char *realName = NULL;
160 code = afs_GetCellHostsAFSDB(acellName, cellHosts, &timeout, &realName);
162 code = afs_NewCell(realName, cellHosts, CNoSUID, NULL, 0, 0, timeout);
165 /* If we found an alias, create it */
166 if (afs_strcasecmp(acellName, realName))
167 afs_NewCellAlias(acellName, realName);
171 afs_osi_FreeStr(realName);
176 * Cell name-to-ID mapping
178 * afs_cellname_new: create a new cell name, optional cell number
179 * afs_cellname_lookup_id: look up a cell name
180 * afs_cellname_lookup_name: look up a cell number
181 * afs_cellname_ref: note that this cell name was referenced somewhere
182 * afs_cellname_init: load the list of cells from given inode
183 * afs_cellname_write: write in-kernel list of cells to disk
186 struct cell_name *afs_cellname_head; /* Export for kdump */
187 static ino_t afs_cellname_inode;
188 static int afs_cellname_inode_set;
189 static int afs_cellname_dirty;
190 static afs_int32 afs_cellnum_next;
192 static struct cell_name *afs_cellname_new(char *name, afs_int32 cellnum)
194 struct cell_name *cn;
197 cellnum = afs_cellnum_next;
199 cn = (struct cell_name *) afs_osi_Alloc(sizeof(*cn));
200 cn->next = afs_cellname_head;
201 cn->cellnum = cellnum;
202 cn->cellname = afs_strdup(name);
204 afs_cellname_head = cn;
206 if (cellnum >= afs_cellnum_next)
207 afs_cellnum_next = cellnum + 1;
212 static struct cell_name *afs_cellname_lookup_id(afs_int32 cellnum)
214 struct cell_name *cn;
216 for (cn = afs_cellname_head; cn; cn = cn->next)
217 if (cn->cellnum == cellnum)
223 static struct cell_name *afs_cellname_lookup_name(char *name)
225 struct cell_name *cn;
227 for (cn = afs_cellname_head; cn; cn = cn->next)
228 if (strcmp(cn->cellname, name) == 0)
234 static void afs_cellname_ref(struct cell_name *cn)
238 afs_cellname_dirty = 1;
242 int afs_cellname_init(ino_t inode, int lookupcode)
244 struct osi_file *tfile;
247 ObtainWriteLock(&afs_xcell, 692);
249 afs_cellnum_next = 1;
250 afs_cellname_dirty = 0;
252 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
253 ReleaseWriteLock(&afs_xcell);
257 ReleaseWriteLock(&afs_xcell);
261 tfile = osi_UFSOpen(inode);
263 ReleaseWriteLock(&afs_xcell);
267 afs_cellname_inode = inode;
268 afs_cellname_inode_set = 1;
271 afs_int32 cellnum, clen, magic;
272 struct cell_name *cn;
275 cc = afs_osi_Read(tfile, off, &magic, sizeof(magic));
276 if (cc != sizeof(magic))
278 if (magic != AFS_CELLINFO_MAGIC)
282 cc = afs_osi_Read(tfile, off, &cellnum, sizeof(cellnum));
283 if (cc != sizeof(cellnum))
287 cc = afs_osi_Read(tfile, off, &clen, sizeof(clen));
288 if (cc != sizeof(clen))
292 cellname = afs_osi_Alloc(clen + 1);
296 cc = afs_osi_Read(tfile, off, cellname, clen);
298 afs_osi_Free(cellname, clen + 1);
302 cellname[clen] = '\0';
304 if (afs_cellname_lookup_name(cellname) ||
305 afs_cellname_lookup_id(cellnum)) {
306 afs_osi_Free(cellname, clen + 1);
310 cn = afs_cellname_new(cellname, cellnum);
311 afs_osi_Free(cellname, clen + 1);
315 ReleaseWriteLock(&afs_xcell);
319 int afs_cellname_write()
321 struct osi_file *tfile;
322 struct cell_name *cn;
325 if (!afs_cellname_dirty || !afs_cellname_inode_set)
327 if (afs_initState != 300)
330 ObtainWriteLock(&afs_xcell, 693);
331 afs_cellname_dirty = 0;
333 tfile = osi_UFSOpen(afs_cellname_inode);
335 ReleaseWriteLock(&afs_xcell);
339 for (cn = afs_cellname_head; cn; cn = cn->next) {
340 afs_int32 magic, cellnum, clen;
346 magic = AFS_CELLINFO_MAGIC;
347 cc = afs_osi_Write(tfile, off, &magic, sizeof(magic));
348 if (cc != sizeof(magic))
352 cellnum = cn->cellnum;
353 cc = afs_osi_Write(tfile, off, &cellnum, sizeof(cellnum));
354 if (cc != sizeof(cellnum))
358 clen = strlen(cn->cellname);
359 cc = afs_osi_Write(tfile, off, &clen, sizeof(clen));
360 if (cc != sizeof(clen))
364 cc = afs_osi_Write(tfile, off, cn->cellname, clen);
371 ReleaseWriteLock(&afs_xcell);
376 * Cell alias implementation
378 * afs_FindCellAlias: look up cell alias by alias name
379 * afs_GetCellAlias: get cell alias by index (starting at 0)
380 * afs_PutCellAlias: put back a cell alias returned by Find or Get
381 * afs_NewCellAlias: create new cell alias entry
384 struct cell_alias *afs_cellalias_head; /* Export for kdump */
385 static afs_int32 afs_cellalias_index;
386 static int afs_CellOrAliasExists_nl(char *aname); /* Forward declaration */
388 static struct cell_alias *afs_FindCellAlias(char *alias)
390 struct cell_alias *tc;
392 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
393 if (!strcmp(alias, tc->alias))
398 struct cell_alias *afs_GetCellAlias(int index)
400 struct cell_alias *tc;
402 ObtainReadLock(&afs_xcell);
403 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
404 if (tc->index == index)
406 ReleaseReadLock(&afs_xcell);
411 void afs_PutCellAlias(struct cell_alias *a)
416 afs_int32 afs_NewCellAlias(char *alias, char *cell)
418 struct cell_alias *tc;
420 ObtainSharedLock(&afs_xcell, 681);
421 if (afs_CellOrAliasExists_nl(alias)) {
422 ReleaseSharedLock(&afs_xcell);
426 UpgradeSToWLock(&afs_xcell, 682);
427 tc = (struct cell_alias *) afs_osi_Alloc(sizeof(struct cell_alias));
428 tc->alias = afs_strdup(alias);
429 tc->cell = afs_strdup(cell);
430 tc->next = afs_cellalias_head;
431 tc->index = afs_cellalias_index++;
432 afs_cellalias_head = tc;
433 ReleaseWriteLock(&afs_xcell);
435 afs_DynrootInvalidate();
440 * Actual cell list implementation
442 * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
443 * afs_RefreshCell: look up cell information in AFSDB if timeout expired
445 * afs_TraverseCells: execute a callback for each existing cell
446 * afs_TraverseCells_nl: same as above except without locking afs_xcell
447 * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
449 * afs_FindCellByName: return a cell with a given name, if it exists
450 * afs_FindCellByName_nl: same as above, without locking afs_xcell
451 * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
452 * afs_GetCell: return a cell with a given cell number
453 * afs_GetCellStale: same as GetCell, but does not try to refresh the data
454 * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
456 * afs_GetPrimaryCell: return the primary cell, if any
457 * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
458 * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
459 * afs_SetPrimaryCell: set the primary cell name to the given cell name
461 * afs_NewCell: create or update a cell entry
464 struct afs_q CellLRU; /* Export for kdump */
465 static char *afs_thiscell;
466 static afs_int32 afs_cellindex;
468 static void afs_UpdateCellLRU(struct cell *c)
470 ObtainWriteLock(&afs_xcell, 100);
472 QAdd(&CellLRU, &c->lruq);
473 ReleaseWriteLock(&afs_xcell);
476 static void afs_RefreshCell(struct cell *ac)
478 if (ac->states & CNoAFSDB)
480 if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
481 afs_LookupAFSDB(ac->cellName);
484 static void *afs_TraverseCells_nl(void *(*cb)(struct cell *, void *), void *arg)
486 struct afs_q *cq, *tq;
490 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
491 tc = QTOC(cq); tq = QNext(cq);
499 void *afs_TraverseCells(void *(*cb)(struct cell *, void *), void *arg)
503 ObtainReadLock(&afs_xcell);
504 ret = afs_TraverseCells_nl(cb, arg);
505 ReleaseReadLock(&afs_xcell);
510 static void *afs_choose_cell_by_name(struct cell *cell, void *arg)
512 return strcmp(cell->cellName, (char *) arg) ? NULL : cell;
515 static void *afs_choose_cell_by_num(struct cell *cell, void *arg)
517 return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
520 static void *afs_choose_cell_by_index(struct cell *cell, void *arg)
522 return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
525 static struct cell *afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
527 return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
530 static struct cell *afs_FindCellByName(char *acellName, afs_int32 locktype)
532 return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
535 struct cell *afs_GetCellByName(char *acellName, afs_int32 locktype)
539 tc = afs_FindCellByName(acellName, locktype);
541 afs_LookupAFSDB(acellName);
542 tc = afs_FindCellByName(acellName, locktype);
545 afs_cellname_ref(tc->cnamep);
546 afs_UpdateCellLRU(tc);
553 struct cell *afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
556 struct cell_name *cn;
558 tc = afs_GetCellStale(cellnum, locktype);
562 ObtainReadLock(&afs_xcell);
563 cn = afs_cellname_lookup_id(cellnum);
564 ReleaseReadLock(&afs_xcell);
566 tc = afs_GetCellByName(cn->cellname, locktype);
571 struct cell *afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
575 tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
577 afs_cellname_ref(tc->cnamep);
578 afs_UpdateCellLRU(tc);
583 struct cell *afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
587 tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
589 afs_UpdateCellLRU(tc);
593 struct cell *afs_GetPrimaryCell(afs_int32 locktype)
595 return afs_GetCellByName(afs_thiscell, locktype);
598 int afs_IsPrimaryCell(struct cell *cell)
600 return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
603 int afs_IsPrimaryCellNum(afs_int32 cellnum)
608 tc = afs_GetCellStale(cellnum, READ_LOCK);
610 primary = afs_IsPrimaryCell(tc);
611 afs_PutCell(tc, READ_LOCK);
617 afs_int32 afs_SetPrimaryCell(char *acellName)
619 ObtainWriteLock(&afs_xcell, 691);
621 afs_osi_FreeStr(afs_thiscell);
622 afs_thiscell = afs_strdup(acellName);
623 ReleaseWriteLock(&afs_xcell);
627 afs_int32 afs_NewCell(char *acellName, afs_int32 *acellHosts, int aflags,
628 char *linkedcname, u_short fsport, u_short vlport, int timeout)
630 struct cell *tc, *tcl=0;
631 afs_int32 i, newc=0, code=0;
633 AFS_STATCNT(afs_NewCell);
635 ObtainWriteLock(&afs_xcell, 103);
637 tc = afs_FindCellByName_nl(acellName, READ_LOCK);
641 tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
642 memset((char *) tc, 0, sizeof(*tc));
643 tc->cellName = afs_strdup(acellName);
644 tc->fsport = AFS_FSPORT;
645 tc->vlport = AFS_VLPORT;
646 RWLOCK_INIT(&tc->lock, "cell lock");
648 if (afs_thiscell && !strcmp(acellName, afs_thiscell))
651 ObtainWriteLock(&tc->lock, 688);
653 /* If the cell we've found has the correct name but no timeout,
654 * and we're called with a non-zero timeout, bail out: never
655 * override static configuration entries with AFSDB ones.
656 * One exception: if the original cell entry had no servers,
657 * it must get servers from AFSDB.
659 if (timeout && !tc->timeout && tc->cellHosts[0]) {
664 /* we don't want to keep pinging old vlservers which were down,
665 * since they don't matter any more. It's easier to do this than
666 * to remove the server from its various hash tables. */
667 for (i=0; i<MAXCELLHOSTS; i++) {
668 if (!tc->cellHosts[i]) break;
669 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
670 tc->cellHosts[i]->flags |= SRVR_ISGONE;
673 if (fsport) tc->fsport = fsport;
674 if (vlport) tc->vlport = vlport;
676 if (aflags & CLinkedCell) {
681 tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
686 if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */
687 tcl->lcellp->lcellp = (struct cell *)0;
688 tcl->lcellp->states &= ~CLinkedCell;
693 tc->states |= aflags;
694 tc->timeout = timeout;
696 memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
697 for (i=0; i<MAXCELLHOSTS; i++) {
699 afs_uint32 temp = acellHosts[i];
701 ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
703 ts->flags &= ~SRVR_ISGONE;
704 tc->cellHosts[i] = ts;
705 afs_PutServer(ts, WRITE_LOCK);
707 afs_SortServers(tc->cellHosts, MAXCELLHOSTS); /* randomize servers */
710 struct cell_name *cn;
712 cn = afs_cellname_lookup_name(acellName);
714 cn = afs_cellname_new(acellName, 0);
717 tc->cellNum = cn->cellnum;
718 tc->cellIndex = afs_cellindex++;
719 afs_stats_cmperf.numCellsVisible++;
720 QAdd(&CellLRU, &tc->lruq);
723 ReleaseWriteLock(&tc->lock);
724 ReleaseWriteLock(&afs_xcell);
726 afs_DynrootInvalidate();
731 afs_osi_FreeStr(tc->cellName);
732 afs_osi_Free(tc, sizeof(struct cell));
734 ReleaseWriteLock(&tc->lock);
735 ReleaseWriteLock(&afs_xcell);
740 * Miscellaneous stuff
742 * afs_CellInit: perform whatever initialization is necessary
743 * shutdown_cell: called on shutdown, should deallocate memory, etc
744 * afs_RemoveCellEntry: remove a server from a cell's server list
745 * afs_CellOrAliasExists: check if the given name exists as a cell or alias
746 * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
747 * afs_CellNumValid: check if a cell number is valid (also set the used flag)
752 RWLOCK_INIT(&afs_xcell, "afs_xcell");
754 RWLOCK_INIT(&afsdb_req.lock, "afsdb_req.lock");
759 afs_cellalias_index = 0;
764 struct afs_q *cq, *tq;
767 RWLOCK_INIT(&afs_xcell, "afs_xcell");
769 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
770 tc = QTOC(cq); tq = QNext(cq);
771 if (tc->cellName) afs_osi_FreeStr(tc->cellName);
772 afs_osi_Free(tc, sizeof(struct cell));
777 void afs_RemoveCellEntry(struct server *srvp)
785 /* Remove the server structure from the cell list - if there */
786 ObtainWriteLock(&tc->lock, 200);
787 for (j=k=0; j<MAXCELLHOSTS; j++) {
788 if (!tc->cellHosts[j]) break;
789 if (tc->cellHosts[j] != srvp) {
790 tc->cellHosts[k++] = tc->cellHosts[j];
794 /* What do we do if we remove the last one? */
796 for (; k<MAXCELLHOSTS; k++) {
797 tc->cellHosts[k] = 0;
799 ReleaseWriteLock(&tc->lock);
802 static int afs_CellOrAliasExists_nl(char *aname)
805 struct cell_alias *ca;
807 c = afs_FindCellByName_nl(aname, READ_LOCK);
809 afs_PutCell(c, READ_LOCK);
813 ca = afs_FindCellAlias(aname);
815 afs_PutCellAlias(ca);
822 int afs_CellOrAliasExists(char *aname)
826 ObtainReadLock(&afs_xcell);
827 ret = afs_CellOrAliasExists_nl(aname);
828 ReleaseReadLock(&afs_xcell);
833 int afs_CellNumValid(afs_int32 cellnum)
835 struct cell_name *cn;
837 ObtainReadLock(&afs_xcell);
838 cn = afs_cellname_lookup_id(cellnum);
839 ReleaseReadLock(&afs_xcell);