SUNRPC: Fix an infinite loop in call_refresh/call_refreshresult
Trond Myklebust [Sat, 20 Nov 2010 16:13:31 +0000 (11:13 -0500)]
If the rpcauth_refreshcred() call returns an error other than
EACCES, ENOMEM or ETIMEDOUT, we currently end up looping forever
between call_refresh and call_refreshresult.

The correct thing to do here is to exit on all errors except
EAGAIN and ETIMEDOUT, for which case we retry 3 times, then
return EACCES.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

net/sunrpc/clnt.c

index 9dab957..92ce94f 100644 (file)
@@ -989,20 +989,26 @@ call_refreshresult(struct rpc_task *task)
        dprint_status(task);
 
        task->tk_status = 0;
-       task->tk_action = call_allocate;
-       if (status >= 0 && rpcauth_uptodatecred(task))
-               return;
+       task->tk_action = call_refresh;
        switch (status) {
-       case -EACCES:
-               rpc_exit(task, -EACCES);
-               return;
-       case -ENOMEM:
-               rpc_exit(task, -ENOMEM);
+       case 0:
+               if (rpcauth_uptodatecred(task))
+                       task->tk_action = call_allocate;
                return;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
+       case -EAGAIN:
+               status = -EACCES;
+               if (!task->tk_cred_retry)
+                       break;
+               task->tk_cred_retry--;
+               dprintk("RPC: %5u %s: retry refresh creds\n",
+                               task->tk_pid, __func__);
+               return;
        }
-       task->tk_action = call_refresh;
+       dprintk("RPC: %5u %s: refresh creds failed with error %d\n",
+                               task->tk_pid, __func__, status);
+       rpc_exit(task, status);
 }
 
 /*