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 static afs_rwlock_t afsdb_client_lock; /* Serializes client requests */
40 static char afsdb_handler_running; /* Protected by GLOCK */
41 static char afsdb_handler_shutdown; /* Protected by GLOCK */
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 if (afsdb_handler_shutdown)
69 afsdb_handler_running = 1;
71 ObtainSharedLock(&afsdb_req.lock, 683);
72 if (afsdb_req.pending) {
75 UpgradeSToWLock(&afsdb_req.lock, 684);
76 hostCount = kernelMsg[0];
77 *afsdb_req.timeout = kernelMsg[1];
78 if (*afsdb_req.timeout)
79 *afsdb_req.timeout += osi_Time();
80 *afsdb_req.realname = afs_strdup(acellName);
82 for (i = 0; i < MAXCELLHOSTS; i++) {
84 afsdb_req.cellhosts[i] = 0;
86 afsdb_req.cellhosts[i] = kernelMsg[2 + i];
89 /* Request completed, wake up the relevant thread */
90 afsdb_req.pending = 0;
91 afsdb_req.complete = 1;
92 afs_osi_Wakeup(&afsdb_req);
93 ConvertWToSLock(&afsdb_req.lock);
95 ConvertSToRLock(&afsdb_req.lock);
97 /* Wait for a request */
98 while (afsdb_req.pending == 0 && afs_termState != AFSOP_STOP_AFSDB) {
99 ReleaseReadLock(&afsdb_req.lock);
100 afs_osi_Sleep(&afsdb_req);
101 ObtainReadLock(&afsdb_req.lock);
104 /* Check if we're shutting down */
105 if (afs_termState == AFSOP_STOP_AFSDB) {
106 ReleaseReadLock(&afsdb_req.lock);
108 /* Inform anyone waiting for us that we're going away */
109 afsdb_handler_shutdown = 1;
110 afsdb_handler_running = 0;
111 afs_osi_Wakeup(&afsdb_req);
113 afs_termState = AFSOP_STOP_RXEVENT;
114 afs_osi_Wakeup(&afs_termState);
118 /* Return the lookup request to userspace */
119 strncpy(acellName, afsdb_req.cellname, acellNameLen);
120 ReleaseReadLock(&afsdb_req.lock);
125 afs_GetCellHostsAFSDB(char *acellName, afs_int32 * acellHosts, int *timeout,
129 if (!afsdb_handler_running)
132 ObtainWriteLock(&afsdb_client_lock, 685);
133 ObtainWriteLock(&afsdb_req.lock, 686);
136 afsdb_req.cellname = afs_strdup(acellName);
137 afsdb_req.cellhosts = acellHosts;
138 afsdb_req.timeout = timeout;
139 afsdb_req.realname = realName;
141 afsdb_req.complete = 0;
142 afsdb_req.pending = 1;
143 afs_osi_Wakeup(&afsdb_req);
144 ConvertWToRLock(&afsdb_req.lock);
146 while (afsdb_handler_running && !afsdb_req.complete) {
147 ReleaseReadLock(&afsdb_req.lock);
148 afs_osi_Sleep(&afsdb_req);
149 ObtainReadLock(&afsdb_req.lock);
152 afs_osi_FreeStr(afsdb_req.cellname);
153 ReleaseReadLock(&afsdb_req.lock);
154 ReleaseWriteLock(&afsdb_client_lock);
164 afs_LookupAFSDB(char *acellName)
167 afs_int32 *cellHosts;
168 char **realName=NULL;
172 if(!(cellHosts = afs_osi_Alloc(MAXCELLHOSTS * sizeof(afs_int32))))
175 if(!(realName = afs_osi_Alloc(sizeof(char *))))
179 if(!(timeout = afs_osi_Alloc(sizeof(int))))
182 code = afs_GetCellHostsAFSDB(acellName, cellHosts, timeout, realName);
185 code = afs_NewCell(*realName, cellHosts, CNoSUID, NULL, 0, 0, *timeout);
186 if (code && code != EEXIST)
189 /* If we found an alias, create it */
190 if (afs_strcasecmp(acellName, *realName))
191 afs_NewCellAlias(acellName, *realName);
195 afs_osi_Free(timeout, sizeof(int));
196 if (realName && *realName)
197 afs_osi_FreeStr(*realName);
199 afs_osi_Free(realName, sizeof(char *));
201 afs_osi_Free(cellHosts, MAXCELLHOSTS * sizeof(afs_int32));
206 * Cell name-to-ID mapping
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
216 struct cell_name *afs_cellname_head; /* Export for kdump */
217 static ino_t afs_cellname_inode;
218 static int afs_cellname_inode_set;
219 static int afs_cellname_dirty;
220 static afs_int32 afs_cellnum_next;
222 static struct cell_name *
223 afs_cellname_new(char *name, afs_int32 cellnum)
225 struct cell_name *cn;
228 cellnum = afs_cellnum_next;
230 cn = (struct cell_name *)afs_osi_Alloc(sizeof(*cn));
231 cn->next = afs_cellname_head;
232 cn->cellnum = cellnum;
233 cn->cellname = afs_strdup(name);
235 afs_cellname_head = cn;
237 if (cellnum >= afs_cellnum_next)
238 afs_cellnum_next = cellnum + 1;
243 static struct cell_name *
244 afs_cellname_lookup_id(afs_int32 cellnum)
246 struct cell_name *cn;
248 for (cn = afs_cellname_head; cn; cn = cn->next)
249 if (cn->cellnum == cellnum)
255 static struct cell_name *
256 afs_cellname_lookup_name(char *name)
258 struct cell_name *cn;
260 for (cn = afs_cellname_head; cn; cn = cn->next)
261 if (strcmp(cn->cellname, name) == 0)
268 afs_cellname_ref(struct cell_name *cn)
272 afs_cellname_dirty = 1;
277 afs_cellname_init(ino_t inode, int lookupcode)
279 struct osi_file *tfile;
282 ObtainWriteLock(&afs_xcell, 692);
284 afs_cellnum_next = 1;
285 afs_cellname_dirty = 0;
287 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
288 ReleaseWriteLock(&afs_xcell);
292 ReleaseWriteLock(&afs_xcell);
296 tfile = osi_UFSOpen(inode);
298 ReleaseWriteLock(&afs_xcell);
302 afs_cellname_inode = inode;
303 afs_cellname_inode_set = 1;
306 afs_int32 cellnum, clen, magic;
307 struct cell_name *cn;
310 cc = afs_osi_Read(tfile, off, &magic, sizeof(magic));
311 if (cc != sizeof(magic))
313 if (magic != AFS_CELLINFO_MAGIC)
317 cc = afs_osi_Read(tfile, off, &cellnum, sizeof(cellnum));
318 if (cc != sizeof(cellnum))
322 cc = afs_osi_Read(tfile, off, &clen, sizeof(clen));
323 if (cc != sizeof(clen))
327 cellname = afs_osi_Alloc(clen + 1);
331 cc = afs_osi_Read(tfile, off, cellname, clen);
333 afs_osi_Free(cellname, clen + 1);
337 cellname[clen] = '\0';
339 if (afs_cellname_lookup_name(cellname)
340 || afs_cellname_lookup_id(cellnum)) {
341 afs_osi_Free(cellname, clen + 1);
345 cn = afs_cellname_new(cellname, cellnum);
346 afs_osi_Free(cellname, clen + 1);
350 ReleaseWriteLock(&afs_xcell);
355 afs_cellname_write(void)
357 struct osi_file *tfile;
358 struct cell_name *cn;
361 if (!afs_cellname_dirty || !afs_cellname_inode_set)
363 if (afs_initState != 300)
366 ObtainWriteLock(&afs_xcell, 693);
367 afs_cellname_dirty = 0;
369 tfile = osi_UFSOpen(afs_cellname_inode);
371 ReleaseWriteLock(&afs_xcell);
375 for (cn = afs_cellname_head; cn; cn = cn->next) {
376 afs_int32 magic, cellnum, clen;
382 magic = AFS_CELLINFO_MAGIC;
383 cc = afs_osi_Write(tfile, off, &magic, sizeof(magic));
384 if (cc != sizeof(magic))
388 cellnum = cn->cellnum;
389 cc = afs_osi_Write(tfile, off, &cellnum, sizeof(cellnum));
390 if (cc != sizeof(cellnum))
394 clen = strlen(cn->cellname);
395 cc = afs_osi_Write(tfile, off, &clen, sizeof(clen));
396 if (cc != sizeof(clen))
400 cc = afs_osi_Write(tfile, off, cn->cellname, clen);
407 ReleaseWriteLock(&afs_xcell);
412 * Cell alias implementation
414 * afs_FindCellAlias: look up cell alias by alias name
415 * afs_GetCellAlias: get cell alias by index (starting at 0)
416 * afs_PutCellAlias: put back a cell alias returned by Find or Get
417 * afs_NewCellAlias: create new cell alias entry
420 struct cell_alias *afs_cellalias_head; /* Export for kdump */
421 static afs_int32 afs_cellalias_index;
422 static int afs_CellOrAliasExists_nl(char *aname); /* Forward declaration */
424 static struct cell_alias *
425 afs_FindCellAlias(char *alias)
427 struct cell_alias *tc;
429 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
430 if (!strcmp(alias, tc->alias))
436 afs_GetCellAlias(int index)
438 struct cell_alias *tc;
440 ObtainReadLock(&afs_xcell);
441 for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
442 if (tc->index == index)
444 ReleaseReadLock(&afs_xcell);
450 afs_PutCellAlias(struct cell_alias *a)
456 afs_NewCellAlias(char *alias, char *cell)
458 struct cell_alias *tc;
460 ObtainSharedLock(&afs_xcell, 681);
461 if (afs_CellOrAliasExists_nl(alias)) {
462 ReleaseSharedLock(&afs_xcell);
466 UpgradeSToWLock(&afs_xcell, 682);
467 tc = (struct cell_alias *)afs_osi_Alloc(sizeof(struct cell_alias));
468 tc->alias = afs_strdup(alias);
469 tc->cell = afs_strdup(cell);
470 tc->next = afs_cellalias_head;
471 tc->index = afs_cellalias_index++;
472 afs_cellalias_head = tc;
473 ReleaseWriteLock(&afs_xcell);
475 afs_DynrootInvalidate();
480 * Actual cell list implementation
482 * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
483 * afs_RefreshCell: look up cell information in AFSDB if timeout expired
485 * afs_TraverseCells: execute a callback for each existing cell
486 * afs_TraverseCells_nl: same as above except without locking afs_xcell
487 * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
489 * afs_FindCellByName: return a cell with a given name, if it exists
490 * afs_FindCellByName_nl: same as above, without locking afs_xcell
491 * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
492 * afs_GetCell: return a cell with a given cell number
493 * afs_GetCellStale: same as GetCell, but does not try to refresh the data
494 * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
496 * afs_GetPrimaryCell: return the primary cell, if any
497 * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
498 * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
499 * afs_SetPrimaryCell: set the primary cell name to the given cell name
501 * afs_NewCell: create or update a cell entry
504 struct afs_q CellLRU; /* Export for kdump */
505 static char *afs_thiscell;
506 afs_int32 afs_cellindex; /* Export for kdump */
509 afs_UpdateCellLRU(struct cell *c)
511 ObtainWriteLock(&afs_xcell, 100);
513 QAdd(&CellLRU, &c->lruq);
514 ReleaseWriteLock(&afs_xcell);
518 afs_RefreshCell(struct cell *ac)
520 if (ac->states & CNoAFSDB)
522 if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
523 afs_LookupAFSDB(ac->cellName);
527 afs_TraverseCells_nl(void *(*cb) (struct cell *, void *), void *arg)
529 struct afs_q *cq, *tq;
533 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
536 /* This is assuming that a NULL return is acceptable. */
552 afs_TraverseCells(void *(*cb) (struct cell *, void *), void *arg)
556 ObtainReadLock(&afs_xcell);
557 ret = afs_TraverseCells_nl(cb, arg);
558 ReleaseReadLock(&afs_xcell);
564 afs_choose_cell_by_name(struct cell *cell, void *arg)
570 return strcmp(cell->cellName, (char *)arg) ? NULL : cell;
575 afs_choose_cell_by_handle(struct cell *cell, void *arg)
581 return memcmp(cell->cellHandle, (char *)arg, 16) ? NULL : cell;
586 afs_choose_cell_by_num(struct cell *cell, void *arg)
588 return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
592 afs_choose_cell_by_index(struct cell *cell, void *arg)
594 return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
598 afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
600 return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
604 afs_FindCellByName(char *acellName, afs_int32 locktype)
606 return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
610 afs_GetCellByName(char *acellName, afs_int32 locktype)
614 tc = afs_FindCellByName(acellName, locktype);
616 afs_LookupAFSDB(acellName);
617 tc = afs_FindCellByName(acellName, locktype);
620 afs_cellname_ref(tc->cnamep);
621 afs_UpdateCellLRU(tc);
629 afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
632 struct cell_name *cn;
634 tc = afs_GetCellStale(cellnum, locktype);
638 ObtainReadLock(&afs_xcell);
639 cn = afs_cellname_lookup_id(cellnum);
640 ReleaseReadLock(&afs_xcell);
642 tc = afs_GetCellByName(cn->cellname, locktype);
648 afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
652 tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
654 afs_cellname_ref(tc->cnamep);
655 afs_UpdateCellLRU(tc);
661 afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
665 tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
667 afs_UpdateCellLRU(tc);
672 afs_GetCellByHandle(void *handle, afs_int32 locktype)
676 tc = afs_TraverseCells(&afs_choose_cell_by_handle, handle);
678 afs_UpdateCellLRU(tc);
683 afs_GetPrimaryCell(afs_int32 locktype)
685 return afs_GetCellByName(afs_thiscell, locktype);
689 afs_IsPrimaryCell(struct cell *cell)
691 /* Simple safe checking */
694 } else if (!afs_thiscell) {
695 /* This is simply a safety net to avoid seg faults especially when
696 * using a user-space library. afs_SetPrimaryCell() should be set
697 * prior to this call. */
698 afs_SetPrimaryCell(cell->cellName);
701 return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
706 afs_IsPrimaryCellNum(afs_int32 cellnum)
711 tc = afs_GetCellStale(cellnum, READ_LOCK);
713 primary = afs_IsPrimaryCell(tc);
714 afs_PutCell(tc, READ_LOCK);
721 afs_SetPrimaryCell(char *acellName)
723 ObtainWriteLock(&afs_xcell, 691);
725 afs_osi_FreeStr(afs_thiscell);
726 afs_thiscell = afs_strdup(acellName);
727 ReleaseWriteLock(&afs_xcell);
732 afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
733 char *linkedcname, u_short fsport, u_short vlport, int timeout)
735 struct cell *tc, *tcl = 0;
736 afs_int32 i, newc = 0, code = 0;
738 AFS_STATCNT(afs_NewCell);
740 ObtainWriteLock(&afs_xcell, 103);
742 tc = afs_FindCellByName_nl(acellName, READ_LOCK);
746 tc = (struct cell *)afs_osi_Alloc(sizeof(struct cell));
747 memset((char *)tc, 0, sizeof(*tc));
748 tc->cellName = afs_strdup(acellName);
749 tc->fsport = AFS_FSPORT;
750 tc->vlport = AFS_VLPORT;
751 AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName));
752 RWLOCK_INIT(&tc->lock, "cell lock");
754 if (afs_thiscell && !strcmp(acellName, afs_thiscell))
757 ObtainWriteLock(&tc->lock, 688);
759 /* If the cell we've found has the correct name but no timeout,
760 * and we're called with a non-zero timeout, bail out: never
761 * override static configuration entries with AFSDB ones.
762 * One exception: if the original cell entry had no servers,
763 * it must get servers from AFSDB.
765 if (timeout && !tc->timeout && tc->cellHosts[0]) {
766 code = EEXIST; /* This code is checked for in afs_LookupAFSDB */
770 /* we don't want to keep pinging old vlservers which were down,
771 * since they don't matter any more. It's easier to do this than
772 * to remove the server from its various hash tables. */
773 for (i = 0; i < MAXCELLHOSTS; i++) {
774 if (!tc->cellHosts[i])
776 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
777 tc->cellHosts[i]->flags |= SRVR_ISGONE;
785 if (aflags & CLinkedCell) {
790 tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
795 if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */
796 tcl->lcellp->lcellp = (struct cell *)0;
797 tcl->lcellp->states &= ~CLinkedCell;
802 tc->states |= aflags;
803 tc->timeout = timeout;
805 memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
806 for (i = 0; i < MAXCELLHOSTS; i++) {
808 afs_uint32 temp = acellHosts[i];
811 ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
813 ts->flags &= ~SRVR_ISGONE;
814 tc->cellHosts[i] = ts;
815 afs_PutServer(ts, WRITE_LOCK);
817 afs_SortServers(tc->cellHosts, MAXCELLHOSTS); /* randomize servers */
820 struct cell_name *cn;
822 cn = afs_cellname_lookup_name(acellName);
824 cn = afs_cellname_new(acellName, 0);
827 tc->cellNum = cn->cellnum;
828 tc->cellIndex = afs_cellindex++;
829 afs_stats_cmperf.numCellsVisible++;
830 QAdd(&CellLRU, &tc->lruq);
833 ReleaseWriteLock(&tc->lock);
834 ReleaseWriteLock(&afs_xcell);
836 afs_DynrootInvalidate();
841 afs_osi_FreeStr(tc->cellName);
842 afs_osi_Free(tc, sizeof(struct cell));
844 ReleaseWriteLock(&tc->lock);
845 ReleaseWriteLock(&afs_xcell);
850 * Miscellaneous stuff
852 * afs_CellInit: perform whatever initialization is necessary
853 * shutdown_cell: called on shutdown, should deallocate memory, etc
854 * afs_RemoveCellEntry: remove a server from a cell's server list
855 * afs_CellOrAliasExists: check if the given name exists as a cell or alias
856 * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
857 * afs_CellNumValid: check if a cell number is valid (also set the used flag)
863 RWLOCK_INIT(&afs_xcell, "afs_xcell");
865 RWLOCK_INIT(&afsdb_client_lock, "afsdb_client_lock");
866 RWLOCK_INIT(&afsdb_req.lock, "afsdb_req.lock");
871 afs_cellalias_index = 0;
877 struct afs_q *cq, *tq;
880 RWLOCK_INIT(&afs_xcell, "afs_xcell");
882 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
886 afs_osi_FreeStr(tc->cellName);
887 afs_osi_Free(tc, sizeof(struct cell));
892 struct cell_name *cn = afs_cellname_head;
895 struct cell_name *next = cn->next;
897 afs_osi_FreeStr(cn->cellname);
898 afs_osi_Free(cn, sizeof(struct cell_name));
905 afs_RemoveCellEntry(struct server *srvp)
914 /* Remove the server structure from the cell list - if there */
915 ObtainWriteLock(&tc->lock, 200);
916 for (j = k = 0; j < MAXCELLHOSTS; j++) {
917 if (!tc->cellHosts[j])
919 if (tc->cellHosts[j] != srvp) {
920 tc->cellHosts[k++] = tc->cellHosts[j];
924 /* What do we do if we remove the last one? */
926 for (; k < MAXCELLHOSTS; k++) {
927 tc->cellHosts[k] = 0;
929 ReleaseWriteLock(&tc->lock);
933 afs_CellOrAliasExists_nl(char *aname)
936 struct cell_alias *ca;
938 c = afs_FindCellByName_nl(aname, READ_LOCK);
940 afs_PutCell(c, READ_LOCK);
944 ca = afs_FindCellAlias(aname);
946 afs_PutCellAlias(ca);
954 afs_CellOrAliasExists(char *aname)
958 ObtainReadLock(&afs_xcell);
959 ret = afs_CellOrAliasExists_nl(aname);
960 ReleaseReadLock(&afs_xcell);
966 afs_CellNumValid(afs_int32 cellnum)
968 struct cell_name *cn;
970 ObtainReadLock(&afs_xcell);
971 cn = afs_cellname_lookup_id(cellnum);
972 ReleaseReadLock(&afs_xcell);