viced-gethostcps-simplify-holds-20030215
[openafs.git] / src / viced / host.c
index 5edd3cf..b349a2d 100644 (file)
@@ -54,6 +54,7 @@ RCSID("$Header$");
 #include <rx/rx.h>
 #include <afs/cellconfig.h>
 #include <stdlib.h>
+#include "viced_prototypes.h"
 #include "viced.h"
 #include "host.h"
 
@@ -416,19 +417,14 @@ static char h_AddrInSameNetwork(afs_uint32 a_targetAddr, afs_uint32 a_candAddr)
 #endif /* FS_STATS_DETAILED */
 
 
-
+/* Assumptions: called with held host */
 void
 h_gethostcps_r(register struct host *host, register afs_int32 now)
 {
     register int code;
-    int  slept=0, held;
-
-    /* at this point, the host might not be locked, nor held */
-    /* make sure that we do not disappear behind the RPC     */
-    if ( !(held = h_Held_r(host)) )
-               h_Hold_r(host);
+    int  slept=0;
 
-       /* wait if somebody else is already doing the getCPS call */
+    /* wait if somebody else is already doing the getCPS call */
     while ( host->hostFlags & HCPS_INPROGRESS ) 
     {
        slept = 1;              /* I did sleep */
@@ -497,10 +493,6 @@ h_gethostcps_r(register struct host *host, register afs_int32 now)
                ViceLog(0, ("LWP_NoYieldSignal returns %d\n", code));
 #endif /* AFS_PTHREAD_ENV */
     }
-
-    /* if we had held the  host, release it now */
-    if ( !held ) 
-       h_Release_r(host);
 }
 
 void h_flushhostcps(hostaddr, hport)
@@ -524,19 +516,10 @@ return;
 
 /*
  * Allocate a host.  It will be identified by the peer (ip,port) info in the
- * rx connection provided.  The host is returned un-held and un-locked
+ * rx connection provided.  The host is returned held and locked
  */
 #define        DEF_ROPCONS 2115
 
-struct host *h_Alloc(register struct rx_connection *r_con)
-{
-    struct host *retVal;
-    H_LOCK
-    retVal = h_Alloc_r(r_con);
-    H_UNLOCK
-    return retVal;
-}
-
 struct host *h_Alloc_r(register struct rx_connection *r_con)
 {
     register int code;
@@ -553,7 +536,10 @@ struct host *h_Alloc_r(register struct rx_connection *r_con)
     host = GetHT();
 
     h_hashChain = (struct h_hashChain*) malloc(sizeof(struct h_hashChain));
-    assert(h_hashChain);
+    if (!h_hashChain) {
+        ViceLog(0, ("Failed malloc in h_Alloc_r\n"));
+        assert(0);
+    }
     h_hashChain->hostPtr = host;
     h_hashChain->addr = rxr_HostOf(r_con);
     h_hashChain->next = hostHashTable[index];
@@ -587,13 +573,14 @@ struct host *h_Alloc_r(register struct rx_connection *r_con)
     host->hostFlags = 0;
     host->hcps.prlist_val = NULL;
     host->hcps.prlist_len = 0;
-    host->hcps.prlist_val = NULL;
     host->interface = 0;
 #ifdef undef
     host->hcpsfailed = 0;      /* save cycles */
-    h_gethostcps(host);      /* do this under host lock */
+    h_gethostcps(host);      /* do this under host hold/lock */
 #endif
     host->FirstClient = 0;      
+    h_Hold_r(host);
+    h_Lock_r(host);
     h_InsertList_r(host);      /* update global host List */
 #if FS_STATS_DETAILED
     /*
@@ -606,7 +593,7 @@ struct host *h_Alloc_r(register struct rx_connection *r_con)
 #endif /* FS_STATS_DETAILED */
     return host;
 
-} /*h_Alloc*/
+} /*h_Alloc_r*/
 
 
 /* Lookup a host given an IP address and UDP port number. */
@@ -645,8 +632,10 @@ restart:
                 * membership list for the host.  Note this could be the
                 * first time that the host is added to a group.  Also
                 * here we also retry on previous legitimate hcps failures.
+                *
+                * If we get here we still have a host hold.
                 */
-               h_gethostcps_r(host,now);
+               h_gethostcps_r(host,now); 
            }
            break;
        }
@@ -685,7 +674,7 @@ struct host *h_LookupUuid_r(afsUUID *uuidp)
  */
 
 /* h_TossStuff_r:  Toss anything in the host structure (the host or
- * clients marked for deletion.  Called from r_Release ONLY.
+ * clients marked for deletion.  Called from h_Release_r ONLY.
  * To be called, there must be no holds, and either host->deleted
  * or host->clientDeleted must be set.
  */
@@ -699,13 +688,24 @@ int h_TossStuff_r(register struct host *host)
     if  (i!=h_maxSlots)
        return;
 
-    /* ASSUMPTION: r_FreeConnection() does not yield */
+    /* if somebody still has this host locked */
+    if (h_NBLock_r(host) != 0) {
+       char hoststr[16];
+       ViceLog(0, ("Warning:  h_TossStuff_r failed; Host %s:%d was locked.\n",
+                   afs_inet_ntoa_r(host->host, hoststr), host->port)); 
+       return;
+    } else {
+       h_Unlock_r(host);
+    }
+
+    /* ASSUMPTION: rxi_FreeConnection() does not yield */
     for (cp = &host->FirstClient; (client = *cp); ) {
        if ((host->hostFlags & HOSTDELETED) || client->deleted) {
            if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
                free(client->CPS.prlist_val);
                 client->CPS.prlist_val = NULL;
            }
+           client->CPS.prlist_len = 0;
            if (client->tcon) {
                rx_SetSpecific(client->tcon, rxcon_client_key, (void *)0);
            }
@@ -744,7 +744,7 @@ int h_TossStuff_r(register struct host *host)
            free(host->hcps.prlist_val);
        host->hcps.prlist_val = NULL;
        host->hcps.prlist_len = 0;
-       DeleteAllCallBacks_r(host);
+       DeleteAllCallBacks_r(host, 1);
        host->hostFlags &= ~RESETDONE;  /* just to be safe */
 
        /* if alternate addresses do not exist */
@@ -837,9 +837,15 @@ void h_Enumerate(int (*proc)(), char *param)
        return;
     }
     list = (struct host **)malloc(hostCount * sizeof(struct host *));
-    assert(list != NULL);
+    if (!list) {
+        ViceLog(0, ("Failed malloc in h_Enumerate\n"));
+       assert(0);
+    }
     held = (int *)malloc(hostCount * sizeof(int));
-    assert(held != NULL);
+    if (!held) {
+        ViceLog(0, ("Failed malloc in h_Enumerate\n"));
+       assert(0);
+    }
     for (count = 0, host = hostList ; host ; host = host->next, count++) {
        list[count] = host;
        if (!(held[count] = h_Held_r(host)))
@@ -894,6 +900,10 @@ void hashInsertUuid_r(struct afsUUID *uuid, struct host* host)
 
         /* insert into beginning of list for this bucket */
        chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
+       if (!chain) {
+           ViceLog(0, ("Failed malloc in hashInsertUuid_r\n"));
+           assert(0);
+       }
        assert(chain);
        chain->hostPtr = host;
        chain->next = hostUuidHashTable[index];
@@ -909,7 +919,6 @@ struct host *h_GetHost_r(struct rx_connection *tcon)
     int held;
     struct interfaceAddr interf;
     int interfValid = 0;
-    afs_int32  buffer[AFS_MAX_INTERFACE_ADDR];
     struct Identity *identP = NULL;
     afs_int32 haddr;
     afs_int32 hport;
@@ -943,6 +952,10 @@ retry:
        H_LOCK
        if ( code == RXGEN_OPCODE ) {
                identP = (struct Identity *)malloc(sizeof(struct Identity));
+               if (!identP) {
+                   ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
+                   assert(0);
+               }
                identP->valid = 0;
                rx_SetSpecific(tcon, rxcon_ident_key, identP);
                /* The host on this connection was unable to respond to 
@@ -962,6 +975,10 @@ retry:
        } else if (code == 0) {
                interfValid = 1;
                identP = (struct Identity *)malloc(sizeof(struct Identity));
+               if (!identP) {
+                   ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
+                   assert(0);
+               }
                identP->valid = 1;
                identP->uuid = interf.uuid;
                rx_SetSpecific(tcon, rxcon_ident_key, identP);
@@ -1007,19 +1024,27 @@ retry:
          && ( ( !identP->valid && host->interface )
            || ( identP->valid && !host->interface )
            || ( identP->valid
-             && !afs_uuid_equal(&identP->uuid, &host->interface->uuid) ) ) ) {
-               /* The host in the cache is not the host for this connection */
-               host->hostFlags |= HOSTDELETED;
-               h_Unlock_r(host);
-               if (!held) h_Release_r(host);
-               ViceLog(0, ("CB: new identity for host %s:%d, deleting\n",
-                          afs_inet_ntoa_r(host->host, hoststr), host->port));
-               goto retry;
+             && !afs_uuid_equal(&identP->uuid, &host->interface->uuid) ) ) ) 
+       {
+           char uuid1[128], uuid2[128];
+           /* The host in the cache is not the host for this connection */
+           host->hostFlags |= HOSTDELETED;
+           h_Unlock_r(host);
+           if (!held) h_Release_r(host);
+
+           if (identP->valid)
+               afsUUID_to_string(identP->uuid, uuid1, 127);
+           if (host->interface)
+               afsUUID_to_string(host->interface->uuid, uuid2, 127);
+           ViceLog(0, 
+                   ("CB: new identity for host %s:%d, deleting(%x %x %s %s)\n", 
+                    afs_inet_ntoa_r(host->host, hoststr), host->port, 
+                    identP->valid, host->interface, identP->valid ? uuid1 : 
+                    "", host->interface ? uuid2 : ""));
+           goto retry;
        }
     } else {
-        host = h_Alloc_r(tcon);
-        h_Hold_r(host);
-        h_Lock_r(host);
+       host = h_Alloc_r(tcon); /* returned held and locked */
        h_gethostcps_r(host,FT_ApproxTime());
         if (!(host->Console&1)) {
            if (!identP || !interfValid) {
@@ -1027,7 +1052,11 @@ retry:
                code = RXAFSCB_WhoAreYou(host->callback_rxcon, &interf);
                H_LOCK
                if ( code == RXGEN_OPCODE ) {
-                 identP = (struct Identity *)malloc(sizeof(struct Identity));
+                   identP = (struct Identity *)malloc(sizeof(struct Identity));
+                   if (!identP) {
+                       ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
+                       assert(0);
+                   }
                    identP->valid = 0;
                    rx_SetSpecific(tcon, rxcon_ident_key, identP);
                    ViceLog(25,
@@ -1037,6 +1066,10 @@ retry:
                } else if (code == 0) {
                    interfValid = 1;
                    identP = (struct Identity *)malloc(sizeof(struct Identity));
+                   if (!identP) {
+                       ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
+                       assert(0);
+                   }
                    identP->valid = 1;
                    identP->uuid = interf.uuid;
                    rx_SetSpecific(tcon, rxcon_ident_key, identP);
@@ -1149,6 +1182,10 @@ static int MapName_r(char *aname, char *acell, afs_int32 *aval)
            }               
            foreign = 1;  /* attempt cross-cell authentication */
            tname = (char *) malloc(anamelen+cnamelen+2);
+           if (!tname) {
+               ViceLog(0, ("Failed malloc in MapName_r\n"));
+               assert(0);
+           }
            strcpy(tname, aname);
            tname[anamelen] = '@';
            strcpy(tname+anamelen+1, acell);
@@ -1239,7 +1276,7 @@ ticket name length != 64
        h_Hold_r(client->host);
        if (client->prfail != 2) {  /* Could add shared lock on client here */
          /* note that we don't have to lock entry in this path to
-          * ensure CPS is initialized, since we don't call rxr_SetSpecific
+          * ensure CPS is initialized, since we don't call rx_SetSpecific
           * until initialization is done, and we only get here if
           * rx_GetSpecific located the client structure.
           */
@@ -1308,6 +1345,16 @@ ticket name length != 64
             if (client->tcon && (client->tcon != tcon)) {
                ViceLog(0, ("*** Vid=%d, sid=%x, tcon=%x, Tcon=%x ***\n", 
                            client->ViceId, client->sid, client->tcon, tcon));
+               oldClient = (struct client *) rx_GetSpecific(client->tcon,
+                                                            rxcon_client_key);
+               if (oldClient) {
+                   if (oldClient == client)
+                       rx_SetSpecific(client->tcon, rxcon_client_key, NULL);
+                   else
+                       ViceLog(0,
+                           ("Client-conn mismatch: CL1=%x, CN=%x, CL2=%x\n",
+                            client, client->tcon, oldClient));
+               }
                client->tcon = (struct rx_connection *)0;
             }
             client->refCount++;
@@ -1334,6 +1381,7 @@ ticket name length != 64
          client->sid = rxr_CidOf(tcon);
          client->VenusEpoch = rxr_GetEpoch(tcon);
          client->CPS.prlist_val = 0;
+         client->CPS.prlist_len = 0;
          client->refCount = 1;
          CurrentConnections++; /* increment number of connections */
        }
@@ -1345,6 +1393,7 @@ ticket name length != 64
           free(client->CPS.prlist_val);
        }
        client->CPS.prlist_val = NULL;
+       client->CPS.prlist_len = 0;
         client->ViceId = viceid;
        client->expTime = expTime;
 
@@ -1391,7 +1440,8 @@ ticket name length != 64
      * required).  So, before setting the RPC's rock, we should disconnect
      * the RPC from the other client structure's rock.
      */
-    if ((oldClient = (struct client *) rx_GetSpecific(tcon, rxcon_client_key))) {
+    oldClient = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
+    if (oldClient && oldClient->tcon == tcon) {
        oldClient->tcon = (struct rx_connection *) 0;
        /* rx_SetSpecific will be done immediately below */
     }
@@ -1425,8 +1475,15 @@ int GetClient(struct rx_connection * tcon, struct client **cp)
     H_LOCK
 
     *cp = client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
-    /* XXXX debug */
-    assert(client && client->tcon && rxr_CidOf(client->tcon) == client->sid);
+    if (!(client && client->tcon && rxr_CidOf(client->tcon) == client->sid)) {
+       if (!client)
+           ViceLog(0, ("GetClient: no client in conn %x\n", tcon));
+       else
+           ViceLog(0, ("GetClient: tcon %x tcon sid %d client sid %d\n", 
+                       client->tcon, client->tcon ? rxr_CidOf(client->tcon)
+                       : -1, client->sid));
+       assert(0);
+    }
     if (client &&
        client->LastCall > client->expTime && client->expTime) {
        char hoststr[16];
@@ -1453,6 +1510,10 @@ char *h_UserName(struct client *client)
 
     lids.idlist_len = 1;
     lids.idlist_val = (afs_int32 *)malloc(1*sizeof(afs_int32));
+    if (!lids.idlist_val) {
+       ViceLog(0, ("Failed malloc in h_UserName\n"));
+       assert(0);
+    }
     lnames.namelist_len = 0;
     lnames.namelist_val = (prname *)0;
     lids.idlist_val[0] = client->ViceId;
@@ -1850,7 +1911,6 @@ static struct AFSFid zerofid;
 int CheckHost(register struct host *host, int held)
 {
     register struct client *client;
-    struct interfaceAddr interf;
     int code;
 
     /* Host is held by h_Enumerate */
@@ -1983,11 +2043,11 @@ initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
                host->host, interf->numberOfInterfaces));
 
        number = interf->numberOfInterfaces;
-       myPort   = host->port;
-       myHost   = host->host; /* current interface address */
+       myPort = host->port;
+       myHost = host->host; /* current interface address */
 
        /* validation checks */
-       if ( number < 0 )
+       if ( number < 0 || number > AFS_MAX_INTERFACE_ADDR )
         {
                ViceLog(0,("Number of alternate addresses returned is %d\n",
                         number));
@@ -2020,7 +2080,10 @@ initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
            interface = (struct Interface *)
                        malloc(sizeof(struct Interface) +
                               (sizeof(afs_int32) * (count-1)));
-           assert(interface);
+           if (!interface) {
+               ViceLog(0, ("Failed malloc in initInterfaceAddr_r\n"));
+               assert(0);
+           }
            interface->numberOfInterfaces = count;
        } else {
            interface = (struct Interface *)
@@ -2056,7 +2119,10 @@ void hashInsert_r(afs_int32 addr, struct host* host)
 
         /* insert into beginning of list for this bucket */
        chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
-       assert(chain);
+       if (!chain) {
+           ViceLog(0, ("Failed malloc in hashInsert_r\n"));
+           assert(0);
+       }
        chain->hostPtr = host;
        chain->next = hostHashTable[index];
        chain->addr = addr;
@@ -2100,6 +2166,10 @@ addInterfaceAddr_r(struct host *host, afs_int32 addr)
            interface = (struct Interface *)
                        malloc(sizeof(struct Interface) +
                               (sizeof(afs_int32) * number));
+           if (!interface) {
+               ViceLog(0, ("Failed malloc in addInterfaceAddr_r\n"));
+               assert(0);
+           }
            interface->numberOfInterfaces = number + 1;
            interface->uuid = host->interface->uuid;
            for (i = 0 ; i < number ; i++)