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