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"
17 ("$Header: /cvs/openafs/src/afs/afs_cell.c,v 1.30.2.3 2005/09/23 14:56:26 shadow Exp $");
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"
25 /* Local variables. */
26 afs_rwlock_t afs_xcell
; /* Export for cmdebug peeking at locks */
29 * AFSDB implementation:
31 * afs_StopAFSDB: terminate the AFSDB handler, used on shutdown
32 * afs_AFSDBHandler: entry point for user-space AFSDB request handler
33 * afs_GetCellHostsAFSDB: query the AFSDB handler and wait for response
34 * afs_LookupAFSDB: look up AFSDB for given cell name and create locally
38 static afs_rwlock_t afsdb_client_lock
; /* Serializes client requests */
39 static char afsdb_handler_running
; /* Protected by GLOCK */
40 static char afsdb_handler_shutdown
; /* Protected by GLOCK */
55 if (afsdb_handler_running
) {
56 afs_osi_Wakeup(&afsdb_req
);
58 afsdb_handler_shutdown
= 1;
59 afs_termState
= AFSOP_STOP_RXEVENT
;
64 afs_AFSDBHandler(char *acellName
, int acellNameLen
, afs_int32
* kernelMsg
)
66 if (afsdb_handler_shutdown
)
68 afsdb_handler_running
= 1;
70 ObtainSharedLock(&afsdb_req
.lock
, 683);
71 if (afsdb_req
.pending
) {
74 UpgradeSToWLock(&afsdb_req
.lock
, 684);
75 hostCount
= kernelMsg
[0];
76 *afsdb_req
.timeout
= kernelMsg
[1];
77 if (*afsdb_req
.timeout
)
78 *afsdb_req
.timeout
+= osi_Time();
79 *afsdb_req
.realname
= afs_strdup(acellName
);
81 for (i
= 0; i
< MAXCELLHOSTS
; i
++) {
83 afsdb_req
.cellhosts
[i
] = 0;
85 afsdb_req
.cellhosts
[i
] = kernelMsg
[2 + i
];
88 /* Request completed, wake up the relevant thread */
89 afsdb_req
.pending
= 0;
90 afsdb_req
.complete
= 1;
91 afs_osi_Wakeup(&afsdb_req
);
92 ConvertWToSLock(&afsdb_req
.lock
);
94 ConvertSToRLock(&afsdb_req
.lock
);
96 /* Wait for a request */
97 while (afsdb_req
.pending
== 0 && afs_termState
!= AFSOP_STOP_AFSDB
) {
98 ReleaseReadLock(&afsdb_req
.lock
);
99 afs_osi_Sleep(&afsdb_req
);
100 ObtainReadLock(&afsdb_req
.lock
);
103 /* Check if we're shutting down */
104 if (afs_termState
== AFSOP_STOP_AFSDB
) {
105 ReleaseReadLock(&afsdb_req
.lock
);
107 /* Inform anyone waiting for us that we're going away */
108 afsdb_handler_shutdown
= 1;
109 afsdb_handler_running
= 0;
110 afs_osi_Wakeup(&afsdb_req
);
112 afs_termState
= AFSOP_STOP_RXEVENT
;
113 afs_osi_Wakeup(&afs_termState
);
117 /* Return the lookup request to userspace */
118 strncpy(acellName
, afsdb_req
.cellname
, acellNameLen
);
119 ReleaseReadLock(&afsdb_req
.lock
);
124 afs_GetCellHostsAFSDB(char *acellName
, afs_int32
* acellHosts
, int *timeout
,
128 if (!afsdb_handler_running
)
131 ObtainWriteLock(&afsdb_client_lock
, 685);
132 ObtainWriteLock(&afsdb_req
.lock
, 686);
135 afsdb_req
.cellname
= acellName
;
136 afsdb_req
.cellhosts
= acellHosts
;
137 afsdb_req
.timeout
= timeout
;
138 afsdb_req
.realname
= realName
;
140 afsdb_req
.complete
= 0;
141 afsdb_req
.pending
= 1;
142 afs_osi_Wakeup(&afsdb_req
);
143 ConvertWToRLock(&afsdb_req
.lock
);
145 while (afsdb_handler_running
&& !afsdb_req
.complete
) {
146 ReleaseReadLock(&afsdb_req
.lock
);
147 afs_osi_Sleep(&afsdb_req
);
148 ObtainReadLock(&afsdb_req
.lock
);
150 ReleaseReadLock(&afsdb_req
.lock
);
151 ReleaseWriteLock(&afsdb_client_lock
);
161 afs_LookupAFSDB(char *acellName
)
164 afs_int32 cellHosts
[MAXCELLHOSTS
];
165 char *realName
= NULL
;
168 code
= afs_GetCellHostsAFSDB(acellName
, cellHosts
, &timeout
, &realName
);
171 code
= afs_NewCell(realName
, cellHosts
, CNoSUID
, NULL
, 0, 0, timeout
);
172 if (code
&& code
!= EEXIST
)
175 /* If we found an alias, create it */
176 if (afs_strcasecmp(acellName
, realName
))
177 afs_NewCellAlias(acellName
, realName
);
181 afs_osi_FreeStr(realName
);
186 * Cell name-to-ID mapping
188 * afs_cellname_new: create a new cell name, optional cell number
189 * afs_cellname_lookup_id: look up a cell name
190 * afs_cellname_lookup_name: look up a cell number
191 * afs_cellname_ref: note that this cell name was referenced somewhere
192 * afs_cellname_init: load the list of cells from given inode
193 * afs_cellname_write: write in-kernel list of cells to disk
196 struct cell_name
*afs_cellname_head
; /* Export for kdump */
197 static ino_t afs_cellname_inode
;
198 static int afs_cellname_inode_set
;
199 static int afs_cellname_dirty
;
200 static afs_int32 afs_cellnum_next
;
202 static struct cell_name
*
203 afs_cellname_new(char *name
, afs_int32 cellnum
)
205 struct cell_name
*cn
;
208 cellnum
= afs_cellnum_next
;
210 cn
= (struct cell_name
*)afs_osi_Alloc(sizeof(*cn
));
211 cn
->next
= afs_cellname_head
;
212 cn
->cellnum
= cellnum
;
213 cn
->cellname
= afs_strdup(name
);
215 afs_cellname_head
= cn
;
217 if (cellnum
>= afs_cellnum_next
)
218 afs_cellnum_next
= cellnum
+ 1;
223 static struct cell_name
*
224 afs_cellname_lookup_id(afs_int32 cellnum
)
226 struct cell_name
*cn
;
228 for (cn
= afs_cellname_head
; cn
; cn
= cn
->next
)
229 if (cn
->cellnum
== cellnum
)
235 static struct cell_name
*
236 afs_cellname_lookup_name(char *name
)
238 struct cell_name
*cn
;
240 for (cn
= afs_cellname_head
; cn
; cn
= cn
->next
)
241 if (strcmp(cn
->cellname
, name
) == 0)
248 afs_cellname_ref(struct cell_name
*cn
)
252 afs_cellname_dirty
= 1;
257 afs_cellname_init(ino_t inode
, int lookupcode
)
259 struct osi_file
*tfile
;
262 ObtainWriteLock(&afs_xcell
, 692);
264 afs_cellnum_next
= 1;
265 afs_cellname_dirty
= 0;
267 if (cacheDiskType
== AFS_FCACHE_TYPE_MEM
) {
268 ReleaseWriteLock(&afs_xcell
);
272 ReleaseWriteLock(&afs_xcell
);
276 tfile
= osi_UFSOpen(inode
);
278 ReleaseWriteLock(&afs_xcell
);
282 afs_cellname_inode
= inode
;
283 afs_cellname_inode_set
= 1;
286 afs_int32 cellnum
, clen
, magic
;
287 struct cell_name
*cn
;
290 cc
= afs_osi_Read(tfile
, off
, &magic
, sizeof(magic
));
291 if (cc
!= sizeof(magic
))
293 if (magic
!= AFS_CELLINFO_MAGIC
)
297 cc
= afs_osi_Read(tfile
, off
, &cellnum
, sizeof(cellnum
));
298 if (cc
!= sizeof(cellnum
))
302 cc
= afs_osi_Read(tfile
, off
, &clen
, sizeof(clen
));
303 if (cc
!= sizeof(clen
))
307 cellname
= afs_osi_Alloc(clen
+ 1);
311 cc
= afs_osi_Read(tfile
, off
, cellname
, clen
);
313 afs_osi_Free(cellname
, clen
+ 1);
317 cellname
[clen
] = '\0';
319 if (afs_cellname_lookup_name(cellname
)
320 || afs_cellname_lookup_id(cellnum
)) {
321 afs_osi_Free(cellname
, clen
+ 1);
325 cn
= afs_cellname_new(cellname
, cellnum
);
326 afs_osi_Free(cellname
, clen
+ 1);
330 ReleaseWriteLock(&afs_xcell
);
335 afs_cellname_write(void)
337 struct osi_file
*tfile
;
338 struct cell_name
*cn
;
341 if (!afs_cellname_dirty
|| !afs_cellname_inode_set
)
343 if (afs_initState
!= 300)
346 ObtainWriteLock(&afs_xcell
, 693);
347 afs_cellname_dirty
= 0;
349 tfile
= osi_UFSOpen(afs_cellname_inode
);
351 ReleaseWriteLock(&afs_xcell
);
355 for (cn
= afs_cellname_head
; cn
; cn
= cn
->next
) {
356 afs_int32 magic
, cellnum
, clen
;
362 magic
= AFS_CELLINFO_MAGIC
;
363 cc
= afs_osi_Write(tfile
, off
, &magic
, sizeof(magic
));
364 if (cc
!= sizeof(magic
))
368 cellnum
= cn
->cellnum
;
369 cc
= afs_osi_Write(tfile
, off
, &cellnum
, sizeof(cellnum
));
370 if (cc
!= sizeof(cellnum
))
374 clen
= strlen(cn
->cellname
);
375 cc
= afs_osi_Write(tfile
, off
, &clen
, sizeof(clen
));
376 if (cc
!= sizeof(clen
))
380 cc
= afs_osi_Write(tfile
, off
, cn
->cellname
, clen
);
387 ReleaseWriteLock(&afs_xcell
);
392 * Cell alias implementation
394 * afs_FindCellAlias: look up cell alias by alias name
395 * afs_GetCellAlias: get cell alias by index (starting at 0)
396 * afs_PutCellAlias: put back a cell alias returned by Find or Get
397 * afs_NewCellAlias: create new cell alias entry
400 struct cell_alias
*afs_cellalias_head
; /* Export for kdump */
401 static afs_int32 afs_cellalias_index
;
402 static int afs_CellOrAliasExists_nl(char *aname
); /* Forward declaration */
404 static struct cell_alias
*
405 afs_FindCellAlias(char *alias
)
407 struct cell_alias
*tc
;
409 for (tc
= afs_cellalias_head
; tc
!= NULL
; tc
= tc
->next
)
410 if (!strcmp(alias
, tc
->alias
))
416 afs_GetCellAlias(int index
)
418 struct cell_alias
*tc
;
420 ObtainReadLock(&afs_xcell
);
421 for (tc
= afs_cellalias_head
; tc
!= NULL
; tc
= tc
->next
)
422 if (tc
->index
== index
)
424 ReleaseReadLock(&afs_xcell
);
430 afs_PutCellAlias(struct cell_alias
*a
)
436 afs_NewCellAlias(char *alias
, char *cell
)
438 struct cell_alias
*tc
;
440 ObtainSharedLock(&afs_xcell
, 681);
441 if (afs_CellOrAliasExists_nl(alias
)) {
442 ReleaseSharedLock(&afs_xcell
);
446 UpgradeSToWLock(&afs_xcell
, 682);
447 tc
= (struct cell_alias
*)afs_osi_Alloc(sizeof(struct cell_alias
));
448 tc
->alias
= afs_strdup(alias
);
449 tc
->cell
= afs_strdup(cell
);
450 tc
->next
= afs_cellalias_head
;
451 tc
->index
= afs_cellalias_index
++;
452 afs_cellalias_head
= tc
;
453 ReleaseWriteLock(&afs_xcell
);
455 afs_DynrootInvalidate();
460 * Actual cell list implementation
462 * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
463 * afs_RefreshCell: look up cell information in AFSDB if timeout expired
465 * afs_TraverseCells: execute a callback for each existing cell
466 * afs_TraverseCells_nl: same as above except without locking afs_xcell
467 * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
469 * afs_FindCellByName: return a cell with a given name, if it exists
470 * afs_FindCellByName_nl: same as above, without locking afs_xcell
471 * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
472 * afs_GetCell: return a cell with a given cell number
473 * afs_GetCellStale: same as GetCell, but does not try to refresh the data
474 * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
476 * afs_GetPrimaryCell: return the primary cell, if any
477 * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
478 * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
479 * afs_SetPrimaryCell: set the primary cell name to the given cell name
481 * afs_NewCell: create or update a cell entry
484 struct afs_q CellLRU
; /* Export for kdump */
485 static char *afs_thiscell
;
486 afs_int32 afs_cellindex
; /* Export for kdump */
489 afs_UpdateCellLRU(struct cell
*c
)
491 ObtainWriteLock(&afs_xcell
, 100);
493 QAdd(&CellLRU
, &c
->lruq
);
494 ReleaseWriteLock(&afs_xcell
);
498 afs_RefreshCell(struct cell
*ac
)
500 if (ac
->states
& CNoAFSDB
)
502 if (!ac
->cellHosts
[0] || (ac
->timeout
&& ac
->timeout
<= osi_Time()))
503 afs_LookupAFSDB(ac
->cellName
);
507 afs_TraverseCells_nl(void *(*cb
) (struct cell
*, void *), void *arg
)
509 struct afs_q
*cq
, *tq
;
513 for (cq
= CellLRU
.next
; cq
!= &CellLRU
; cq
= tq
) {
516 /* This is assuming that a NULL return is acceptable. */
532 afs_TraverseCells(void *(*cb
) (struct cell
*, void *), void *arg
)
536 ObtainReadLock(&afs_xcell
);
537 ret
= afs_TraverseCells_nl(cb
, arg
);
538 ReleaseReadLock(&afs_xcell
);
544 afs_choose_cell_by_name(struct cell
*cell
, void *arg
)
550 return strcmp(cell
->cellName
, (char *)arg
) ? NULL
: cell
;
555 afs_choose_cell_by_num(struct cell
*cell
, void *arg
)
557 return (cell
->cellNum
== *((afs_int32
*) arg
)) ? cell
: NULL
;
561 afs_choose_cell_by_index(struct cell
*cell
, void *arg
)
563 return (cell
->cellIndex
== *((afs_int32
*) arg
)) ? cell
: NULL
;
567 afs_FindCellByName_nl(char *acellName
, afs_int32 locktype
)
569 return afs_TraverseCells_nl(&afs_choose_cell_by_name
, acellName
);
573 afs_FindCellByName(char *acellName
, afs_int32 locktype
)
575 return afs_TraverseCells(&afs_choose_cell_by_name
, acellName
);
579 afs_GetCellByName(char *acellName
, afs_int32 locktype
)
583 tc
= afs_FindCellByName(acellName
, locktype
);
585 afs_LookupAFSDB(acellName
);
586 tc
= afs_FindCellByName(acellName
, locktype
);
589 afs_cellname_ref(tc
->cnamep
);
590 afs_UpdateCellLRU(tc
);
598 afs_GetCell(afs_int32 cellnum
, afs_int32 locktype
)
601 struct cell_name
*cn
;
603 tc
= afs_GetCellStale(cellnum
, locktype
);
607 ObtainReadLock(&afs_xcell
);
608 cn
= afs_cellname_lookup_id(cellnum
);
609 ReleaseReadLock(&afs_xcell
);
611 tc
= afs_GetCellByName(cn
->cellname
, locktype
);
617 afs_GetCellStale(afs_int32 cellnum
, afs_int32 locktype
)
621 tc
= afs_TraverseCells(&afs_choose_cell_by_num
, &cellnum
);
623 afs_cellname_ref(tc
->cnamep
);
624 afs_UpdateCellLRU(tc
);
630 afs_GetCellByIndex(afs_int32 index
, afs_int32 locktype
)
634 tc
= afs_TraverseCells(&afs_choose_cell_by_index
, &index
);
636 afs_UpdateCellLRU(tc
);
641 afs_GetPrimaryCell(afs_int32 locktype
)
643 return afs_GetCellByName(afs_thiscell
, locktype
);
647 afs_IsPrimaryCell(struct cell
*cell
)
649 /* Simple safe checking */
652 } else if (!afs_thiscell
) {
653 /* This is simply a safety net to avoid seg faults especially when
654 * using a user-space library. afs_SetPrimaryCell() should be set
655 * prior to this call. */
656 afs_SetPrimaryCell(cell
->cellName
);
659 return strcmp(cell
->cellName
, afs_thiscell
) ? 0 : 1;
664 afs_IsPrimaryCellNum(afs_int32 cellnum
)
669 tc
= afs_GetCellStale(cellnum
, READ_LOCK
);
671 primary
= afs_IsPrimaryCell(tc
);
672 afs_PutCell(tc
, READ_LOCK
);
679 afs_SetPrimaryCell(char *acellName
)
681 ObtainWriteLock(&afs_xcell
, 691);
683 afs_osi_FreeStr(afs_thiscell
);
684 afs_thiscell
= afs_strdup(acellName
);
685 ReleaseWriteLock(&afs_xcell
);
690 afs_NewCell(char *acellName
, afs_int32
* acellHosts
, int aflags
,
691 char *linkedcname
, u_short fsport
, u_short vlport
, int timeout
)
693 struct cell
*tc
, *tcl
= 0;
694 afs_int32 i
, newc
= 0, code
= 0;
696 AFS_STATCNT(afs_NewCell
);
698 ObtainWriteLock(&afs_xcell
, 103);
700 tc
= afs_FindCellByName_nl(acellName
, READ_LOCK
);
704 tc
= (struct cell
*)afs_osi_Alloc(sizeof(struct cell
));
705 memset((char *)tc
, 0, sizeof(*tc
));
706 tc
->cellName
= afs_strdup(acellName
);
707 tc
->fsport
= AFS_FSPORT
;
708 tc
->vlport
= AFS_VLPORT
;
709 RWLOCK_INIT(&tc
->lock
, "cell lock");
713 ObtainWriteLock(&tc
->lock
, 688);
715 /* If the cell we've found has the correct name but no timeout,
716 * and we're called with a non-zero timeout, bail out: never
717 * override static configuration entries with AFSDB ones.
718 * One exception: if the original cell entry had no servers,
719 * it must get servers from AFSDB.
721 if (timeout
&& !tc
->timeout
&& tc
->cellHosts
[0]) {
722 code
= EEXIST
; /* This code is checked for in afs_LookupAFSDB */
726 /* we don't want to keep pinging old vlservers which were down,
727 * since they don't matter any more. It's easier to do this than
728 * to remove the server from its various hash tables. */
729 for (i
= 0; i
< MAXCELLHOSTS
; i
++) {
730 if (!tc
->cellHosts
[i
])
732 tc
->cellHosts
[i
]->flags
&= ~SRVR_ISDOWN
;
733 tc
->cellHosts
[i
]->flags
|= SRVR_ISGONE
;
741 if (aflags
& CLinkedCell
) {
746 tcl
= afs_FindCellByName_nl(linkedcname
, READ_LOCK
);
751 if (tcl
->lcellp
) { /* XXX Overwriting if one existed before! XXX */
752 tcl
->lcellp
->lcellp
= (struct cell
*)0;
753 tcl
->lcellp
->states
&= ~CLinkedCell
;
758 tc
->states
|= aflags
;
759 tc
->timeout
= timeout
;
761 memset((char *)tc
->cellHosts
, 0, sizeof(tc
->cellHosts
));
762 for (i
= 0; i
< MAXCELLHOSTS
; i
++) {
764 afs_uint32 temp
= acellHosts
[i
];
767 ts
= afs_GetServer(&temp
, 1, 0, tc
->vlport
, WRITE_LOCK
, NULL
, 0);
769 ts
->flags
&= ~SRVR_ISGONE
;
770 tc
->cellHosts
[i
] = ts
;
771 afs_PutServer(ts
, WRITE_LOCK
);
773 afs_SortServers(tc
->cellHosts
, MAXCELLHOSTS
); /* randomize servers */
776 struct cell_name
*cn
;
778 cn
= afs_cellname_lookup_name(acellName
);
780 cn
= afs_cellname_new(acellName
, 0);
783 tc
->cellNum
= cn
->cellnum
;
784 tc
->cellIndex
= afs_cellindex
++;
785 afs_stats_cmperf
.numCellsVisible
++;
786 QAdd(&CellLRU
, &tc
->lruq
);
789 ReleaseWriteLock(&tc
->lock
);
790 ReleaseWriteLock(&afs_xcell
);
792 afs_DynrootInvalidate();
797 afs_osi_FreeStr(tc
->cellName
);
798 afs_osi_Free(tc
, sizeof(struct cell
));
800 ReleaseWriteLock(&tc
->lock
);
801 ReleaseWriteLock(&afs_xcell
);
806 * Miscellaneous stuff
808 * afs_CellInit: perform whatever initialization is necessary
809 * shutdown_cell: called on shutdown, should deallocate memory, etc
810 * afs_RemoveCellEntry: remove a server from a cell's server list
811 * afs_CellOrAliasExists: check if the given name exists as a cell or alias
812 * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
813 * afs_CellNumValid: check if a cell number is valid (also set the used flag)
819 RWLOCK_INIT(&afs_xcell
, "afs_xcell");
821 RWLOCK_INIT(&afsdb_client_lock
, "afsdb_client_lock");
822 RWLOCK_INIT(&afsdb_req
.lock
, "afsdb_req.lock");
827 afs_cellalias_index
= 0;
833 struct afs_q
*cq
, *tq
;
836 RWLOCK_INIT(&afs_xcell
, "afs_xcell");
838 for (cq
= CellLRU
.next
; cq
!= &CellLRU
; cq
= tq
) {
842 afs_osi_FreeStr(tc
->cellName
);
843 afs_osi_Free(tc
, sizeof(struct cell
));
848 struct cell_name
*cn
= afs_cellname_head
;
851 struct cell_name
*next
= cn
->next
;
853 afs_osi_FreeStr(cn
->cellname
);
854 afs_osi_Free(cn
, sizeof(struct cell_name
));
861 afs_RemoveCellEntry(struct server
*srvp
)
870 /* Remove the server structure from the cell list - if there */
871 ObtainWriteLock(&tc
->lock
, 200);
872 for (j
= k
= 0; j
< MAXCELLHOSTS
; j
++) {
873 if (!tc
->cellHosts
[j
])
875 if (tc
->cellHosts
[j
] != srvp
) {
876 tc
->cellHosts
[k
++] = tc
->cellHosts
[j
];
880 /* What do we do if we remove the last one? */
882 for (; k
< MAXCELLHOSTS
; k
++) {
883 tc
->cellHosts
[k
] = 0;
885 ReleaseWriteLock(&tc
->lock
);
889 afs_CellOrAliasExists_nl(char *aname
)
892 struct cell_alias
*ca
;
894 c
= afs_FindCellByName_nl(aname
, READ_LOCK
);
896 afs_PutCell(c
, READ_LOCK
);
900 ca
= afs_FindCellAlias(aname
);
902 afs_PutCellAlias(ca
);
910 afs_CellOrAliasExists(char *aname
)
914 ObtainReadLock(&afs_xcell
);
915 ret
= afs_CellOrAliasExists_nl(aname
);
916 ReleaseReadLock(&afs_xcell
);
922 afs_CellNumValid(afs_int32 cellnum
)
924 struct cell_name
*cn
;
926 ObtainReadLock(&afs_xcell
);
927 cn
= afs_cellname_lookup_id(cellnum
);
928 ReleaseReadLock(&afs_xcell
);