NFSv4: Retry the DELEGRETURN if the embedded GETATTR is rejected with EACCES
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 19 Dec 2016 15:23:10 +0000 (10:23 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 19 Dec 2016 22:30:03 +0000 (17:30 -0500)
If our DELEGRETURN RPC call is rejected with an EACCES call, then we should
remove the GETATTR call from the compound RPC and retry.
This could potentially happen when there is a conflict between an
ACL denying attribute reads and our use of SP4_MACH_CRED.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c

index 4b66b0c469cd18bc1a7f1e74bce47794b223e695..6dcbc5defb7a8dd670b63995eb553c379e47a0d4 100644 (file)
@@ -5695,6 +5695,14 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_STALE_STATEID:
                task->tk_status = 0;
                break;
+       case -NFS4ERR_ACCESS:
+               if (data->args.bitmask) {
+                       data->args.bitmask = NULL;
+                       data->res.fattr = NULL;
+                       task->tk_status = 0;
+                       rpc_restart_call_prepare(task);
+                       return;
+               }
        default:
                if (nfs4_async_handle_error(task, data->res.server,
                                            NULL, NULL) == -EAGAIN) {
index 6f2365b99fb441959ac856e10a01ba2414abcdcd..e9255cb453e664c385c9a94969f69bc3514024b1 100644 (file)
@@ -2705,7 +2705,8 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
        encode_putfh(xdr, args->fhandle, &hdr);
        if (args->lr_args)
                encode_layoutreturn(xdr, args->lr_args, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       if (args->bitmask)
+               encode_getfattr(xdr, args->bitmask, &hdr);
        encode_delegreturn(xdr, args->stateid, &hdr);
        encode_nops(&hdr);
 }
@@ -6972,9 +6973,11 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
                if (status)
                        goto out;
        }
-       status = decode_getfattr(xdr, res->fattr, res->server);
-       if (status != 0)
-               goto out;
+       if (res->fattr) {
+               status = decode_getfattr(xdr, res->fattr, res->server);
+               if (status != 0)
+                       goto out;
+       }
        status = decode_delegreturn(xdr);
 out:
        return status;