viced: Add options for interrupting clients
authorAndrew Deason <adeason@sinenomine.net>
Tue, 12 Oct 2010 22:46:36 +0000 (17:46 -0500)
committerDerrick Brashear <shadow@dementia.org>
Mon, 15 Nov 2010 17:33:09 +0000 (09:33 -0800)
Add the -offline-timeout and -offline-shutdown-timeout options to the
fileserver, to implement interrupting clients accessing volumes we are
trying to take the volume offline. Document the new options.

Currently this is only implemented for read operations. Implementing
this for write operations and callback breaks will require more work.

This also removes the VGetVolumeTimed interface from the volume
package, since the fileserver was the only user and with this change
the fileserver now uses the VGetVolumeWithCall interface.

Change-Id: I2c6246d522d37dfd2fa0ecf69d6f71803b2acc03
Reviewed-on: http://gerrit.openafs.org/2984
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

doc/man-pages/pod8/fragments/dafileserver-synopsis.pod
doc/man-pages/pod8/fragments/fileserver-options.pod
doc/man-pages/pod8/fragments/fileserver-synopsis.pod
src/viced/afsfileprocs.c
src/viced/viced.c
src/vol/volume.c
src/vol/volume.h

index e86df4d..2a27cae 100644 (file)
@@ -54,3 +54,5 @@ B<dafileserver>
     S<<< [B<-vlruinterval> <I<seconds between VLRU scans>>] >>>
     S<<< [B<-vlrumax> <I<max volumes to soft detach in one VLRU scan>>] >>>
     S<<< [B<-unsafe-nosalvage>] >>>
+    S<<< [B<-offline-timeout> <I<timeout in seconds>>] >>>
+    S<<< [B<-offline-shutdown-timeout> <I<timeout in seconds>>] >>>
index fa07c1f..c703539 100644 (file)
@@ -296,3 +296,44 @@ consequences.  This option is not supported on platforms other than AIX.
 Prevents any portion of the fileserver binary from being paged (swapped)
 out of memory on a file server machine running the IRIX operating system.
 This option is not supported on platforms other than IRIX.
+
+=item B<-offline-timeout> <I<timeout in seconds>>
+
+Setting this option to I<N> means that if any clients are reading from a
+volume when we want to offline that volume (for example, as part of
+releasing a volume), we will wait I<N> seconds for the clients' request
+to finish. If the clients' requests have not finished, we will then
+interrupt the client requests and send an error to those clients,
+allowing the volume to go offline.
+
+If a client is interrupted, from the client's point of view, it will
+appear as if they had accessed the volume after it had gone offline. For
+RO volumes, this mean the client should fail-over to other valid RO
+sites for that volume. This option may speed up volume releases if
+volumes are being accessed by clients that have slow or unreliable
+network connections.
+
+Setting this option to C<0> means to interrupt clients immediately if a
+volume is waiting to go offline. Setting this option to C<-1> means to
+wait forever for client requests to finish. The default value is C<-1>.
+
+For the LWP fileserver, the only valid value for this option is C<-1>.
+
+=item B<-offline-shutdown-timeout> <I<timeout in seconds>>
+
+This option behaves similarly to B<-offline-timeout> but applies to
+volumes that are going offline as part of the fileserver shutdown
+process. If the value specified is I<N>, we will interrupt any clients
+reading from volumes after I<N> seconds have passed since we first
+needed to wait for a volume to offline during the shutdown process.
+
+Setting this option to C<0> means to interrupt all clients reading from
+volumes immediately during the shutdown process. Setting this option to
+C<-1> means to wait forever for client requests to finish during the
+shutdown process.
+
+If B<-offline-timeout> is specified, the default value of
+B<-offline-shutdown-timeout> is the value specified for
+B<-offline-timeout>. Otherwise, the default value is C<-1>.
+
+For the LWP fileserver, the only valid value for this option is C<-1>.
index 6884828..cec61e3 100644 (file)
@@ -45,3 +45,5 @@ B<fileserver>
     S<<< [B<-vattachpar> <I<number of volume attach threads>>] >>>
     S<<< [B<-m> <I<min percentage spare in partition>>] >>>
     S<<< [B<-lock>] >>>
+    S<<< [B<-offline-timeout> <I<timeout in seconds>>] >>>
+    S<<< [B<-offline-shutdown-timeout> <I<timeout in seconds>>] >>>
index 6336e1f..91f7f7b 100644 (file)
@@ -470,7 +470,8 @@ CallPostamble(struct rx_connection *aconn, afs_int32 ret,
  * are incremented and they must be eventualy released.
  */
 static afs_int32
-CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+CheckVnodeWithCall(AFSFid * fid, Volume ** volptr, struct VCallByVol *cbv,
+                   Vnode ** vptr, int lock)
 {
     Error fileCode = 0;
     Error local_errorCode, errorCode = -1;
@@ -497,7 +498,8 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
 #endif
 
            errorCode = 0;
-           *volptr = VGetVolumeTimed(&local_errorCode, &errorCode, (afs_int32) fid->Volume, ts);
+           *volptr = VGetVolumeWithCall(&local_errorCode, &errorCode,
+                                              fid->Volume, ts, cbv);
            if (!errorCode) {
                osi_Assert(*volptr);
                break;
@@ -607,6 +609,12 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
     return (0);
 }                              /*CheckVnode */
 
+static_inline afs_int32
+CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+{
+    return CheckVnodeWithCall(fid, volptr, NULL, vptr, lock);
+}
+
 /*
  * This routine returns the ACL associated with the targetptr. If the
  * targetptr isn't a directory, we access its parent dir and get the ACL
@@ -757,16 +765,16 @@ VanillaUser(struct client *client)
  * interface calls.
  */
 static afs_int32
-GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
-                Vnode ** targetptr, int chkforDir, Vnode ** parent,
-                struct client **client, int locktype, afs_int32 * rights,
-                afs_int32 * anyrights)
+GetVolumePackageWithCall(struct rx_connection *tcon, struct VCallByVol *cbv,
+                         AFSFid * Fid, Volume ** volptr, Vnode ** targetptr,
+                         int chkforDir, Vnode ** parent, struct client **client,
+                         int locktype, afs_int32 * rights, afs_int32 * anyrights)
 {
     struct acl_accessList *aCL;        /* Internal access List */
     int aCLSize;               /* size of the access list */
     Error errorCode = 0;               /* return code to caller */
 
-    if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
+    if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
        return (errorCode);
     if (chkforDir) {
        if (chkforDir == MustNOTBeDIR
@@ -807,14 +815,26 @@ GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
 
 }                              /*GetVolumePackage */
 
+static_inline afs_int32
+GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
+                Vnode ** targetptr, int chkforDir, Vnode ** parent,
+                struct client **client, int locktype, afs_int32 * rights,
+                afs_int32 * anyrights)
+{
+    return GetVolumePackageWithCall(tcon, NULL, Fid, volptr, targetptr,
+                                    chkforDir, parent, client, locktype,
+                                    rights, anyrights);
+}
+
 
 /*
  * This is the opposite of GetVolumePackage(), and is always used at the end of
  * AFS calls to put back all used vnodes and the volume in the proper order!
  */
 static void
-PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
-                Vnode * parentptr, Volume * volptr, struct client **client)
+PutVolumePackageWithCall(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+                         Vnode * parentptr, Volume * volptr,
+                         struct client **client, struct VCallByVol *cbv)
 {
     Error fileCode = 0;                /* Error code returned by the volume package */
 
@@ -831,13 +851,21 @@ PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
        osi_Assert(!fileCode || (fileCode == VSALVAGE));
     }
     if (volptr) {
-       VPutVolume(volptr);
+       VPutVolumeWithCall(volptr, cbv);
     }
     if (*client) {
        PutClient(client);
     }
 }                              /*PutVolumePackage */
 
+static_inline void
+PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+                Vnode * parentptr, Volume * volptr, struct client **client)
+{
+    PutVolumePackageWithCall(parentwhentargetnotdir, targetptr, parentptr,
+                             volptr, client, NULL);
+}
+
 static int
 VolumeOwner(struct client *client, Vnode * targetptr)
 {
@@ -2145,6 +2173,7 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
     afs_int32 rights, anyrights;       /* rights for this and any user */
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
+    struct VCallByVol tcbv, *cbv = NULL;
 #if FS_STATS_DETAILED
     struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
     struct fs_stats_xferData *xferP;   /* Ptr to this op's byte size struct */
@@ -2184,12 +2213,17 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
            ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
             Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
             ntohs(rxr_PortOf(tcon)), t_client->ViceId));
+
+    queue_NodeInit(&tcbv);
+    tcbv.call = acall;
+    cbv = &tcbv;
+
     /*
      * Get volume/vnode for the fetched file; caller's access rights to
      * it are also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackageWithCall(tcon, cbv, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_FetchData;
@@ -2327,8 +2361,8 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_FetchData:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackageWithCall(parentwhentargetnotdir, targetptr,
+                                   (Vnode *) 0, volptr, &client, cbv);
     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
@@ -7141,10 +7175,15 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
        (*a_bytesFetchedP) += nBytes;
 #endif /* FS_STATS_DETAILED */
        if (nBytes != wlen) {
+           afs_int32 err;
            FDH_CLOSE(fdP);
 #ifndef HAVE_PIOV
            FreeSendBuffer((struct afs_buffer *)tbuffer);
 #endif /* HAVE_PIOV */
+           err = VIsGoingOffline(volptr);
+           if (err) {
+               return err;
+           }
            return -31;
        }
        Len -= wlen;
index 83bb3af..4d86fe8 100644 (file)
@@ -198,6 +198,8 @@ int udpBufSize = 0;         /* UDP buffer size for receive */
 int sendBufSize = 16384;       /* send buffer size */
 int saneacls = 0;              /* Sane ACLs Flag */
 static int unsafe_attach = 0;   /* avoid inUse check on vol attach? */
+static int offline_timeout = -1; /* -offline-timeout option */
+static int offline_shutdown_timeout = -1; /* -offline-shutdown-timeout option */
 
 struct timeval tp;
 
@@ -966,6 +968,8 @@ FlagMsg(void)
     fputs("[-abortthreshold <abort threshold>] ", stdout);
     fputs("[-nojumbo (disable jumbogram network packets - deprecated)] ", stdout);
     fputs("[-jumbo (enable jumbogram network packets)] ", stdout);
+    fputs("[-offline-timeout <client RX timeout for offlining volumes>]", stdout);
+    fputs("[-offline-shutdown-timeout <RX timeout for offlining volumes during shutdown>]", stdout);
 /*   fputs("[-enable_peer_stats] ", stdout); */
 /*   fputs("[-enable_process_stats] ", stdout); */
     fputs("[-help]\n", stdout);
@@ -1443,6 +1447,45 @@ ParseArgs(int argc, char *argv[])
        else if (strcmp(argv[i], "-saneacls") == 0) {
            saneacls = 1;
        }
+       else if (strcmp(argv[i], "-offline-timeout") == 0) {
+           if (i + 1 >= argc) {
+               printf("You have to specify -offline-timeout <integer>\n");
+               return -1;
+           }
+           offline_timeout = atoi(argv[++i]);
+#ifndef AFS_PTHREAD_ENV
+           if (offline_timeout != -1) {
+               printf("The only valid -offline-timeout value for the LWP "
+                      "fileserver is -1\n");
+               return -1;
+           }
+#endif /* AFS_PTHREAD_ENV */
+           if (offline_timeout < -1) {
+               printf("Invalid -offline-timeout value %s; the only valid "
+                      "negative value is -1\n", argv[i]);
+               return -1;
+           }
+       }
+       else if (strcmp(argv[i], "-offline-shutdown-timeout") == 0) {
+           if (i + 1 >= argc) {
+               printf("You have to specify -offline-shutdown-timeout "
+                      "<integer>\n");
+               return -1;
+           }
+           offline_shutdown_timeout = atoi(argv[++i]);
+#ifndef AFS_PTHREAD_ENV
+           if (offline_shutdown_timeout != -1) {
+               printf("The only valid -offline-shutdown-timeout value for the "
+                      "LWP fileserver is -1\n");
+               return -1;
+           }
+#endif /* AFS_PTHREAD_ENV */
+           if (offline_shutdown_timeout < -1) {
+               printf("Invalid -offline-timeout value %s; the only valid "
+                      "negative value is -1\n", argv[i]);
+               return -1;
+           }
+       }
        else {
            return (-1);
        }
@@ -2252,6 +2295,18 @@ main(int argc, char *argv[])
     opts.nSmallVnodes = nSmallVns;
     opts.volcache = volcache;
     opts.unsafe_attach = unsafe_attach;
+    if (offline_timeout != -1) {
+       opts.interrupt_rxcall = rx_InterruptCall;
+       opts.offline_timeout = offline_timeout;
+    }
+    if (offline_shutdown_timeout == -1) {
+       /* default to -offline-timeout, if shutdown-specific timeout is not
+        * specified */
+       opts.offline_shutdown_timeout = offline_timeout;
+    } else {
+       opts.interrupt_rxcall = rx_InterruptCall;
+       opts.offline_shutdown_timeout = offline_shutdown_timeout;
+    }
 
     if (VInitVolumePackage2(fileServer, &opts)) {
        ViceLog(0,
index 1d639ba..20e5426 100644 (file)
@@ -3862,20 +3862,6 @@ VGetVolume(Error * ec, Error * client_ec, VolId volumeId)
     return retVal;
 }
 
-/* same as VGetVolume, but if a volume is waiting to go offline, we only wait
- * until time ts. If we have waited longer than that, we return that it is
- * actually offline, instead of waiting for it to go offline */
-Volume *
-VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId,
-                const struct timespec *ts)
-{
-    Volume *retVal;
-    VOL_LOCK;
-    retVal = GetVolume(ec, client_ec, volumeId, NULL, ts);
-    VOL_UNLOCK;
-    return retVal;
-}
-
 /**
  * Get a volume reference associated with an RX call.
  *
index e3d6c7b..1bc2cde 100644 (file)
@@ -829,8 +829,6 @@ struct volHeader {
 extern char *VSalvageMessage;  /* Canonical message when a volume is forced
                                 * offline */
 extern Volume *VGetVolume(Error * ec, Error * client_ec, VolId volumeId);
-extern Volume *VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId,
-                               const struct timespec *ts);
 extern Volume *VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId,
                                   const struct timespec *ts, struct VCallByVol *cbv);
 extern Volume *VGetVolume_r(Error * ec, VolId volumeId);