kernel - Attempt to fix lost rpc issue with NFS timeout/retry
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 2 Nov 2010 19:55:17 +0000 (12:55 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 2 Nov 2010 19:56:56 +0000 (12:56 -0700)
* An edge case in the timeout/retry code failed to pick up on
  async RPCs which are replied to while the timeout code has the
  rpc locked for retry.

Reported-by: Thomas Nikolajsen <thomas.nikolajsen@mail.dk>
sys/vfs/nfs/nfs_socket.c

index f1d7dea..c879c8b 100644 (file)
@@ -1718,13 +1718,28 @@ nfs_timer_callout(void *arg /* never used */)
                                continue;
                        if (req->r_flags & (R_SOFTTERM | R_LOCKED))
                                continue;
+
+                       /*
+                        * Handle timeout/retry.  Be sure to process r_mrep
+                        * for async requests that completed while we had
+                        * the request locked or they will hang in the reqq
+                        * forever.
+                        */
                        req->r_flags |= R_LOCKED;
                        if (nfs_sigintr(nmp, req, req->r_td)) {
                                nfs_softterm(req, 1);
+                               req->r_flags &= ~R_LOCKED;
                        } else {
                                nfs_timer_req(req);
+                               if (req->r_flags & R_ASYNC) {
+                                       if (req->r_mrep)
+                                               nfs_hardterm(req, 1);
+                                       req->r_flags &= ~R_LOCKED;
+                                       nfssvc_iod_reader_wakeup(nmp);
+                               } else {
+                                       req->r_flags &= ~R_LOCKED;
+                               }
                        }
-                       req->r_flags &= ~R_LOCKED;
                        if (req->r_flags & R_WANTED) {
                                req->r_flags &= ~R_WANTED;
                                wakeup(req);