Windows: Readonly Volume Versioning for Windows Cache Manager
authorJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 5 Oct 2009 18:00:50 +0000 (14:00 -0400)
committerJeffrey Altman <jaltman|account-1000011@unknown>
Mon, 12 Oct 2009 14:38:52 +0000 (07:38 -0700)
When the HKLM\SYSTEM\CurrentControlSet\Services\TransarcAFSDaemon\Parameters
"ReadOnlyVolumeVersioning" DWORD registry value is non-zero, the volserver
will be queried for each .readonly volume to obtain the lastUpdateTime.
The lastUpdateTime will be used as a volume version identifier for each
cm_scache_t object stored in the volume.  With a known volume version,
whenever a current status is obtained for any object within the .readonly volume,
all the cached objects within that volume that have the same volume version
can share the resulting callback registration.

LICENSE MIT

Reviewed-on: http://gerrit.openafs.org/579
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_conn.c
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_server.c
src/WINNT/afsd/cm_server.h
src/WINNT/afsd/cm_volume.c
src/WINNT/afsd/cm_volume.h

index 77c242f..4603251 100644 (file)
@@ -424,6 +424,7 @@ AFSD_EXELIBS =\
        $(DESTDIR)\lib\libafsconf.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afspthread.lib \
+        $(DESTDIR)\lib\afs\afstvolser.lib \
         $(LANAHELPERLIB)
 
 $(AFSD_EXEFILE): $(OUT)\afsd.obj $(AFSDOBJS) $(OUT)\afsd.res  $(RXOBJS) $(AFSD_EXELIBS)
index 2176154..17835ae 100644 (file)
@@ -111,6 +111,7 @@ extern int cm_fakeGettingCallback;                  // 1 if currently updating the fake root.af
 
 extern int cm_dnsEnabled;
 extern int cm_freelanceEnabled;
+extern int cm_readonlyVolumeVersioning;
 
 extern long rx_mtu;
 
index d9f85f3..54a8a39 100644 (file)
@@ -68,6 +68,7 @@ DWORD cm_mountRootLen;
 clientchar_t cm_mountRootC[1024];
 DWORD cm_mountRootCLen;
 
+int cm_readonlyVolumeVersioning = 0;
 int cm_logChunkSize;
 int cm_chunkSize;
 
@@ -398,6 +399,21 @@ static void afsd_InitServerPreferences(void)
                 tsp->flags |= CM_SERVERFLAG_PREF_SET;
                 lock_ReleaseMutex(&tsp->mx);
             }
+
+            if (cm_readonlyVolumeVersioning) {
+                /* Add a matching vol server */
+                tsp = cm_FindServer(&saddr, CM_SERVER_VOL);
+                if ( tsp )             /* an existing server - ref count increased */
+                {
+                    tsp->ipRank = (USHORT)dwRank; /* no need to protect by mutex*/
+                    cm_PutServer(tsp);  /* decrease refcount */
+                }
+                else   /* add a new server without a cell */
+                {
+                    tsp = cm_NewServer(&saddr, CM_SERVER_VOL, NULL, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
+                    tsp->ipRank = (USHORT)dwRank;
+                }
+            }
         }
 
         RegCloseKey(hkPrefs);
@@ -1199,7 +1215,7 @@ afsd_InitCM(char **reasonP)
                            (BYTE *) &dwValue, &dummyLen);
     if (code == ERROR_SUCCESS) {
         cm_followBackupPath = (unsigned short) dwValue;
-    } 
+    }
     afsi_log("CM FollowBackupPath is %u", cm_followBackupPath);
 
     dummyLen = sizeof(DWORD);
@@ -1210,6 +1226,14 @@ afsd_InitCM(char **reasonP)
     } 
     afsi_log("CM PerFileAccessCheck is %d", cm_accessPerFileCheck);
 
+    dummyLen = sizeof(DWORD);
+    code = RegQueryValueEx(parmKey, "ReadOnlyVolumeVersioning", NULL, NULL,
+                           (BYTE *) &dwValue, &dummyLen);
+    if (code == ERROR_SUCCESS) {
+        cm_readonlyVolumeVersioning = (unsigned short) dwValue;
+    }
+    afsi_log("CM ReadOnlyVolumeVersioning is %u", cm_readonlyVolumeVersioning);
+
     RegCloseKey (parmKey);
 
     cacheBlocks = ((afs_uint64)cacheSize * 1024) / blockSize;
index e919bf4..60ce24d 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <WINNT/syscfg.h>
 #include <WINNT/afsreg.h>
+#include <afs/vldbint.h>
+#include <afs/volint.h>
 
 int
 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid);
@@ -1729,6 +1731,60 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
         if (scp && scp->flags & CM_SCACHEFLAG_PURERO) {
             cm_volume_t * volp = cm_GetVolumeByFID(&scp->fid);
             if (volp) {
+                /* If the volume has a valid callback from the same
+                 * server as issued this latest callback and we know
+                 * the last update time of the RO volume,
+                 * then the last update time of the RO volume
+                 * must not have changed.  Otherwise, we must obtain
+                 * the volume status info from the volserver that
+                 * matches the file server the callback was received
+                 * from.
+                 */
+                if (cm_readonlyVolumeVersioning &&
+                    (volp->cbExpiresRO == 0 || volp->cbServerpRO != scp->cbServerp)) {
+                    cm_server_t *volserverp;
+
+                    volserverp = cm_FindServer(&scp->cbServerp->addr, CM_SERVER_VOL);
+                    if (volserverp) {
+                        afs_int32 vcode = -1, code = -1;
+                        volEntries volumeInfo;
+                        struct nvldbentry entry;
+                        int i;
+                        afs_uint32 addr = volserverp->addr.sin_addr.s_addr;
+                        cm_cell_t *cellp;
+                        cm_conn_t *connp;
+                        struct rx_connection * rxconnp;
+                        cm_req_t req;
+
+                        cm_InitReq(&req);
+
+                        cellp = cm_FindCellByID(scp->fid.cell, 0);
+                        code = cm_ConnByMServers(cellp->vlServersp, cm_rootUserp, &req, &connp);
+                        if (code == 0) {
+                            rxconnp = cm_GetRxConn(connp);
+                            vcode = VL_GetEntryByIDN(rxconnp, scp->fid.volume, -1, &entry);
+                            rx_PutConnection(rxconnp);
+                        }
+                        if (vcode == 0) {
+                            for (i=0, code=-1; i < entry.nServers; i++) {
+                                if ( entry.serverNumber[i] == htonl(addr)) {
+                                    code = cm_ConnByServer(volserverp, cm_rootUserp, &connp);
+                                    if (code == 0) {
+                                        rxconnp = cm_GetRxConn(connp);
+                                        memset(&volumeInfo, 0, sizeof(volumeInfo));
+                                        code = AFSVolListOneVolume(rxconnp, entry.serverPartition[i], scp->fid.volume, &volumeInfo);
+                                        rx_PutConnection(rxconnp);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        volp->lastUpdateRO = (vcode == 0 && code == 0 ? volumeInfo.volEntries_val->updateDate : 0);
+                        cm_PutServer(volserverp);
+                    }
+                }
+
+                scp->lastUpdateRO = volp->lastUpdateRO;
                 volp->cbExpiresRO = scp->cbExpires;
                 if (volp->cbServerpRO != scp->cbServerp) {
                     if (volp->cbServerpRO)
@@ -1941,8 +1997,22 @@ void cm_CheckCBExpiration(void)
             if (scp->flags & CM_SCACHEFLAG_PURERO) {
                 cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
                 if (volp) {
+                    /* In the case of a scp from a .readonly volume
+                     * we can automatically refresh the scp callback
+                     * state under one of two conditions:
+                     *
+                     *   - there is currently an unexpired callback
+                     *     and the callback is simply being extended
+                     *
+                     *   - the lastUpdateRO time for the scp and the
+                     *     volp are the same indicating that the
+                     *     .readonly has not changed
+                     */
                     if (volp->cbExpiresRO > scp->cbExpires &&
-                        scp->cbExpires > 0) 
+                        (volp->cbServerpRO == scp->cbServerp &&
+                         scp->cbExpires > 0 ||
+                         volp->lastUpdateRO > 0 &&
+                         scp->lastUpdateRO == volp->lastUpdateRO))
                     {
                         scp->cbExpires = volp->cbExpiresRO;
                         if (volp->cbServerpRO != scp->cbServerp) {
index 6bc2bdf..3eca87d 100644 (file)
@@ -1074,6 +1074,11 @@ static void cm_NewRXConnection(cm_conn_t *tcp, cm_ucell_t *ucellp,
             port = htons(7000);
         serviceID = 1;
         break;
+    case CM_SERVER_VOL:
+        if (port == 0)
+            port = htons(7005);
+        serviceID = 4;
+        break;
     default:
         osi_panic("unknown server type", __FILE__, __LINE__);
     }
index c86453f..8512b60 100644 (file)
@@ -208,6 +208,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
         scp->cbServerp = NULL;
     }
     scp->cbExpires = 0;
+    scp->lastUpdateRO = 0;
 
     scp->fid.vnode = 0;
     scp->fid.volume = 0;
@@ -619,6 +620,7 @@ void cm_InitSCache(int newFile, long maxSCaches)
 #endif
                 scp->cbServerp = NULL;
                 scp->cbExpires = 0;
+                scp->lastUpdateRO = 0;
                 scp->fileLocksH = NULL;
                 scp->fileLocksT = NULL;
                 scp->serverLock = (-1);
@@ -1963,11 +1965,44 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
   
     for (scp = cm_data.allSCachesp; scp; scp = scp->allNextp) 
     {
-        sprintf(output, "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) type=%d dv=%I64d len=0x%I64x mp='%s' Locks (server=0x%x shared=%u excl=%u clnt=%u) lockCount=%d flags=0x%x cb=0x%x refCount=%u\r\n",
-                cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique, 
-                scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mountPointStringp, 
+        time_t t;
+        char *srvStr = NULL;
+        afs_uint32 srvStrRpc = TRUE;
+        char *cbt = NULL;
+        char *lurot = NULL;
+
+        if (scp->cbServerp) {
+            if (!((scp->cbServerp->flags & CM_SERVERFLAG_UUID) &&
+                UuidToString((UUID *)&scp->cbServerp->uuid, &srvStr) == RPC_S_OK)) {
+                afs_asprintf(&srvStr, "%.0I", scp->cbServerp->addr.sin_addr.s_addr);
+                srvStrRpc = FALSE;
+            }
+        }
+        if (scp->cbExpires) {
+            t = scp->cbExpires;
+            cbt = ctime(&t);
+            if (cbt) {
+                cbt = strdup(cbt);
+                cbt[strlen(cbt)-1] = '\0';
+            }
+        }
+        if (scp->lastUpdateRO) {
+            t = scp->lastUpdateRO;
+            lurot = ctime(&t);
+            if (lurot) {
+                lurot = strdup(lurot);
+                lurot[strlen(lurot)-1] = '\0';
+            }
+        }
+        sprintf(output,
+                "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) type=%d dv=%I64d len=0x%I64x "
+                "mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
+                "flags=0x%x cbServer='%s' cbExpires='%s' lastUpdateRO='%s' refCount=%u\r\n",
+                cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mountPointStringp,
                 scp->serverLock, scp->sharedLocks, scp->exclusiveLocks, scp->clientLocks, scp->fsLockCount,
-                scp->flags, (unsigned long)scp->cbExpires, scp->refCount);
+                scp->linkCount, scp->anyAccess, scp->flags, srvStr ? srvStr : "<none>", cbt ? cbt : "<none>",
+                lurot ? lurot : "<none>", scp->refCount);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         if (scp->fileLocksH) {
@@ -1976,27 +2011,41 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
 
             for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
                 cm_file_lock_t * lockp = (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
-                sprintf(output, "  %s lockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x key=0x%I64x flags=0x%x update=0x%I64u\r\n", 
-                         cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length, 
-                         lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
+                sprintf(output,
+                        "  %s lockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x "
+                        "key=0x%I64x flags=0x%x update=0x%I64u\r\n",
+                        cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length,
+                        lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
                 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
             }       
 
             sprintf(output, "  %s - done dumping scp locks\r\n", cookie);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
+
+        if (srvStr) {
+            if (srvStrRpc)
+                RpcStringFree(&srvStr);
+            else
+                free(srvStr);
+        }
+        if (cbt)
+            free(cbt);
+        if (lurot)
+            free(lurot);
     }
   
     sprintf(output, "%s - Done dumping all scache.\r\n", cookie);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s - dumping cm_data.scacheHashTable - cm_data.scacheHashTableSize=%d\r\n", cookie, cm_data.scacheHashTableSize);
+    sprintf(output, "%s - dumping cm_data.scacheHashTable - cm_data.scacheHashTableSize=%d\r\n",
+            cookie, cm_data.scacheHashTableSize);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
     for (i = 0; i < cm_data.scacheHashTableSize; i++)
     {
         for(scp = cm_data.scacheHashTablep[i]; scp; scp=scp->nextp) 
         {
-            sprintf(output, "%s scp=0x%p, hash=%d, fid (cell=%d, volume=%d, vnode=%d, unique=%d)\r\n", 
+            sprintf(output, "%s scp=0x%p, hash=%d, fid (cell=%d, volume=%d, vnode=%d, unique=%d)\r\n",
                     cookie, scp, i, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
@@ -2010,9 +2059,11 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
 
     for (q = cm_allFileLocks; q; q = osi_QNext(q)) {
         cm_file_lock_t * lockp = (cm_file_lock_t *)q;
-        sprintf(output, "%s filelockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x key=0x%I64x flags=0x%x update=0x%I64u\r\n", 
-                 cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length, 
-                 lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
+        sprintf(output,
+                "%s filelockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x "
+                "key=0x%I64x flags=0x%x update=0x%I64u\r\n",
+                cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length,
+                lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }       
 
index 79046f9..9c480c0 100644 (file)
@@ -128,6 +128,9 @@ typedef struct cm_scache {
     afs_uint32 group;                  /* file owning group */
     cm_user_t *creator;                        /* user, if new file */
 
+    /* volume status */
+    time_t lastUpdateRO;                /* last update time for readonly volume */
+
     /* pseudo file status */
     osi_hyper_t serverLength;          /* length known to server */
 
index 16e6824..b49a6c9 100644 (file)
@@ -29,6 +29,7 @@ osi_rwlock_t cm_syscfgLock;
 cm_server_t *cm_allServersp;
 afs_uint32   cm_numFileServers = 0;
 afs_uint32   cm_numVldbServers = 0;
+afs_uint32   cm_numVolServers = 0;
 
 void
 cm_ForceNewConnectionsAllServers(void)
@@ -59,6 +60,10 @@ cm_PingServer(cm_server_t *tsp)
     char hoststr[16];
     cm_req_t req;
 
+    /* do not probe vol server (yet) */
+    if (tsp->type == CM_SERVER_VOL)
+        return;
+
     lock_ObtainMutex(&tsp->mx);
     if (tsp->flags & CM_SERVERFLAG_PINGING) {
        tsp->waitCount++;
@@ -86,7 +91,7 @@ cm_PingServer(cm_server_t *tsp)
 
        osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
                  osi_LogSaveString(afsd_logp, hoststr), 
-                 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
+                 tsp->type == CM_SERVER_VLDB ? "vldb" : (tsp->type == CM_SERVER_FILE ? "file" : "vol"),
                  wasDown ? "down" : "up",
                  tsp->capabilities);
 
@@ -210,9 +215,14 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
     int doPing;
     int isDown;
     int isFS;
+    int isVLDB;
 
     lock_ObtainRead(&cm_serverLock);
     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
+        /* do not probe vol server (yet) */
+        if (tsp->type == CM_SERVER_VOL)
+            continue;
+
         cm_GetServerNoLock(tsp);
         lock_ReleaseRead(&cm_serverLock);
 
@@ -222,6 +232,7 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
         doPing = 0;
         isDown = tsp->flags & CM_SERVERFLAG_DOWN;
         isFS   = tsp->type == CM_SERVER_FILE;
+        isVLDB = tsp->type == CM_SERVER_VLDB;
 
         /* only do the ping if the cell matches the requested cell, or we're
          * matching all cells (cellp == NULL), and if we've requested to ping
@@ -231,7 +242,7 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
              ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
                (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
              ((!(flags & CM_FLAG_CHECKVLDBSERVERS) || 
-               !isFS && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
+               isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
               (!(flags & CM_FLAG_CHECKFILESERVERS) || 
                  isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
             doPing = 1;
@@ -837,7 +848,7 @@ void cm_SetServerPrefs(cm_server_t * serverp)
     }
 
     serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
-    serverp->ipRank  = CM_IPRANK_LOW;  /* default setings */
+    serverp->ipRank  = CM_IPRANK_LOW;  /* default settings */
 
     for ( i=0; i < cm_noIPAddr; i++)
     {
@@ -908,11 +919,14 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell
         case CM_SERVER_FILE:
             cm_numFileServers++;
             break;
+        case CM_SERVER_VOL:
+            cm_numVolServers++;
+            break;
         }
 
         lock_ReleaseWrite(&cm_serverLock);     /* release server lock */
 
-        if ( !(flags & CM_FLAG_NOPROBE) ) {
+        if ( !(flags & CM_FLAG_NOPROBE) && (type != CM_SERVER_VOL)) {
             tsp->flags |= CM_SERVERFLAG_DOWN;  /* assume down; ping will mark up if available */
             cm_PingServer(tsp);                        /* Obtain Capabilities and check up/down state */
         }
@@ -1241,6 +1255,9 @@ void cm_FreeServer(cm_server_t* serverp)
             case CM_SERVER_FILE:
                 cm_numFileServers--;
                 break;
+            case CM_SERVER_VOL:
+                cm_numVolServers--;
+                break;
             }
 
            lock_FinalizeMutex(&serverp->mx);
@@ -1337,8 +1354,8 @@ int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
     if (lock)
         lock_ObtainRead(&cm_serverLock);
   
-    sprintf(output, "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n", 
-            cookie, cm_numFileServers, cm_numVldbServers);
+    sprintf(output, "%s - dumping servers - cm_numFileServers=%d, cm_numVolServers=%d, cm_numVldbServers=%d\r\n",
+            cookie, cm_numFileServers, cm_numVolServers, cm_numVldbServers);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
@@ -1353,6 +1370,9 @@ int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
         case CM_SERVER_FILE:
             type = "file";
             break;
+        case CM_SERVER_VOL:
+            type = "vol";
+            break;
         default:
             type = "unknown";
         }
index f401123..dd3fb89 100644 (file)
@@ -53,6 +53,7 @@ typedef struct cm_serverRef {
 /* types */
 #define CM_SERVER_VLDB         1       /* a VLDB server */
 #define CM_SERVER_FILE         2       /* a file server */
+#define CM_SERVER_VOL           3       /* a vol server */
 
 /* flags */
 #define CM_SERVERFLAG_DOWN     0x1     /* server is down */
index 4e15051..c9df208 100644 (file)
@@ -169,7 +169,7 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
     afs_uint32 j, k;
     cm_serverRef_t *tsrp;
     cm_server_t *tsp;
-    struct sockaddr_in tsockAddr;
+    struct sockaddr_in tsockAddr, tsockAddr2;
     long tflags;
     u_long tempAddr;
     struct vldbentry vldbEntry;
@@ -526,9 +526,18 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
                 }
             }
             if (!tsp) {
-                /* cm_NewServer will probe the server which in turn will
-                 * update the state on the volume group object */
                 lock_ReleaseWrite(&volp->rw);
+
+                if (cm_readonlyVolumeVersioning) {
+                    tsockAddr2 = tsockAddr;
+                    tsockAddr2.sin_port = htons(7005);
+                    /* Do not probe the volserver.  We will always use the file server's state. */
+                    tsp = cm_NewServer(&tsockAddr2, CM_SERVER_VOL, cellp, &serverUUID[i], CM_FLAG_NOPROBE);
+                    cm_PutServer(tsp); /* no longer need to vol server reference */
+                }
+
+                /* cm_NewServer will probe the file server which in turn will
+                 * update the state on the volume group object */
                 tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, &serverUUID[i], 0);
                 lock_ObtainWrite(&volp->rw);
             }
@@ -937,6 +946,7 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
         }
         volp->cbExpiresRO = 0;
         volp->cbServerpRO = NULL;
+        volp->lastUpdateRO = 0;
         cm_AddVolumeToNameHashTable(volp);
         lock_ReleaseWrite(&cm_volumeLock);
     }
@@ -1484,10 +1494,50 @@ int cm_DumpVolumes(FILE *outputFile, char *cookie, int lock)
   
     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp)
     {
-        sprintf(output, "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x refCount=%u\r\n", 
-                 cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID, volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags, 
-                 volp->refCount);
+        time_t t;
+        char *srvStr = NULL;
+        afs_uint32 srvStrRpc = TRUE;
+        char *cbt = NULL;
+        char *lurot = NULL;
+
+        if (volp->cbServerpRO) {
+            if (!((volp->cbServerpRO->flags & CM_SERVERFLAG_UUID) &&
+                UuidToString((UUID *)&volp->cbServerpRO->uuid, &srvStr) == RPC_S_OK)) {
+                afs_asprintf(&srvStr, "%.0I", volp->cbServerpRO->addr.sin_addr.s_addr);
+                srvStrRpc = FALSE;
+            }
+        }
+        if (volp->cbExpiresRO) {
+            t = volp->cbExpiresRO;
+            cbt = ctime(&t);
+            if (cbt) {
+                cbt = strdup(cbt);
+                cbt[strlen(cbt)-1] = '\0';
+            }
+        }
+        if (volp->lastUpdateRO) {
+            t = volp->lastUpdateRO;
+            lurot = ctime(&t);
+            if (lurot) {
+                lurot = strdup(lurot);
+                lurot[strlen(lurot)-1] = '\0';
+            }
+        }
+
+        sprintf(output, "%s - volp=0x%p cell=%s name=%s rwID=%u roID=%u bkID=%u flags=0x%x cbServerpRO='%s' cbExpiresRO='%s' lastUpdateRO='%s' refCount=%u\r\n",
+                 cookie, volp, volp->cellp->name, volp->namep, volp->vol[RWVOL].ID, volp->vol[ROVOL].ID, volp->vol[BACKVOL].ID, volp->flags,
+                 srvStr ? srvStr : "<none>", cbt ? cbt : "<none>", lurot ? lurot : "<none>", volp->refCount);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        if (srvStr) {
+            if (srvStrRpc)
+                RpcStringFree(&srvStr);
+            else
+                free(srvStr);
+        }
+        if (cbt)
+            free(cbt);
+        if (lurot)
+            free(lurot);
     }
     sprintf(output, "%s - Done dumping volumes.\r\n", cookie);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
index a7aecff..d3cdd48 100644 (file)
@@ -44,6 +44,7 @@ typedef struct cm_volume {
     afs_int32 refCount;                        /* by Interlocked operations */
     struct cm_server *cbServerpRO;      /* server granting RO callback; by cm_scacheLock */
     time_t cbExpiresRO;                 /* latest RO expiration time; by cm_scacheLock */
+    time_t lastUpdateRO;                /* latest RO volume update time; 0 if unknown; by cm_scacheLock */
 } cm_volume_t;
 
 #define CM_VOLUMEFLAG_RESET       1    /* reload this info on next use */