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"
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"
26 /* Local variables. */
27 afs_rwlock_t afs_xcell; /* Export for cmdebug peeking at locks */
30 * AFSDB implementation:
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
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 */
44 /* from cellconfig.h */
45 #define MAXCELLCHARS 64
47 /* lock moved to afsdb_req_lock for cmdebug */
56 if (afsdb_handler_running) {
57 afs_osi_Wakeup(&afsdb_req);
59 afsdb_handler_shutdown = 1;
60 afs_termState = AFSOP_STOP_RXEVENT;
65 afs_AFSDBHandler(char *acellName, int acellNameLen, afs_int32 * kernelMsg)
67 afs_int32 timeout, code;
68 afs_int32 cellHosts[MAXCELLHOSTS];
70 if (afsdb_handler_shutdown)
72 afsdb_handler_running = 1;
74 ObtainSharedLock(&afsdb_req_lock, 683);
75 if (afsdb_req.pending) {
78 UpgradeSToWLock(&afsdb_req_lock, 684);
79 hostCount = kernelMsg[0];
80 timeout = kernelMsg[1];
82 timeout += osi_Time();
84 for (i = 0; i < MAXCELLHOSTS; i++) {
88 cellHosts[i] = kernelMsg[2 + i];
92 code = afs_NewCell(acellName, cellHosts, CNoSUID, NULL, 0, 0,
95 if (!hostCount || (code && code != EEXIST))
96 /* null out the cellname if the lookup failed */
97 afsdb_req.cellname = NULL;
99 /* If we found an alias, create it */
100 if (afs_strcasecmp(afsdb_req.cellname, acellName))
101 afs_NewCellAlias(afsdb_req.cellname, acellName);
103 /* Request completed, wake up the relevant thread */
104 afsdb_req.pending = 0;
105 afsdb_req.complete = 1;
106 afs_osi_Wakeup(&afsdb_req);
107 ConvertWToSLock(&afsdb_req_lock);
109 ConvertSToRLock(&afsdb_req_lock);
111 /* Wait for a request */
112 while (afsdb_req.pending == 0 && afs_termState != AFSOP_STOP_AFSDB) {
113 ReleaseReadLock(&afsdb_req_lock);
114 afs_osi_Sleep(&afsdb_req);
115 ObtainReadLock(&afsdb_req_lock);
118 /* Check if we're shutting down */
119 if (afs_termState == AFSOP_STOP_AFSDB) {
120 ReleaseReadLock(&afsdb_req_lock);
122 /* Inform anyone waiting for us that we're going away */
123 afsdb_handler_shutdown = 1;
124 afsdb_handler_running = 0;
125 afs_osi_Wakeup(&afsdb_req);
127 afs_termState = AFSOP_STOP_RXEVENT;
128 afs_osi_Wakeup(&afs_termState);
132 /* Return the lookup request to userspace */
133 strncpy(acellName, afsdb_req.cellname, acellNameLen);
134 ReleaseReadLock(&afsdb_req_lock);
139 afs_GetCellHostsAFSDB(char *acellName)
142 if (!afsdb_handler_running)
145 ObtainWriteLock(&afsdb_client_lock, 685);
146 ObtainWriteLock(&afsdb_req_lock, 686);
148 afsdb_req.cellname = acellName;
150 afsdb_req.complete = 0;
151 afsdb_req.pending = 1;
152 afs_osi_Wakeup(&afsdb_req);
153 ConvertWToRLock(&afsdb_req_lock);
155 while (afsdb_handler_running && !afsdb_req.complete) {
156 ReleaseReadLock(&afsdb_req_lock);
157 afs_osi_Sleep(&afsdb_req);
158 ObtainReadLock(&afsdb_req_lock);
161 afs_osi_FreeStr(afsdb_req.cellname);
162 ReleaseReadLock(&afsdb_req_lock);
163 ReleaseWriteLock(&afsdb_client_lock);
165 if (afsdb_req.cellname)
173 afs_LookupAFSDB(char *acellName)
177 char *cellName = afs_strdup(acellName);
179 code = afs_GetCellHostsAFSDB(cellName);
180 afs_Trace2(afs_iclSetp, CM_TRACE_AFSDB, ICL_TYPE_STRING, cellName,
181 ICL_TYPE_INT32, code);
182 afs_osi_FreeStr(cellName);
187 * Cell name-to-ID mapping
189 * afs_cellname_new: create a new cell name, optional cell number
190 * afs_cellname_lookup_id: look up a cell name
191 * afs_cellname_lookup_name: look up a cell number
192 * afs_cellname_ref: note that this cell name was referenced somewhere
193 * afs_cellname_init: load the list of cells from given inode
194 * afs_cellname_write: write in-kernel list of cells to disk
197 struct cell_name *afs_cellname_head; /* Export for kdump */
198 static ino_t afs_cellname_inode;
199 static int afs_cellname_inode_set;
200 static int afs_cellname_dirty;
201 static afs_int32 afs_cellnum_next;
203 static struct cell_name *
204 afs_cellname_new(char *name, afs_int32 cellnum)
206 struct cell_name *cn;
209 cellnum = afs_cellnum_next;
211 cn = (struct cell_name *)afs_osi_Alloc(sizeof(*cn));
212 cn->next = afs_cellname_head;
213 cn->cellnum = cellnum;
214 cn->cellname = afs_strdup(name);
216 afs_cellname_head = cn;
218 if (cellnum >= afs_cellnum_next)
219 afs_cellnum_next = cellnum + 1;
224 static struct cell_name *
225 afs_cellname_lookup_id(afs_int32 cellnum)
227 struct cell_name *cn;
229 for (cn = afs_cellname_head; cn; cn = cn->next)
230 if (cn->cellnum == cellnum)
236 static struct cell_name *
237 afs_cellname_lookup_name(char *name)
239 struct cell_name *cn;
241 for (cn = afs_cellname_head; cn; cn = cn->next)
242 if (strcmp(cn->cellname, name) == 0)
249 afs_cellname_ref(struct cell_name *cn)
253 afs_cellname_dirty = 1;
258 afs_cellname_init(ino_t inode, int lookupcode)
260 struct osi_file *tfile;
263 ObtainWriteLock(&afs_xcell, 692);
265 afs_cellnum_next = 1;
266 afs_cellname_dirty = 0;
268 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
269 ReleaseWriteLock(&afs_xcell);
273 ReleaseWriteLock(&afs_xcell);
277 tfile = osi_UFSOpen(inode);
279 ReleaseWriteLock(&afs_xcell);
283 afs_cellname_inode = inode;
284 afs_cellname_inode_set = 1;
287 afs_int32 cellnum, clen, magic;
288 struct cell_name *cn;
291 cc = afs_osi_Read(tfile, off, &magic, sizeof(magic));
292 if (cc != sizeof(magic))
294 if (magic != AFS_CELLINFO_MAGIC)
298 cc = afs_osi_Read(tfile, off, &cellnum, sizeof(cellnum));
299 if (cc != sizeof(cellnum))
303 cc = afs_osi_Read(tfile, off, &clen, sizeof(clen));
304 if (cc != sizeof(clen))
308 cellname = afs_osi_Alloc(clen + 1);
312 cc = afs_osi_Read(tfile, off, cellname, clen);
314 afs_osi_Free(cellname, clen + 1);
318 cellname[clen] = '\0';
320 if (afs_cellname_lookup_name(cellname)
321 || afs_cellname_lookup_id(cellnum)) {
322 afs_osi_Free(cellname, clen + 1);
326 cn = afs_cellname_new(cellname, cellnum);
327 afs_osi_Free(cellname, clen + 1);
331 ReleaseWriteLock(&afs_xcell);
336 afs_cellname_write(void)
338 struct osi_file *tfile;
339 struct cell_name *cn;
342 if (!afs_cellname_dirty || !afs_cellname_inode_set)
344 if (afs_initState != 300)
347 ObtainWriteLock(&afs_xcell, 693);
348 afs_cellname_dirty = 0;
350 tfile = osi_UFSOpen(afs_cellname_inode);
352 ReleaseWriteLock(&afs_xcell);
356 for (cn = afs_cellname_head; cn; cn = cn->next) {
357 afs_int32 magic, cellnum, clen;
363 magic = AFS_CELLINFO_MAGIC;
364 cc = afs_osi_Write(tfile, off, &magic, sizeof(magic));
365 if (cc != sizeof(magic))
369 cellnum = cn->cellnum;
370 cc = afs_osi_Write(tfile, off, &cellnum, sizeof(cellnum));
371 if (cc != sizeof(cellnum))
375 clen = strlen(cn->cellname);
376 cc = afs_osi_Write(tfile, off, &clen, sizeof(clen));
377 if (cc != sizeof(clen))
381 cc = afs_osi_Write(tfile, off, cn->cellname, clen);
388 ReleaseWriteLock(&afs_xcell);
393 * Cell alias implementation
395 * afs_FindCellAlias: look up cell alias by alias name
396 * afs_GetCellAlias: get cell alias by index (starting at 0)
397 * afs_PutCellAlias: put back a cell alias returned by Find or Get
398 * afs_NewCellAlias: create new cell alias entry
401 struct cell_alias *afs_cellalias_head; /* Export for kdump */
402 static afs_int32 afs_cellalias_index;
403 static int afs_CellOrAliasExists_nl(char *aname); /* Forward declaration */
405 static struct cell_alias *
406 afs_FindCellAlias(char *alias)
408 struct cell_alias *tc;
410 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
411 if (!strcmp(alias, tc->alias))
417 afs_GetCellAlias(int index)
419 struct cell_alias *tc;
421 ObtainReadLock(&afs_xcell);
422 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
423 if (tc->index == index)
425 ReleaseReadLock(&afs_xcell);
431 afs_PutCellAlias(struct cell_alias *a)
437 afs_NewCellAlias(char *alias, char *cell)
439 struct cell_alias *tc;
441 ObtainSharedLock(&afs_xcell, 681);
442 if (afs_CellOrAliasExists_nl(alias)) {
443 ReleaseSharedLock(&afs_xcell);
447 UpgradeSToWLock(&afs_xcell, 682);
448 tc = (struct cell_alias *)afs_osi_Alloc(sizeof(struct cell_alias));
449 tc->alias = afs_strdup(alias);
450 tc->cell = afs_strdup(cell);
451 tc->next = afs_cellalias_head;
452 tc->index = afs_cellalias_index++;
453 afs_cellalias_head = tc;
454 ReleaseWriteLock(&afs_xcell);
456 afs_DynrootInvalidate();
461 * Actual cell list implementation
463 * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
464 * afs_RefreshCell: look up cell information in AFSDB if timeout expired
466 * afs_TraverseCells: execute a callback for each existing cell
467 * afs_TraverseCells_nl: same as above except without locking afs_xcell
468 * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
470 * afs_FindCellByName: return a cell with a given name, if it exists
471 * afs_FindCellByName_nl: same as above, without locking afs_xcell
472 * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
473 * afs_GetCell: return a cell with a given cell number
474 * afs_GetCellStale: same as GetCell, but does not try to refresh the data
475 * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
477 * afs_GetPrimaryCell: return the primary cell, if any
478 * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
479 * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
480 * afs_SetPrimaryCell: set the primary cell name to the given cell name
482 * afs_NewCell: create or update a cell entry
485 struct afs_q CellLRU; /* Export for kdump */
486 static char *afs_thiscell;
487 afs_int32 afs_cellindex; /* Export for kdump */
490 afs_UpdateCellLRU(struct cell *c)
492 ObtainWriteLock(&afs_xcell, 100);
494 QAdd(&CellLRU, &c->lruq);
495 ReleaseWriteLock(&afs_xcell);
499 afs_RefreshCell(struct cell *ac)
501 if (ac->states & CNoAFSDB)
503 if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
504 afs_LookupAFSDB(ac->cellName);
508 afs_TraverseCells_nl(void *(*cb) (struct cell *, void *), void *arg)
510 struct afs_q *cq, *tq;
514 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
517 /* This is assuming that a NULL return is acceptable. */
533 afs_TraverseCells(void *(*cb) (struct cell *, void *), void *arg)
537 ObtainReadLock(&afs_xcell);
538 ret = afs_TraverseCells_nl(cb, arg);
539 ReleaseReadLock(&afs_xcell);
545 afs_choose_cell_by_name(struct cell *cell, void *arg)
551 return strcmp(cell->cellName, (char *)arg) ? NULL : cell;
556 afs_choose_cell_by_handle(struct cell *cell, void *arg)
562 return memcmp(cell->cellHandle, (char *)arg, 16) ? NULL : cell;
567 afs_choose_cell_by_num(struct cell *cell, void *arg)
569 return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
573 afs_choose_cell_by_index(struct cell *cell, void *arg)
575 return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
579 afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
581 return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
585 afs_FindCellByName(char *acellName, afs_int32 locktype)
587 return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
591 afs_GetCellByName(char *acellName, afs_int32 locktype)
595 tc = afs_FindCellByName(acellName, locktype);
597 afs_LookupAFSDB(acellName);
598 tc = afs_FindCellByName(acellName, locktype);
601 afs_cellname_ref(tc->cnamep);
602 afs_UpdateCellLRU(tc);
610 afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
613 struct cell_name *cn;
615 tc = afs_GetCellStale(cellnum, locktype);
619 ObtainReadLock(&afs_xcell);
620 cn = afs_cellname_lookup_id(cellnum);
621 ReleaseReadLock(&afs_xcell);
623 tc = afs_GetCellByName(cn->cellname, locktype);
629 afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
633 tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
635 afs_cellname_ref(tc->cnamep);
636 afs_UpdateCellLRU(tc);
642 afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
646 tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
648 afs_UpdateCellLRU(tc);
653 afs_GetCellByHandle(void *handle, afs_int32 locktype)
657 tc = afs_TraverseCells(&afs_choose_cell_by_handle, handle);
659 afs_UpdateCellLRU(tc);
664 afs_GetPrimaryCell(afs_int32 locktype)
666 return afs_GetCellByName(afs_thiscell, locktype);
670 afs_IsPrimaryCell(struct cell *cell)
672 /* Simple safe checking */
675 } else if (!afs_thiscell) {
676 /* This is simply a safety net to avoid seg faults especially when
677 * using a user-space library. afs_SetPrimaryCell() should be set
678 * prior to this call. */
679 afs_SetPrimaryCell(cell->cellName);
682 return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
687 afs_IsPrimaryCellNum(afs_int32 cellnum)
692 tc = afs_GetCellStale(cellnum, READ_LOCK);
694 primary = afs_IsPrimaryCell(tc);
695 afs_PutCell(tc, READ_LOCK);
702 afs_SetPrimaryCell(char *acellName)
704 ObtainWriteLock(&afs_xcell, 691);
706 afs_osi_FreeStr(afs_thiscell);
707 afs_thiscell = afs_strdup(acellName);
708 ReleaseWriteLock(&afs_xcell);
713 afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
714 char *linkedcname, u_short fsport, u_short vlport, int timeout)
716 struct cell *tc, *tcl = 0;
717 afs_int32 i, newc = 0, code = 0;
719 AFS_STATCNT(afs_NewCell);
721 ObtainWriteLock(&afs_xcell, 103);
723 tc = afs_FindCellByName_nl(acellName, READ_LOCK);
727 tc = (struct cell *)afs_osi_Alloc(sizeof(struct cell));
728 memset((char *)tc, 0, sizeof(*tc));
729 tc->cellName = afs_strdup(acellName);
730 tc->fsport = AFS_FSPORT;
731 tc->vlport = AFS_VLPORT;
732 AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName));
733 RWLOCK_INIT(&tc->lock, "cell lock");
737 ObtainWriteLock(&tc->lock, 688);
739 /* If the cell we've found has the correct name but no timeout,
740 * and we're called with a non-zero timeout, bail out: never
741 * override static configuration entries with AFSDB ones.
742 * One exception: if the original cell entry had no servers,
743 * it must get servers from AFSDB.
745 if (timeout && !tc->timeout && tc->cellHosts[0]) {
746 code = EEXIST; /* This code is checked for in afs_LookupAFSDB */
750 /* we don't want to keep pinging old vlservers which were down,
751 * since they don't matter any more. It's easier to do this than
752 * to remove the server from its various hash tables. */
753 for (i = 0; i < MAXCELLHOSTS; i++) {
754 if (!tc->cellHosts[i])
756 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
757 tc->cellHosts[i]->flags |= SRVR_ISGONE;
765 if (aflags & CLinkedCell) {
770 tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
775 if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */
776 tcl->lcellp->lcellp = (struct cell *)0;
777 tcl->lcellp->states &= ~CLinkedCell;
782 tc->states |= aflags;
783 tc->timeout = timeout;
785 memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
786 for (i = 0; i < MAXCELLHOSTS; i++) {
788 afs_uint32 temp = acellHosts[i];
791 ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
793 ts->flags &= ~SRVR_ISGONE;
794 tc->cellHosts[i] = ts;
795 afs_PutServer(ts, WRITE_LOCK);
797 afs_SortServers(tc->cellHosts, MAXCELLHOSTS); /* randomize servers */
800 struct cell_name *cn;
802 cn = afs_cellname_lookup_name(acellName);
804 cn = afs_cellname_new(acellName, 0);
807 tc->cellNum = cn->cellnum;
808 tc->cellIndex = afs_cellindex++;
809 afs_stats_cmperf.numCellsVisible++;
810 QAdd(&CellLRU, &tc->lruq);
813 ReleaseWriteLock(&tc->lock);
814 ReleaseWriteLock(&afs_xcell);
816 afs_DynrootInvalidate();
821 afs_osi_FreeStr(tc->cellName);
822 afs_osi_Free(tc, sizeof(struct cell));
824 ReleaseWriteLock(&tc->lock);
825 ReleaseWriteLock(&afs_xcell);
830 * Miscellaneous stuff
832 * afs_CellInit: perform whatever initialization is necessary
833 * shutdown_cell: called on shutdown, should deallocate memory, etc
834 * afs_RemoveCellEntry: remove a server from a cell's server list
835 * afs_CellOrAliasExists: check if the given name exists as a cell or alias
836 * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
837 * afs_CellNumValid: check if a cell number is valid (also set the used flag)
843 RWLOCK_INIT(&afs_xcell, "afs_xcell");
845 RWLOCK_INIT(&afsdb_client_lock, "afsdb_client_lock");
846 RWLOCK_INIT(&afsdb_req_lock, "afsdb_req_lock");
851 afs_cellalias_index = 0;
857 struct afs_q *cq, *tq;
860 RWLOCK_INIT(&afs_xcell, "afs_xcell");
862 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
866 afs_osi_FreeStr(tc->cellName);
867 afs_osi_Free(tc, sizeof(struct cell));
872 struct cell_name *cn = afs_cellname_head;
875 struct cell_name *next = cn->next;
877 afs_osi_FreeStr(cn->cellname);
878 afs_osi_Free(cn, sizeof(struct cell_name));
885 afs_RemoveCellEntry(struct server *srvp)
894 /* Remove the server structure from the cell list - if there */
895 ObtainWriteLock(&tc->lock, 200);
896 for (j = k = 0; j < MAXCELLHOSTS; j++) {
897 if (!tc->cellHosts[j])
899 if (tc->cellHosts[j] != srvp) {
900 tc->cellHosts[k++] = tc->cellHosts[j];
904 /* What do we do if we remove the last one? */
906 for (; k < MAXCELLHOSTS; k++) {
907 tc->cellHosts[k] = 0;
909 ReleaseWriteLock(&tc->lock);
913 afs_CellOrAliasExists_nl(char *aname)
916 struct cell_alias *ca;
918 c = afs_FindCellByName_nl(aname, READ_LOCK);
920 afs_PutCell(c, READ_LOCK);
924 ca = afs_FindCellAlias(aname);
926 afs_PutCellAlias(ca);
934 afs_CellOrAliasExists(char *aname)
938 ObtainReadLock(&afs_xcell);
939 ret = afs_CellOrAliasExists_nl(aname);
940 ReleaseReadLock(&afs_xcell);
946 afs_CellNumValid(afs_int32 cellnum)
948 struct cell_name *cn;
950 ObtainReadLock(&afs_xcell);
951 cn = afs_cellname_lookup_id(cellnum);
952 ReleaseReadLock(&afs_xcell);