afsd -dynroot-sparse mode for hushed cells
[openafs.git] / src / afs / afs_cell.c
index d8c01da..89d385d 100644 (file)
  * Implements:
  */
 #include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
 
-RCSID("$Header$");
-
-#include "../afs/stds.h"
-#include "../afs/sysincludes.h"        /* Standard vendor system headers */
-
-#if !defined(UKERNEL)
-#include <net/if.h>
-#include <netinet/in.h>
-
-#ifdef AFS_SGI62_ENV
-#include "../h/hashing.h"
-#endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
-#include <netinet/in_var.h>
-#endif /* ! ASF_HPUX110_ENV */
-#endif /* !defined(UKERNEL) */
-
-#include "../afs/afsincludes.h"        /* Afs-based standard headers */
-#include "../afs/afs_stats.h"   /* afs statistics */
-
-#if    defined(AFS_SUN56_ENV)
-#include <inet/led.h>
-#include <inet/common.h>
-#if     defined(AFS_SUN58_ENV)
-#include <netinet/ip6.h>
-#endif
-#include <inet/ip.h>
-#endif
-
-/* Exported variables */
-afs_rwlock_t afs_xcell;                        /* allocation lock for cells */
-struct afs_q CellLRU;
-afs_int32 afs_cellindex=0;
-afs_uint32 afs_nextCellNum = 0x100;
 
+#include "afs/stds.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* afs statistics */
+#include "afs/afs_osi.h"
+#include "afs/afs_md5.h"
 
 /* Local variables. */
-struct cell *afs_rootcell = 0;
-
-/* Handler waiting for request from client */
-static char afs_AfsdbHandlerWait;
-/* Client waiting for handler to become available or finish request */
-static char afs_AfsdbLookupWait;
-
-/* Set to 1 when we've seen the userspace AFSDB process at least once */
-char afs_AfsdbHandlerPresent = 0;
-/* Set to 1 when there is a client interacting with the AFSDB handler.
- * Protects the in and out variables below.  Protected by GLOCK. */
-char afs_AfsdbHandlerInuse = 0;
-/* Set to 1 when AFSDB has been shut down */
-char afs_AfsdbHandlerShutdown = 0;
-
-/* Input to handler from the client: cell name to look up */
-char *afs_AfsdbHandler_CellName;
-/* Outputs from handler to client: cell hosts, TTL, and real cell name */
-afs_int32 *afs_AfsdbHandler_CellHosts;
-int *afs_AfsdbHandler_Timeout;
-char **afs_AfsdbHandler_RealName;
-
-/* Client sets ReqPending to 1 whenever it queues a request for it */
-char afs_AfsdbHandler_ReqPending = 0;
-/* Handler sets Completed to 1 when it completes the client request */
-char afs_AfsdbHandler_Completed = 0;
-
-
-int afs_strcasecmp(s1, s2)
-    register char *s1, *s2;
-{
-    while (*s1 && *s2) {
-       register char c1, c2;
-
-       c1 = *s1++;
-       c2 = *s2++;
-       if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
-       if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
-       if (c1 != c2)
-           return c1-c2;
-    }
-
-    return *s1 - *s2;
-}
+afs_rwlock_t afs_xcell;                /* Export for cmdebug peeking at locks */
 
+/*
+ * AFSDB implementation:
+ *
+ * afs_StopAFSDB: terminate the AFSDB handler, used on shutdown
+ * afs_AFSDBHandler: entry point for user-space AFSDB request handler
+ * afs_GetCellHostsAFSDB: query the AFSDB handler and wait for response
+ * afs_LookupAFSDB: look up AFSDB for given cell name and create locally
+ */
 
-#ifdef AFS_AFSDB_ENV
-void afs_StopAfsdb()
+afs_rwlock_t afsdb_client_lock;        /* Serializes client requests */
+afs_rwlock_t afsdb_req_lock;   /* Serializes client requests */
+static char afsdb_handler_running;     /* Protected by GLOCK */
+static char afsdb_handler_shutdown;    /* Protected by GLOCK */
+
+/* from cellconfig.h */
+#define MAXCELLCHARS    64
+static struct {
+    /* lock moved to afsdb_req_lock for cmdebug */
+    char pending;
+    char complete;
+    char *cellname;
+} afsdb_req;
+
+/*!
+ * Terminate the AFSDB handler, used on shutdown.
+ */
+void
+afs_StopAFSDB(void)
 {
-    if (afs_AfsdbHandlerPresent) {
-       afs_osi_Wakeup(&afs_AfsdbHandlerWait);
+    if (afsdb_handler_running) {
+       afs_osi_Wakeup(&afsdb_req);
     } else {
-       afs_AfsdbHandlerShutdown = 1;
+       afsdb_handler_shutdown = 1;
        afs_termState = AFSOP_STOP_RXEVENT;
+       afs_osi_Wakeup(&afs_termState);
     }
 }
 
-int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
-    char *acellName;
-    int acellNameLen;
-    afs_int32 *kernelMsg;
+/*!
+ * \brief Entry point for user-space AFSDB request handler.
+ * Reads cell data from kerlenMsg and add new cell, or alias.
+ * \param acellName Cell name. If a cell is found, it's name will be filled in here.
+ * \param acellNameLen Cell name length.
+ * \param kernelMsg Buffer containing data about host count, time out, and cell hosts ids.
+ * \return 0 for success, < 0 for error.
+ */
+int
+afs_AFSDBHandler(char *acellName, int acellNameLen, afs_int32 * kernelMsg)
 {
-    /* afs_syscall_call() has already grabbed the global lock */
+    afs_int32 timeout, code;
+    afs_int32 cellHosts[AFS_MAXCELLHOSTS];
 
-    if (afs_AfsdbHandlerShutdown) return -2;
-    afs_AfsdbHandlerPresent = 1;
+    if (afsdb_handler_shutdown)
+       return -2;
+    afsdb_handler_running = 1;
 
-    if (afs_AfsdbHandler_ReqPending) {
+    ObtainSharedLock(&afsdb_req_lock, 683);
+    if (afsdb_req.pending) {
        int i, hostCount;
 
+       UpgradeSToWLock(&afsdb_req_lock, 684);
        hostCount = kernelMsg[0];
-       *afs_AfsdbHandler_Timeout = kernelMsg[1];
-       if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
+       timeout = kernelMsg[1];
+       if (timeout)
+           timeout += osi_Time();
 
-       *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
-       strcpy(*afs_AfsdbHandler_RealName, acellName);
-
-       for (i=0; i<MAXCELLHOSTS; i++) {
+       for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
            if (i >= hostCount)
-               afs_AfsdbHandler_CellHosts[i] = 0;
+               cellHosts[i] = 0;
            else
-               afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
+               cellHosts[i] = kernelMsg[2 + i];
        }
 
+       if (hostCount)
+           code = afs_NewCell(acellName, cellHosts, CNoSUID, NULL, 0, 0, 
+                              timeout);
+
+       if (!hostCount || (code && code != EEXIST)) 
+           /* null out the cellname if the lookup failed */
+           afsdb_req.cellname = NULL;
+       else
+           /* If we found an alias, create it */
+           if (afs_strcasecmp(afsdb_req.cellname, acellName))
+               afs_NewCellAlias(afsdb_req.cellname, acellName);
+
        /* Request completed, wake up the relevant thread */
-       afs_AfsdbHandler_ReqPending = 0;
-       afs_AfsdbHandler_Completed = 1;
-       afs_osi_Wakeup(&afs_AfsdbLookupWait);
+       afsdb_req.pending = 0;
+       afsdb_req.complete = 1;
+       afs_osi_Wakeup(&afsdb_req);
+       ConvertWToSLock(&afsdb_req_lock);
     }
+    ConvertSToRLock(&afsdb_req_lock);
 
     /* Wait for a request */
-    while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
-       afs_osi_Sleep(&afs_AfsdbHandlerWait);
+    while (afsdb_req.pending == 0 && afs_termState != AFSOP_STOP_AFSDB) {
+       ReleaseReadLock(&afsdb_req_lock);
+       afs_osi_Sleep(&afsdb_req);
+       ObtainReadLock(&afsdb_req_lock);
+    }
 
     /* Check if we're shutting down */
     if (afs_termState == AFSOP_STOP_AFSDB) {
+       ReleaseReadLock(&afsdb_req_lock);
+
        /* Inform anyone waiting for us that we're going away */
-       afs_AfsdbHandlerShutdown = 1;
-       afs_AfsdbHandlerPresent = 0;
-       afs_osi_Wakeup(&afs_AfsdbLookupWait);
+       afsdb_handler_shutdown = 1;
+       afsdb_handler_running = 0;
+       afs_osi_Wakeup(&afsdb_req);
 
        afs_termState = AFSOP_STOP_RXEVENT;
        afs_osi_Wakeup(&afs_termState);
        return -2;
     }
 
-    /* Copy the requested cell name into the request buffer */
-    strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
-
-    /* Return the lookup request to userspace */    
+    /* Return the lookup request to userspace */
+    strncpy(acellName, afsdb_req.cellname, acellNameLen);
+    ReleaseReadLock(&afsdb_req_lock);
     return 0;
 }
-#endif
 
+/*!
+ * \brief Query the AFSDB handler and wait for response.
+ * \param  acellName
+ * \return 0 for success. < 0 is error.
+ */
+static int
+afs_GetCellHostsAFSDB(char *acellName)
+{
+    AFS_ASSERT_GLOCK();
+    if (!afsdb_handler_running)
+       return ENOENT;
+
+    ObtainWriteLock(&afsdb_client_lock, 685);
+    ObtainWriteLock(&afsdb_req_lock, 686);
+
+    afsdb_req.cellname = acellName;
+
+    afsdb_req.complete = 0;
+    afsdb_req.pending = 1;
+    afs_osi_Wakeup(&afsdb_req);
+    ConvertWToRLock(&afsdb_req_lock);
+
+    while (afsdb_handler_running && !afsdb_req.complete) {
+       ReleaseReadLock(&afsdb_req_lock);
+       afs_osi_Sleep(&afsdb_req);
+       ObtainReadLock(&afsdb_req_lock);
+    };
+
+    ReleaseReadLock(&afsdb_req_lock);
+    ReleaseWriteLock(&afsdb_client_lock);
+
+    if (afsdb_req.cellname) {
+       return 0;
+    } else
+       return ENOENT;
+}
+
+
+/*! 
+ * Look up AFSDB for given cell name and create locally.
+ * \param acellName Cell name. 
+ */
+void
+afs_LookupAFSDB(char *acellName)
+{
+    int code;
+    char *cellName = afs_strdup(acellName);
+
+    code = afs_GetCellHostsAFSDB(cellName);
+    afs_Trace2(afs_iclSetp, CM_TRACE_AFSDB, ICL_TYPE_STRING, cellName, 
+               ICL_TYPE_INT32, code);
+    afs_osi_FreeStr(cellName);
+}
 
-int afs_GetCellHostsFromDns(acellName, acellHosts, timeout, realName)
-    char *acellName;
-    afs_int32 *acellHosts;
-    int *timeout;
-    char **realName;
+/*
+ * Cell name-to-ID mapping
+ *
+ * afs_cellname_new: create a new cell name, optional cell number
+ * afs_cellname_lookup_id: look up a cell name
+ * afs_cellname_lookup_name: look up a cell number
+ * afs_cellname_ref: note that this cell name was referenced somewhere
+ * afs_cellname_init: load the list of cells from given inode
+ * afs_cellname_write: write in-kernel list of cells to disk
+ */
+
+struct cell_name *afs_cellname_head;   /* Export for kdump */
+static afs_dcache_id_t afs_cellname_inode;
+static int afs_cellname_inode_set;
+static int afs_cellname_dirty;
+static afs_int32 afs_cellnum_next;
+
+/*!
+ * Create a new cell name, optional cell number.
+ * \param  name Name of cell.
+ * \param cellnum Cellname number.
+ * \return Initialized structure.
+ */
+static struct cell_name *
+afs_cellname_new(char *name, afs_int32 cellnum)
 {
-#ifdef AFS_AFSDB_ENV
-    char grab_glock = 0;
+    struct cell_name *cn;
 
-    if (!afs_AfsdbHandlerPresent) return ENOENT;
+    if (cellnum == 0)
+       cellnum = afs_cellnum_next;
 
-    /* Initialize host list to empty in case the handler is gone */
-    *acellHosts = 0;
+    cn = (struct cell_name *)afs_osi_Alloc(sizeof(*cn));
+    cn->next = afs_cellname_head;
+    cn->cellnum = cellnum;
+    cn->cellname = afs_strdup(name);
+    cn->used = 0;
+    afs_cellname_head = cn;
 
-    if (!ISAFS_GLOCK()) {
-       grab_glock = 1;
-       AFS_GLOCK();
-    }
+    if (cellnum >= afs_cellnum_next)
+       afs_cellnum_next = cellnum + 1;
 
-    /* Wait until the AFSDB handler is available, and grab it */
-    while (afs_AfsdbHandlerInuse)
-       afs_osi_Sleep(&afs_AfsdbLookupWait);
-    afs_AfsdbHandlerInuse = 1;
+    return cn;
+}
 
-    /* Set up parameters for the handler */
-    afs_AfsdbHandler_CellName = acellName;
-    afs_AfsdbHandler_CellHosts = acellHosts;
-    afs_AfsdbHandler_Timeout = timeout;
-    afs_AfsdbHandler_RealName = realName;
+/*!
+ * Look up a cell name by id.
+ * \param cellnum
+ * \return 
+ */
+static struct cell_name *
+afs_cellname_lookup_id(afs_int32 cellnum)
+{
+    struct cell_name *cn;
 
-    /* Wake up the AFSDB handler */
-    afs_AfsdbHandler_Completed = 0;
-    afs_AfsdbHandler_ReqPending = 1;
-    afs_osi_Wakeup(&afs_AfsdbHandlerWait);
+    for (cn = afs_cellname_head; cn; cn = cn->next)
+       if (cn->cellnum == cellnum)
+           return cn;
 
-    /* Wait for the handler to get back to us with the reply */
-    while (afs_AfsdbHandlerPresent && !afs_AfsdbHandler_Completed)
-       afs_osi_Sleep(&afs_AfsdbLookupWait);
+    return NULL;
+}
 
-    /* Release the AFSDB handler and wake up others waiting for it */
-    afs_AfsdbHandlerInuse = 0;
-    afs_osi_Wakeup(&afs_AfsdbLookupWait);
+/*!
+ * Look up a cell name.
+ * \param name Cell name.
+ * \return 
+ */
+static struct cell_name *
+afs_cellname_lookup_name(char *name)
+{
+    struct cell_name *cn;
 
-    if (grab_glock) AFS_GUNLOCK();
+    for (cn = afs_cellname_head; cn; cn = cn->next)
+       if (strcmp(cn->cellname, name) == 0)
+           return cn;
 
-    if (*acellHosts) return 0;
-    return ENOENT;
-#else
-    return ENOENT;
-#endif
+    return NULL;
 }
 
+/*!
+ * Note that this cell name was referenced somewhere.
+ * \param  cn
+ */
+static void
+afs_cellname_ref(struct cell_name *cn)
+{
+    if (!cn->used) {
+       cn->used = 1;
+       afs_cellname_dirty = 1;
+    }
+}
 
-void afs_RefreshCell(ac)
-    register struct cell *ac;
+/*!
+ * \brief Load the list of cells from given inode.
+ * \param inode Source inode.
+ * \param lookupcode 
+ * \return 0 for success. < 0 for error.
+ */
+int
+afs_cellname_init(afs_dcache_id_t *inode, int lookupcode)
 {
-    afs_int32 cellHosts[MAXCELLHOSTS];
-    char *realName = NULL;
-    struct cell *tc;
-    int timeout;
-
-    if (ac->cellHosts[0])      /* If we already have some servers.. */
-       if (!ac->timeout || ac->timeout > osi_Time())
-                               /* Don't refresh if not expired */
-           return;
-
-    if (afs_GetCellHostsFromDns(ac->cellName, cellHosts, &timeout, &realName))
-       /* In case of lookup failure, keep old data */
-       goto done;
-
-    /* Refresh the DB servers for the real cell; other values stay the same. */
-    afs_NewCell(realName, cellHosts, 0, (char *) 0, 0, 0, timeout, (char *) 0);
-
-    /* If this is an alias, update the alias entry too */
-    if (afs_strcasecmp(ac->cellName, realName)) {
-       /*
-        * Look up the entry we just updated, to compensate for
-        * uppercase-vs-lowercase lossage with DNS.
-        */
-       tc = afs_FindCellByName(realName, READ_LOCK);
-
-       if (tc) {
-           afs_NewCell(ac->cellName, 0, CAlias, (char *) 0, 0, 0,
-                       timeout, tc->cellName);
-           afs_PutCell(tc, READ_LOCK);
+    struct osi_file *tfile;
+    int cc, off = 0;
+
+    ObtainWriteLock(&afs_xcell, 692);
+
+    afs_cellnum_next = 1;
+    afs_cellname_dirty = 0;
+
+    if (cacheDiskType == AFS_FCACHE_TYPE_MEM) {
+       ReleaseWriteLock(&afs_xcell);
+       return 0;
+    }
+    if (lookupcode) {
+       ReleaseWriteLock(&afs_xcell);
+       return lookupcode;
+    }
+
+    tfile = osi_UFSOpen(inode);
+    if (!tfile) {
+       ReleaseWriteLock(&afs_xcell);
+       return EIO;
+    }
+
+    afs_copy_inode(&afs_cellname_inode, inode);
+    afs_cellname_inode_set = 1;
+
+    while (1) {
+       afs_int32 cellnum, clen, magic;
+       struct cell_name *cn;
+       char *cellname;
+
+       cc = afs_osi_Read(tfile, off, &magic, sizeof(magic));
+       if (cc != sizeof(magic))
+           break;
+       if (magic != AFS_CELLINFO_MAGIC)
+           break;
+       off += cc;
+
+       cc = afs_osi_Read(tfile, off, &cellnum, sizeof(cellnum));
+       if (cc != sizeof(cellnum))
+           break;
+       off += cc;
+
+       cc = afs_osi_Read(tfile, off, &clen, sizeof(clen));
+       if (cc != sizeof(clen))
+           break;
+       off += cc;
+
+       cellname = afs_osi_Alloc(clen + 1);
+       if (!cellname)
+           break;
+
+       cc = afs_osi_Read(tfile, off, cellname, clen);
+       if (cc != clen) {
+           afs_osi_Free(cellname, clen + 1);
+           break;
+       }
+       off += cc;
+       cellname[clen] = '\0';
+
+       if (afs_cellname_lookup_name(cellname)
+           || afs_cellname_lookup_id(cellnum)) {
+           afs_osi_Free(cellname, clen + 1);
+           break;
        }
+
+       cn = afs_cellname_new(cellname, cellnum);
+       afs_osi_Free(cellname, clen + 1);
+    }
+
+    osi_UFSClose(tfile);
+    ReleaseWriteLock(&afs_xcell);
+    return 0;
+}
+
+/*!
+ * Write in-kernel list of cells to disk.
+ */
+int
+afs_cellname_write(void)
+{
+    struct osi_file *tfile;
+    struct cell_name *cn;
+    int off;
+
+    if (!afs_cellname_dirty || !afs_cellname_inode_set)
+       return 0;
+    if (afs_initState != 300)
+       return 0;
+
+    ObtainWriteLock(&afs_xcell, 693);
+    afs_cellname_dirty = 0;
+    off = 0;
+    tfile = osi_UFSOpen(&afs_cellname_inode);
+    if (!tfile) {
+       ReleaseWriteLock(&afs_xcell);
+       return EIO;
+    }
+
+    for (cn = afs_cellname_head; cn; cn = cn->next) {
+       afs_int32 magic, cellnum, clen;
+       int cc;
+
+       if (!cn->used)
+           continue;
+
+       magic = AFS_CELLINFO_MAGIC;
+       cc = afs_osi_Write(tfile, off, &magic, sizeof(magic));
+       if (cc != sizeof(magic))
+           break;
+       off += cc;
+
+       cellnum = cn->cellnum;
+       cc = afs_osi_Write(tfile, off, &cellnum, sizeof(cellnum));
+       if (cc != sizeof(cellnum))
+           break;
+       off += cc;
+
+       clen = strlen(cn->cellname);
+       cc = afs_osi_Write(tfile, off, &clen, sizeof(clen));
+       if (cc != sizeof(clen))
+           break;
+       off += cc;
+
+       cc = afs_osi_Write(tfile, off, cn->cellname, clen);
+       if (cc != clen)
+           break;
+       off += clen;
     }
 
-done:
-    if (realName)
-       afs_osi_Free(realName, strlen(realName) + 1);
+    osi_UFSClose(tfile);
+    ReleaseWriteLock(&afs_xcell);
+    return 0;
 }
 
+/*
+ * Cell alias implementation
+ *
+ * afs_FindCellAlias: look up cell alias by alias name
+ * afs_GetCellAlias: get cell alias by index (starting at 0)
+ * afs_PutCellAlias: put back a cell alias returned by Find or Get
+ * afs_NewCellAlias: create new cell alias entry
+ */
+
+struct cell_alias *afs_cellalias_head; /* Export for kdump */
+static afs_int32 afs_cellalias_index;
+static int afs_CellOrAliasExists_nl(char *aname);      /* Forward declaration */
 
-struct cell *afs_GetCellByName_Dns(acellName, locktype)
-    register char *acellName;
-    afs_int32 locktype;
+/*!
+ * Look up cell alias by alias name.
+ * \param  alias 
+ * \return Found struct or NULL.
+ */
+static struct cell_alias *
+afs_FindCellAlias(char *alias)
 {
-    afs_int32 cellHosts[MAXCELLHOSTS];
-    char *realName = NULL;
-    struct cell *tc;
-    int timeout;
+    struct cell_alias *tc;
 
-    if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
-       goto bad;
-    if (afs_NewCell(realName, cellHosts, CNoSUID, (char *) 0, 0, 0,
-                   timeout, (char *) 0))
-       goto bad;
+    for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
+       if (!strcmp(alias, tc->alias))
+           break;
+    return tc;
+}
 
-    /* If this is an alias, create an entry for it too */
-    if (afs_strcasecmp(acellName, realName)) {
-       /*
-        * Look up the entry we just updated, to compensate for
-        * uppercase-vs-lowercase lossage with DNS.
-        */
-       tc = afs_FindCellByName(realName, READ_LOCK);
-       if (!tc)
-           goto bad;
+/*!
+ * Get cell alias by index (starting at 0).
+ * \param index Cell index. 
+ * \return Found struct or null.
+ */
+struct cell_alias *
+afs_GetCellAlias(int index)
+{
+    struct cell_alias *tc;
 
-       if (afs_NewCell(acellName, 0, CAlias, (char *) 0, 0, 0,
-                       timeout, tc->cellName)) {
-           afs_PutCell(tc, READ_LOCK);
-           goto bad;
-       }
+    ObtainReadLock(&afs_xcell);
+    for (tc = afs_cellalias_head; tc != NULL; tc = tc->next)
+       if (tc->index == index)
+           break;
+    ReleaseReadLock(&afs_xcell);
 
-       afs_PutCell(tc, READ_LOCK);
+    return tc;
+}
+
+
+ /*!
+  * Put back a cell alias returned by Find or Get.
+  * \param a Alias. 
+  * \return 
+  */
+void
+afs_PutCellAlias(struct cell_alias *a)
+{
+    return;
+}
+
+/*!
+ * Create new cell alias entry and update dynroot vnode.
+ * \param alias
+ * \param cell
+ * \return 
+ */
+afs_int32
+afs_NewCellAlias(char *alias, char *cell)
+{
+    struct cell_alias *tc;
+
+    ObtainSharedLock(&afs_xcell, 681);
+    if (afs_CellOrAliasExists_nl(alias)) {
+       ReleaseSharedLock(&afs_xcell);
+       return EEXIST;
     }
 
-    if (realName)
-       afs_osi_Free(realName, strlen(realName) + 1);
-    return afs_FindCellByName(acellName, locktype);
+    UpgradeSToWLock(&afs_xcell, 682);
+    tc = (struct cell_alias *)afs_osi_Alloc(sizeof(struct cell_alias));
+    tc->alias = afs_strdup(alias);
+    tc->cell = afs_strdup(cell);
+    tc->next = afs_cellalias_head;
+    tc->index = afs_cellalias_index++;
+    afs_cellalias_head = tc;
+    ReleaseWriteLock(&afs_xcell);
+
+    afs_DynrootInvalidate();
+    return 0;
+}
+
+/*
+ * Actual cell list implementation
+ *
+ * afs_UpdateCellLRU: bump given cell up to the front of the LRU queue
+ * afs_RefreshCell: look up cell information in AFSDB if timeout expired
+ *
+ * afs_TraverseCells: execute a callback for each existing cell
+ * afs_TraverseCells_nl: same as above except without locking afs_xcell
+ * afs_choose_cell_by_{name,num,index}: useful traversal callbacks
+ *
+ * afs_FindCellByName: return a cell with a given name, if it exists
+ * afs_FindCellByName_nl: same as above, without locking afs_xcell
+ * afs_GetCellByName: same as FindCellByName but tries AFSDB if not found
+ * afs_GetCell: return a cell with a given cell number
+ * afs_GetCellStale: same as GetCell, but does not try to refresh the data
+ * afs_GetCellByIndex: return a cell with a given index number (starting at 0)
+ *
+ * afs_GetPrimaryCell: return the primary cell, if any
+ * afs_IsPrimaryCell: returns true iff the given cell is the primary cell
+ * afs_IsPrimaryCellNum: returns afs_IsPrimaryCell(afs_GetCell(cellnum))
+ * afs_SetPrimaryCell: set the primary cell name to the given cell name
+ *
+ * afs_NewCell: create or update a cell entry
+ */
+
+struct afs_q CellLRU;          /* Export for kdump */
+static char *afs_thiscell = NULL;
+afs_int32 afs_cellindex;       /* Export for kdump */
 
-bad:
-    if (realName)
-       afs_osi_Free(realName, strlen(realName) + 1);
-    return (struct cell *) 0;
+/*!
+ * Bump given cell up to the front of the LRU queue.
+ * \param c Cell to set. 
+ */
+static void
+afs_UpdateCellLRU(struct cell *c)
+{
+    ObtainWriteLock(&afs_xcell, 100);
+    QRemove(&c->lruq);
+    QAdd(&CellLRU, &c->lruq);
+    ReleaseWriteLock(&afs_xcell);
 }
 
+/*!
+ * Look up cell information in AFSDB if timeout expired
+ * \param ac Cell to be refreshed.
+ * \return 
+ */
+static void
+afs_RefreshCell(struct cell *ac)
+{
+    if (ac->states & CNoAFSDB)
+       return;
+    if (!ac->cellHosts[0] || (ac->timeout && ac->timeout <= osi_Time()))
+       afs_LookupAFSDB(ac->cellName);
+}
 
-struct cell *afs_FindCellByName(acellName, locktype)
-    register char *acellName;
-    afs_int32 locktype;
+/*! 
+ * Execute a callback for each existing cell, without a lock on afs_xcell.
+ * Iterate on CellLRU, and execute a callback for each cell until given arguments are met.
+ * \see afs_TraverseCells
+ * \param cb Traversal callback for each cell.
+ * \param arg Callback arguments.
+ * \return Found data or NULL.
+ */
+static void *
+afs_TraverseCells_nl(void *(*cb) (struct cell *, void *), void *arg)
 {
-    register struct cell *tc;
-    register struct afs_q *cq, *tq;
-    int didAlias = 0;
+    struct afs_q *cq, *tq;
+    struct cell *tc;
+    void *ret = NULL;
 
-    AFS_STATCNT(afs_GetCellByName);
-retry:
-    ObtainWriteLock(&afs_xcell,100);
     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-       tc = QTOC(cq); tq = QNext(cq);
-       if (!afs_strcasecmp(tc->cellName, acellName)) {
-           QRemove(&tc->lruq);
-           QAdd(&CellLRU, &tc->lruq);
-           ReleaseWriteLock(&afs_xcell);
-           afs_RefreshCell(tc);
-           if ((tc->states & CAlias) && (didAlias == 0)) {
-               acellName = tc->realName;
-               if (!acellName) return (struct cell *) 0;
-               didAlias = 1;
-               goto retry;
-           }
-           return tc;
+       tc = QTOC(cq);
+
+       /* This is assuming that a NULL return is acceptable. */
+       if (cq) {
+           tq = QNext(cq);
+       } else {
+           return NULL;
        }
+
+       ret = cb(tc, arg);
+       if (ret)
+           break;
     }
 
-    ReleaseWriteLock(&afs_xcell);
-    return (struct cell *) 0;
-} /*afs_FindCellByName*/
+    return ret;
+}
+
+/*!
+ * Execute a callback for each existing cell, with a lock on afs_xcell.
+ * \see afs_TraverseCells_nl
+ * \param cb Traversal callback for each cell.
+ * \param arg 
+ * \return Found data or NULL.
+ */
+void *
+afs_TraverseCells(void *(*cb) (struct cell *, void *), void *arg)
+{
+    void *ret;
+
+    ObtainReadLock(&afs_xcell);
+    ret = afs_TraverseCells_nl(cb, arg);
+    ReleaseReadLock(&afs_xcell);
+
+    return ret;
+}
 
+/*!
+ * Useful traversal callback: Match by name.
+ * \param cell 
+ * \param arg Cell name (compared with cell->cellName).
+ * \return Returns found cell or NULL.
+ */
+static void *
+afs_choose_cell_by_name(struct cell *cell, void *arg)
+{
+    if (!arg) {
+       /* Safety net */
+       return cell;
+    } else {
+       return strcmp(cell->cellName, (char *)arg) ? NULL : cell;
+    }
+}
+
+/*!
+ * Useful traversal callback: Match by handle.
+ * \param cell 
+ * \param arg Cell handle (compared with cell->cellHandle).
+ * \return Returns found cell or NULL.
+ */
+static void *
+afs_choose_cell_by_handle(struct cell *cell, void *arg)
+{
+    if (!arg) {
+       /* Safety net */
+       return cell;
+    } else {
+       return memcmp(cell->cellHandle, (char *)arg, 16) ? NULL : cell;
+    }
+}
+
+/*!
+ * Useful traversal callback: Match by cell number.
+ * \param cell 
+ * \param arg Cell number (compared with cell->cellNum).
+ * \return Returns found cell or NULL.
+ */
+static void *
+afs_choose_cell_by_num(struct cell *cell, void *arg)
+{
+    return (cell->cellNum == *((afs_int32 *) arg)) ? cell : NULL;
+}
+
+/*!
+ * Useful traversal callback: Match by index.
+ * \param cell 
+ * \param arg Cell index (compared with cell->cellIndex).
+ * \return Returns found cell or NULL.
+ */
+static void *
+afs_choose_cell_by_index(struct cell *cell, void *arg)
+{
+    return (cell->cellIndex == *((afs_int32 *) arg)) ? cell : NULL;
+}
+
+/*!
+ * Return a cell with a given name, if it exists. No lock version.
+ * Does not check AFSDB.
+ * \param acellName Cell name.
+ * \param locktype Type of lock to be used (not used).
+ * \return 
+ */
+static struct cell *
+afs_FindCellByName_nl(char *acellName, afs_int32 locktype)
+{
+    return afs_TraverseCells_nl(&afs_choose_cell_by_name, acellName);
+}
 
-struct cell *afs_GetCellByName(acellName, locktype)
-    register char *acellName;
-    afs_int32 locktype;
+/*!
+ * Return a cell with a given name, if it exists.It uses locks.
+ * Does not check AFSDB.
+ * \param acellName Cell name.
+ * \param locktype Type of lock to be used.
+ * \return 
+ */
+static struct cell *
+afs_FindCellByName(char *acellName, afs_int32 locktype)
+{
+    return afs_TraverseCells(&afs_choose_cell_by_name, acellName);
+}
+
+/*!
+ * Same as FindCellByName but tries AFSDB if not found.
+ * \param acellName Cell name.
+ * \param locktype Type of lock to be used.
+ * \return 
+ */
+struct cell *
+afs_GetCellByName(char *acellName, afs_int32 locktype)
 {
     struct cell *tc;
 
     tc = afs_FindCellByName(acellName, locktype);
-    if (!tc)
-       tc = afs_GetCellByName_Dns(acellName, locktype);
+    if (!tc) {
+       afs_LookupAFSDB(acellName);
+       tc = afs_FindCellByName(acellName, locktype);
+    }
+    if (tc) {
+       afs_cellname_ref(tc->cnamep);
+       afs_UpdateCellLRU(tc);
+       afs_RefreshCell(tc);
+    }
 
     return tc;
-} /*afs_GetCellByName*/
+}
 
-static struct cell *afs_GetCellInternal(acell, locktype, holdxcell)
-    register afs_int32 acell;
-    afs_int32 locktype;
-    int holdxcell;
+/*!
+ * Return a cell with a given cell number.
+ * \param cellnum Cell number.
+ * \param locktype Lock to be used. 
+ * \return 
+ */
+struct cell *
+afs_GetCell(afs_int32 cellnum, afs_int32 locktype)
 {
-    register struct cell *tc;
-    register struct afs_q *cq, *tq;
+    struct cell *tc;
+    struct cell_name *cn;
 
-    AFS_STATCNT(afs_GetCell);
-    if (acell == 1 && afs_rootcell) return afs_rootcell;
-    if (holdxcell)
-       ObtainWriteLock(&afs_xcell,101);
-    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-       tc = QTOC(cq); tq = QNext(cq);
-       if (tc->cell == acell) {
-           QRemove(&tc->lruq);
-           QAdd(&CellLRU, &tc->lruq);
-           if (holdxcell)
-               ReleaseWriteLock(&afs_xcell);
-           afs_RefreshCell(tc);
-           return tc;
-       }
+    tc = afs_GetCellStale(cellnum, locktype);
+    if (tc) {
+       afs_RefreshCell(tc);
+    } else {
+       ObtainReadLock(&afs_xcell);
+       cn = afs_cellname_lookup_id(cellnum);
+       ReleaseReadLock(&afs_xcell);
+       if (cn)
+           tc = afs_GetCellByName(cn->cellname, locktype);
     }
-    if (holdxcell)
-       ReleaseWriteLock(&afs_xcell);
-    return (struct cell *) 0;
+    return tc;
+}
+
+/*!
+ * Same as GetCell, but does not try to refresh the data.
+ * \param cellnum Cell number.
+ * \param locktype What lock should be used.
+ * \return 
+ */
+struct cell *
+afs_GetCellStale(afs_int32 cellnum, afs_int32 locktype)
+{
+    struct cell *tc;
 
-} /*afs_GetCell*/
+    tc = afs_TraverseCells(&afs_choose_cell_by_num, &cellnum);
+    if (tc) {
+       afs_cellname_ref(tc->cnamep);
+       afs_UpdateCellLRU(tc);
+    }
+    return tc;
+}
 
-struct cell *afs_GetCell(acell, locktype)
-    register afs_int32 acell;
-    afs_int32 locktype;
+/*!
+ * Return a cell with a given index number (starting at 0). Update CellLRU as well.
+ * \param index
+ * \param locktype Type of lock used.
+ * \return 
+ */
+struct cell *
+afs_GetCellByIndex(afs_int32 index, afs_int32 locktype)
 {
-    return afs_GetCellInternal(acell, locktype, 1);
+    struct cell *tc;
+
+    tc = afs_TraverseCells(&afs_choose_cell_by_index, &index);
+    if (tc)
+       afs_UpdateCellLRU(tc);
+    return tc;
 }
 
-/* This is only to be called if the caller is already holding afs_xcell */
-struct cell *afs_GetCellNoLock(acell, locktype)
-    register afs_int32 acell;
-    afs_int32 locktype;
+/*!
+ * Return a cell with a given handle..
+ * \param index
+ * \param locktype Type of lock used.
+ * \return 
+ */
+struct cell *
+afs_GetCellByHandle(void *handle, afs_int32 locktype)
 {
-    return afs_GetCellInternal(acell, locktype, 0);
+    struct cell *tc;
+
+    tc = afs_TraverseCells(&afs_choose_cell_by_handle, handle);
+    if (tc)
+       afs_UpdateCellLRU(tc);
+    return tc;
 }
 
-struct cell *afs_GetCellByIndex(cellindex, locktype, refresh)
-    register afs_int32 cellindex;
-    afs_int32 locktype;
-    afs_int32 refresh;
+/*!
+ * Return primary cell, if any.
+ * \param locktype Type of lock used.
+ * \return 
+ */
+struct cell *
+afs_GetPrimaryCell(afs_int32 locktype)
 {
-    register struct cell *tc;
-    register struct afs_q *cq, *tq;
+    return afs_GetCellByName(afs_thiscell, locktype);
+}
 
-    AFS_STATCNT(afs_GetCellByIndex);
-    ObtainWriteLock(&afs_xcell,102);
-    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-       tc = QTOC(cq); tq = QNext(cq);
-       if (tc->cellIndex == cellindex) {
-           QRemove(&tc->lruq);
-           QAdd(&CellLRU, &tc->lruq);
-           ReleaseWriteLock(&afs_xcell);
-           if (refresh) afs_RefreshCell(tc);
-           return tc;
-       }
+/*!
+ * Returns true if the given cell is the primary cell.
+ * \param cell
+ * \return 
+ */
+int
+afs_IsPrimaryCell(struct cell *cell)
+{
+    /* Simple safe checking */
+    if (!cell) {
+       return 0;
+    } else if (!afs_thiscell) {
+       /* This is simply a safety net to avoid seg faults especially when
+        * using a user-space library.  afs_SetPrimaryCell() should be set
+        * prior to this call. */
+       afs_SetPrimaryCell(cell->cellName);
+       return 1;
+    } else {
+       return strcmp(cell->cellName, afs_thiscell) ? 0 : 1;
     }
-    ReleaseWriteLock(&afs_xcell);
-    return (struct cell *) 0;
+}
 
-} /*afs_GetCellByIndex*/
+/*!
+ * Returns afs_IsPrimaryCell(afs_GetCell(cellnum)).
+ * \param cellnum 
+ * \return 
+ */
+int
+afs_IsPrimaryCellNum(afs_int32 cellnum)
+{
+    struct cell *tc;
+    int primary = 0;
 
+    tc = afs_GetCellStale(cellnum, READ_LOCK);
+    if (tc) {
+       primary = afs_IsPrimaryCell(tc);
+       afs_PutCell(tc, READ_LOCK);
+    }
 
-afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout, aliasFor)
-    int aflags;
-    char *acellName;
-    register afs_int32 *acellHosts;
-    char *linkedcname;
-    u_short fsport, vlport;
-    int timeout;
-    char *aliasFor;
+    return primary;
+}
+
+/*!
+ * Set the primary cell name to the given cell name.
+ * \param acellName Cell name. 
+ * \return 0 for success, < 0 for error.
+ */
+afs_int32
+afs_SetPrimaryCell(char *acellName)
 {
-    register struct cell *tc, *tcl=0;
-    register afs_int32 i, newc=0, code=0;
-    register struct afs_q *cq, *tq;
+    ObtainWriteLock(&afs_xcell, 691);
+    if (afs_thiscell)
+       afs_osi_FreeStr(afs_thiscell);
+    afs_thiscell = afs_strdup(acellName);
+    ReleaseWriteLock(&afs_xcell);
+    return 0;
+}
 
-    AFS_STATCNT(afs_NewCell);
+/*!
+ * Create or update a cell entry. 
+ * \param acellName Name of cell.
+ * \param acellHosts Array of hosts that this cell has.
+ * \param aflags Cell flags.
+ * \param linkedcname 
+ * \param fsport File server port.
+ * \param vlport Volume server port.
+ * \param timeout Cell timeout value, 0 means static AFSDB entry.
+ * \return 
+ */
+afs_int32
+afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags,
+           char *linkedcname, u_short fsport, u_short vlport, int timeout)
+{
+    struct cell *tc, *tcl = 0;
+    afs_int32 i, newc = 0, code = 0;
 
-    ObtainWriteLock(&afs_xcell,103);
+    AFS_STATCNT(afs_NewCell);
 
-    /* Find the cell and mark its servers as not down but gone */
-    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-       tc = QTOC(cq); tq = QNext(cq);
-       if (afs_strcasecmp(tc->cellName, acellName) == 0) {
-           /* If the cell we've found has the correct name but no timeout,
-            * and we're called with a non-zero timeout, bail out:  never
-            * override static configuration entries with AFSDB ones.
-            * One exception: if the original cell entry had no servers,
-            * it must get servers from AFSDB.
-            */
-           if (timeout && !tc->timeout && tc->cellHosts[0]) {
-               ReleaseWriteLock(&afs_xcell);
-               return 0;
-           }
-           /* we don't want to keep pinging old vlservers which were down,
-            * since they don't matter any more.  It's easier to do this than
-            * to remove the server from its various hash tables. */
-           for (i=0; i<MAXCELLHOSTS; i++) {
-               if (!tc->cellHosts[i]) break;
-               tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
-               tc->cellHosts[i]->flags |= SRVR_ISGONE;
-           }
-           break;
-       }
-    }
+    ObtainWriteLock(&afs_xcell, 103);
 
-    if (cq != &CellLRU) {
+    tc = afs_FindCellByName_nl(acellName, READ_LOCK);
+    if (tc) {
        aflags &= ~CNoSUID;
+    } else {
+       tc = (struct cell *)afs_osi_Alloc(sizeof(struct cell));
+       memset(tc, 0, sizeof(*tc));
+       tc->cellName = afs_strdup(acellName);
+       tc->fsport = AFS_FSPORT;
+       tc->vlport = AFS_VLPORT;
+       AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName));
+       AFS_RWLOCK_INIT(&tc->lock, "cell lock");
+       newc = 1;
+       aflags |= CNoSUID;
     }
-    else {
-       tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
-       memset((char *)tc, 0, sizeof(*tc));
-       QAdd(&CellLRU, &tc->lruq);                      /* put in lruq */
-       tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
-       strcpy(tc->cellName, acellName);
-       tc->cellIndex = afs_cellindex++;
-       if (aflags & CPrimary) {
-           extern int afs_rootCellIndex;
-           tc->cell = 1;       /* primary cell is always 1 */
-           afs_rootcell = tc;
-           afs_rootCellIndex = tc->cellIndex;
-       } else {
-           tc->cell = afs_nextCellNum++;
-       }
-       tc->states = 0;
-       tc->lcellp = (struct cell *)0;
-       tc->fsport = (fsport ? fsport : AFS_FSPORT);
-       tc->vlport = (vlport ? vlport : AFS_VLPORT);
-       afs_stats_cmperf.numCellsVisible++;
-       newc++;
+    ObtainWriteLock(&tc->lock, 688);
+
+    /* If the cell we've found has the correct name but no timeout,
+     * and we're called with a non-zero timeout, bail out:  never
+     * override static configuration entries with AFSDB ones.
+     * One exception: if the original cell entry had no servers,
+     * it must get servers from AFSDB.
+     */
+    if (timeout && !tc->timeout && tc->cellHosts[0]) {
+       code = EEXIST;          /* This code is checked for in afs_LookupAFSDB */
+       goto bad;
     }
 
+    /* we don't want to keep pinging old vlservers which were down,
+     * since they don't matter any more.  It's easier to do this than
+     * to remove the server from its various hash tables. */
+    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
+       if (!tc->cellHosts[i])
+           break;
+       tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
+       tc->cellHosts[i]->flags |= SRVR_ISGONE;
+    }
+
+    if (fsport)
+       tc->fsport = fsport;
+    if (vlport)
+       tc->vlport = vlport;
+
     if (aflags & CLinkedCell) {
        if (!linkedcname) {
            code = EINVAL;
            goto bad;
        }
-       for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
-           tcl = QTOC(cq); tq = QNext(cq);
-           if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
-               break;
-           }
-           tcl = 0;
-       }
+       tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK);
        if (!tcl) {
            code = ENOENT;
            goto bad;
@@ -514,69 +970,219 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
     }
     tc->states |= aflags;
     tc->timeout = timeout;
-
-    /* Allow converting an alias into a real cell */
-    if (!(aflags & CAlias)) tc->states &= ~CAlias;
-    memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
-    if (aflags & CAlias) {
-       if (!aliasFor) {
-           code = EINVAL;
-           goto bad;
-       }
-       if (tc->realName) afs_osi_Free(tc->realName, strlen(tc->realName)+1);
-       tc->realName = (char *) afs_osi_Alloc(strlen(aliasFor)+1);
-       strcpy(tc->realName, aliasFor);
-       goto done;
-    }
-
-    for (i=0; i<MAXCELLHOSTS; i++) {
-        struct server *ts;
+    
+    memset(tc->cellHosts, 0, sizeof(tc->cellHosts));
+    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
+       /* Get server for each host and link this cell in.*/    
+       struct server *ts;
        afs_uint32 temp = acellHosts[i];
-       if (!temp) break;
-       ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
-        ts->cell = tc;
+       if (!temp)
+           break;
+       ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0);
+       ts->cell = tc;
        ts->flags &= ~SRVR_ISGONE;
+       /* Set the server as a host of the new cell. */
        tc->cellHosts[i] = ts;
        afs_PutServer(ts, WRITE_LOCK);
     }
-    afs_SortServers(tc->cellHosts, MAXCELLHOSTS);      /* randomize servers */
-done:
+    afs_SortServers(tc->cellHosts, AFS_MAXCELLHOSTS);  /* randomize servers */
+       
+    /* New cell: Build and add to LRU cell queue. */
+    if (newc) {
+       struct cell_name *cn;
+
+       cn = afs_cellname_lookup_name(acellName);
+       if (!cn)
+           cn = afs_cellname_new(acellName, 0);
+
+       tc->cnamep = cn;
+       tc->cellNum = cn->cellnum;
+       tc->cellIndex = afs_cellindex++;
+       afs_stats_cmperf.numCellsVisible++;
+       QAdd(&CellLRU, &tc->lruq);
+    }
+
+    ReleaseWriteLock(&tc->lock);
     ReleaseWriteLock(&afs_xcell);
+    afs_PutCell(tc, 0);
+    if (!aflags & CHush)
+       afs_DynrootInvalidate();
     return 0;
-bad:
+
+  bad:
     if (newc) {
-       QRemove(&tc->lruq);
-       afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
-       afs_osi_Free((char *)tc, sizeof(struct cell));
+       afs_osi_FreeStr(tc->cellName);
+       afs_osi_Free(tc, sizeof(struct cell));
     }
+    ReleaseWriteLock(&tc->lock);
     ReleaseWriteLock(&afs_xcell);
     return code;
+}
+
+/*
+ * Miscellaneous stuff
+ *
+ * afs_CellInit: perform whatever initialization is necessary
+ * shutdown_cell: called on shutdown, should deallocate memory, etc
+ * afs_RemoveCellEntry: remove a server from a cell's server list
+ * afs_CellOrAliasExists: check if the given name exists as a cell or alias
+ * afs_CellOrAliasExists_nl: same as above without locking afs_xcell
+ * afs_CellNumValid: check if a cell number is valid (also set the used flag)
+ */
+
+/*!
+ * Perform whatever initialization is necessary.
+ */
+void
+afs_CellInit(void)
+{
+    static char CellInit_done = 0;
+
+    if (CellInit_done)
+       return;
+
+    CellInit_done = 1;
+
+    AFS_RWLOCK_INIT(&afs_xcell, "afs_xcell");
+    AFS_RWLOCK_INIT(&afsdb_client_lock, "afsdb_client_lock");
+    AFS_RWLOCK_INIT(&afsdb_req_lock, "afsdb_req_lock");
+    QInit(&CellLRU);
+
+    afs_cellindex = 0;
+    afs_cellalias_index = 0;
+}
+
+/*!
+ * Called on shutdown, should deallocate memory, etc.
+ */
+void
+shutdown_cell(void)
+{
+    struct afs_q *cq, *tq;
+    struct cell *tc;
+
+#ifdef AFS_CACHE_VNODE_PATH
+    if (cacheDiskType != AFS_FCACHE_TYPE_MEM) {
+       afs_osi_FreeStr(afs_cellname_inode.ufs);
+    }
+#endif
+    AFS_RWLOCK_INIT(&afs_xcell, "afs_xcell");
+
+    for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
+       tc = QTOC(cq);
+       tq = QNext(cq);
+       if (tc->cellName)
+           afs_osi_FreeStr(tc->cellName);
+       afs_osi_Free(tc, sizeof(struct cell));
+    }
+    QInit(&CellLRU);
 
-} /*afs_NewCell*/
+{
+    struct cell_name *cn = afs_cellname_head;
+
+    while (cn) {
+       struct cell_name *next = cn->next;
+
+       afs_osi_FreeStr(cn->cellname);
+       afs_osi_Free(cn, sizeof(struct cell_name));
+       cn = next;
+    }
+}
+}
 
+/*!
+ * Remove a server from a cell's server list.
+ * \param srvp Server to be removed.
+ * \return 
+ */
+void
 afs_RemoveCellEntry(struct server *srvp)
 {
-  struct cell *tc;
-  afs_int32 j, k;
-
-  tc = srvp->cell;
-  if (!tc) return;
-
-  /* Remove the server structure from the cell list - if there */
-  ObtainWriteLock(&afs_xcell,200);
-  for (j=k=0; j<MAXCELLHOSTS; j++) {
-     if (!tc->cellHosts[j]) break;
-     if (tc->cellHosts[j] != srvp) {
-        tc->cellHosts[k++] = tc->cellHosts[j];
-     }
-  }
-  if (k == 0) {
-     /* What do we do if we remove the last one? */
-  }
-  for (; k<MAXCELLHOSTS; k++) {
-     tc->cellHosts[k] = 0;
-  }
-  ReleaseWriteLock(&afs_xcell);
+    struct cell *tc;
+    afs_int32 j, k;
+
+    tc = srvp->cell;
+    if (!tc)
+       return;
+
+    /* Remove the server structure from the cell list - if there */
+    ObtainWriteLock(&tc->lock, 200);
+    for (j = k = 0; j < AFS_MAXCELLHOSTS; j++) {
+       if (!tc->cellHosts[j])
+           break;
+       if (tc->cellHosts[j] != srvp) {
+           tc->cellHosts[k++] = tc->cellHosts[j];
+       }
+    }
+    if (k == 0) {
+       /* What do we do if we remove the last one? */
+    }
+    for (; k < AFS_MAXCELLHOSTS; k++) {
+       tc->cellHosts[k] = 0;
+    }
+    ReleaseWriteLock(&tc->lock);
+}
+
+/*!
+ * Check if the given name exists as a cell or alias. Does not lock afs_xcell.
+ * \param aname 
+ * \return 
+ */
+static int
+afs_CellOrAliasExists_nl(char *aname)
+{
+    struct cell *c;
+    struct cell_alias *ca;
+
+    c = afs_FindCellByName_nl(aname, READ_LOCK);
+    if (c) {
+       afs_PutCell(c, READ_LOCK);
+       return 1;
+    }
+
+    ca = afs_FindCellAlias(aname);
+    if (ca) {
+       afs_PutCellAlias(ca);
+       return 1;
+    }
+
+    return 0;
 }
 
+/*!
+ * Check if the given name exists as a cell or alias. Locks afs_xcell.
+ * \param aname
+ * \return 
+ */
+int
+afs_CellOrAliasExists(char *aname)
+{
+    int ret;
+
+    ObtainReadLock(&afs_xcell);
+    ret = afs_CellOrAliasExists_nl(aname);
+    ReleaseReadLock(&afs_xcell);
+
+    return ret;
+}
+
+/*!
+ * Check if a cell number is valid (also set the used flag).
+ * \param cellnum 
+ * \return 1 - true, 0 - false
+ */
+int
+afs_CellNumValid(afs_int32 cellnum)
+{
+    struct cell_name *cn;
+
+    ObtainReadLock(&afs_xcell);
+    cn = afs_cellname_lookup_id(cellnum);
+    ReleaseReadLock(&afs_xcell);
+    if (cn) {
+       cn->used = 1;
+       return 1;
+    } else {
+       return 0;
+    }
+}