Fileserver capabilities support for the UNIX client
authorFelix Frank <Felix.Frank@Desy.de>
Thu, 4 Mar 2010 03:41:15 +0000 (22:41 -0500)
committerDerrick Brashear <shadow@dementia.org>
Tue, 13 Apr 2010 11:30:25 +0000 (04:30 -0700)
The attached patch has the client perform a GetCapabilities RPC
on fileservers it encounters.
It uses an additional server flag bit to keep track of the servers that
have been queried already.

In the case of afs_CeckServers(), GetTime RPCs are largely replaced by
GetCapabilities. GetTime is performed on a server if and only if
afs_setTime is nonzero and either
(a) no setTimeHost has yet been determined or
(b) the server in question has been designated as setTimeHost
The GetServers() function could thus be simplified even further wrt. the
setTime mechanism, but doing so would imply more rewriting (violating
the KISS principle; a followup patch should deal with that).

When a client is asked to reset callback states, it also resets the
"capabilites known" bit.

Thanks go to Simon Wilkinson, Jeffrey Altman and Jeffrey Hutzelman for
input regarding logic and implementation details.

FIXES 124972

Change-Id: I4e22db3c5ca71f00e8c77f337e38daa0fa5b9124
Reviewed-on: http://gerrit.openafs.org/1640
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/afs.h
src/afs/afs_callback.c
src/afs/afs_prototypes.h
src/afs/afs_server.c

index 1b2ab15..d4da4f8 100644 (file)
@@ -406,6 +406,10 @@ struct srvAddr {
 #define        SRVR_ISGONE                     0x80
 #define        SNO_INLINEBULK                  0x100
 #define SNO_64BIT                       0x200
+#define SCAPS_KNOWN                    0x400
+
+#define SRV_CAPABILITIES(ts) \
+{ if ( !(ts->flags & SCAPS_KNOWN)) afs_GetCapabilities(ts); ts->capabilities; }
 
 #define afs_serverSetNo64Bit(s) ((s)->srvr->server->flags |= SNO_64BIT)
 #define afs_serverHasNo64Bit(s) ((s)->srvr->server->flags & SNO_64BIT)
@@ -437,6 +441,7 @@ struct server {
     afs_int32 sumOfDowntimes;  /* Total downtime experienced, in seconds */
     struct srvAddr *addr;
     afs_uint32 flags;          /* Misc flags */
+    afs_int32 capabilities;
 };
 
 #define        afs_PutServer(servp, locktype)
index b8373bb..674bb86 100644 (file)
@@ -771,6 +771,11 @@ SRXAFSCB_InitCallBackState(struct rx_call *a_call)
                        ReleaseWriteLock(&afs_xcbhash);
                    }
                }
+
+           /* capabilities need be requested again */
+           ObtainWriteLock(&afs_xserver, 877);
+           ts->flags &= ~SCAPS_KNOWN;
+           ReleaseWriteLock(&afs_xserver);
        }
 
 
index d4dc7fc..cbaef5b 100644 (file)
@@ -833,6 +833,7 @@ extern struct server *afs_GetServer(afs_uint32 * aserver, afs_int32 nservers,
                                    afs_int32 acell, u_short aport,
                                    afs_int32 locktype, afsUUID * uuidp,
                                    afs_int32 addr_uniquifier);
+extern void afs_GetCapabilities(struct server *ts);
 extern void ForceAllNewConnections(void);
 extern void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown);
 extern afs_int32 afs_ServerDown(struct srvAddr *sa);
index 8dfd2f1..01e81a4 100644 (file)
@@ -542,6 +542,7 @@ afs_CheckServers(int adown, struct cell *acellp)
     int nconns;
     struct rx_connection **rxconns;      
     afs_int32 *conntimer, *deltas, *results;
+    Capabilities *caps = NULL;
 
     AFS_STATCNT(afs_CheckServers);
 
@@ -588,6 +589,9 @@ afs_CheckServers(int adown, struct cell *acellp)
     deltas = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
     results = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
 
+    caps = (Capabilities *)afs_osi_Alloc(j * sizeof (Capabilities));
+    memset(caps, 0, j * sizeof(Capabilities));
+
     for (i = 0; i < j; i++) {
        deltas[i] = 0;
        sa = addrs[i];
@@ -636,23 +640,72 @@ afs_CheckServers(int adown, struct cell *acellp)
        }
     } /* Outer loop over addrs */
 
-    start = osi_Time();         /* time the gettimeofday call */
-    AFS_GUNLOCK(); 
+    AFS_GUNLOCK();
     multi_Rx(rxconns,nconns)
       {
-       tv.tv_sec = tv.tv_usec = 0;
-       multi_RXAFS_GetTime((afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
-       tc = conns[multi_i];
-       sa = tc->srvr;
-       if (conntimer[multi_i] == 1)
-         rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
-       end = osi_Time();
-       results[multi_i]=multi_error;
-       if ((start == end) && !multi_error)
-         deltas[multi_i] = end - tv.tv_sec;
-       
+       multi_RXAFS_GetCapabilities(&caps[multi_i]);
+       results[multi_i] = multi_error;
       } multi_End;
-    AFS_GLOCK(); 
+    AFS_GLOCK();
+
+    for ( i = 0 ; i < nconns ; i++ ) {
+       ts = addrs[i]->server;
+       if ( !ts )
+           continue;
+       ts->capabilities = 0;
+       ts->flags |= SCAPS_KNOWN;
+       if ( results[i] == RXGEN_OPCODE ) {
+           /* Mark server as up - it responded */
+           results[i] = 0;
+           continue;
+       }
+       if ( results[i] >= 0 )
+           /* we currently handle 32-bits of capabilities */
+           if (caps[i].Capabilities_len > 0) {
+               ts->capabilities = caps[i].Capabilities_val[0];
+               xdr_free((xdrproc_t)xdr_Capabilities, &caps[i]);
+               caps[i].Capabilities_val = NULL;
+               caps[i].Capabilities_len = 0;
+           }
+    }
+
+    if ( afs_setTime != 0 ) {
+       start = osi_Time();         /* time the gettimeofday call */
+       AFS_GUNLOCK();
+       if ( afs_setTimeHost == NULL ) {
+           multi_Rx(rxconns,nconns)
+             {
+               tv.tv_sec = tv.tv_usec = 0;
+               multi_RXAFS_GetTime(
+                       (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
+               tc = conns[multi_i];
+               sa = tc->srvr;
+               if (conntimer[multi_i] == 1)
+                 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
+               end = osi_Time();
+               results[multi_i]=multi_error;
+               if ((start == end) && !multi_error)
+                 deltas[multi_i] = end - tv.tv_sec;
+
+             } multi_End;
+           }
+       else {                  /* find and query setTimeHost only */
+           for ( i = 0 ; i < j ; i++ ) {
+               if ( conns[i] == NULL || conns[i]->srvr == NULL )
+                   continue;
+               if ( conns[i]->srvr->server == afs_setTimeHost ) {
+                   tv.tv_sec = tv.tv_usec = 0;
+                   results[i] = RXAFS_GetTime(rxconns[i],
+                               (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
+                   end = osi_Time();
+                   if ((start == end) && !results[i])
+                       deltas[i] = end - tv.tv_sec;
+                   break;
+               }
+           }
+       }
+       AFS_GLOCK();
+    }
     
     for(i=0;i<nconns;i++){
       tc = conns[i];
@@ -755,6 +808,7 @@ afs_CheckServers(int adown, struct cell *acellp)
     afs_osi_Free(conntimer, j * sizeof(afs_int32));
     afs_osi_Free(deltas, j * sizeof(afs_int32));
     afs_osi_Free(results, j * sizeof(afs_int32));
+    afs_osi_Free(caps, j * sizeof(Capabilities));
     
 } /*afs_CheckServers*/
 
@@ -1623,6 +1677,48 @@ afs_RemoveSrvAddr(struct srvAddr *sap)
     }
 }
 
+/* afs_GetCapabilities
+ * Try and retrieve capabilities of a given file server. Carps on actual
+ * failure. Servers are not expected to support this RPC. */
+void
+afs_GetCapabilities(struct server *ts)
+{
+    Capabilities caps = {0, NULL};
+    struct vrequest treq;
+    struct afs_conn *tc;
+    struct unixuser *tu;
+    afs_int32 code;
+
+    if ( !ts )
+       return;
+    if ( !afs_osi_credp )
+       return;
+
+    if ((code = afs_InitReq(&treq, afs_osi_credp)))
+       return;
+    tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
+    if ( !tu )
+       return;
+    tc = afs_ConnBySA(ts->addr, ts->cell->fsport, ts->cell->cellNum, tu, 0, 1,
+                                                               SHARED_LOCK);
+    if ( !tc )
+       return;
+    code = RXAFS_GetCapabilities(tc->id, &caps);
+    if ( code && code != RXGEN_OPCODE )
+       afs_warn("RXAFS_GetCapabilities failed with code %d\n", code);
+    else
+       ts->flags |= SCAPS_KNOWN;
+    afs_PutConn(tc, SHARED_LOCK);
+
+    if ( caps.Capabilities_len > 0 ) {
+       ts->capabilities = caps.Capabilities_val[0];
+       xdr_free((xdrproc_t)xdr_Capabilities, &caps);
+       caps.Capabilities_len = 0;
+       caps.Capabilities_val = NULL;
+    }
+
+}
+
 /* afs_GetServer()
  * Return an updated and properly initialized server structure
  * corresponding to the server ID, cell, and port specified.
@@ -1823,6 +1919,9 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
            afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
     }
 
+    if ( aport == AFS_FSPORT && !(newts->flags & SCAPS_KNOWN))
+       afs_GetCapabilities(newts);
+
     ReleaseWriteLock(&afs_xsrvAddr);
     ReleaseWriteLock(&afs_xserver);
     return (newts);