nfsd4: skip encoder in trivial error cases
authorJ. Bruce Fields <bfields@redhat.com>
Sat, 6 May 2017 14:49:21 +0000 (10:49 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Fri, 25 Aug 2017 02:12:48 +0000 (22:12 -0400)
Most encoders do nothing in the error case.  But they can still screw
things up in that case: most errors happen very early in rpc processing,
possibly before argument fields are filled in and bounds-tested, so
encoders that do anything other than immediately bail on error can
easily crash in odd error cases.

So just handle errors centrally most of the time to remove the chance of
error.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
fs/nfsd/xdr4.h

index ac53ae2435c5b5ea047ba5e01c62bc4890ca4cac..3c69db7d4905e379487ebdec7f31c2b4670412d6 100644 (file)
@@ -2141,13 +2141,15 @@ static const struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_LOCK] = {
                .op_func = nfsd4_lock,
-               .op_flags = OP_MODIFIES_SOMETHING,
+               .op_flags = OP_MODIFIES_SOMETHING |
+                               OP_NONTRIVIAL_ERROR_ENCODE,
                .op_name = "OP_LOCK",
                .op_rsize_bop = nfsd4_lock_rsize,
                .op_set_currentstateid = nfsd4_set_lockstateid,
        },
        [OP_LOCKT] = {
                .op_func = nfsd4_lockt,
+               .op_flags = OP_NONTRIVIAL_ERROR_ENCODE,
                .op_name = "OP_LOCKT",
                .op_rsize_bop = nfsd4_lock_rsize,
        },
@@ -2277,14 +2279,16 @@ static const struct nfsd4_operation nfsd4_ops[] = {
        [OP_SETATTR] = {
                .op_func = nfsd4_setattr,
                .op_name = "OP_SETATTR",
-               .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+               .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME
+                               | OP_NONTRIVIAL_ERROR_ENCODE,
                .op_rsize_bop = nfsd4_setattr_rsize,
                .op_get_currentstateid = nfsd4_get_setattrstateid,
        },
        [OP_SETCLIENTID] = {
                .op_func = nfsd4_setclientid,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-                               | OP_MODIFIES_SOMETHING | OP_CACHEME,
+                               | OP_MODIFIES_SOMETHING | OP_CACHEME
+                               | OP_NONTRIVIAL_ERROR_ENCODE,
                .op_name = "OP_SETCLIENTID",
                .op_rsize_bop = nfsd4_setclientid_rsize,
        },
index 7d683e3aebf0945e4d4e34c23b409916e6fb7e4e..08badcf64554ab91017aa4c8ebbfd41c5dd00fdf 100644 (file)
@@ -4461,6 +4461,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
 
        if (op->opnum == OP_ILLEGAL)
                goto status;
+       if (op->status && opdesc &&
+                       !(opdesc->op_flags & OP_NONTRIVIAL_ERROR_ENCODE))
+               goto status;
        BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
               !nfsd4_enc_ops[op->opnum]);
        encoder = nfsd4_enc_ops[op->opnum];
index 1e6274e0e066616fac5e2567602b54c7c4791154..f8a0b6549a88aea36dcf9b1c36310c2c7333c2fc 100644 (file)
@@ -778,6 +778,8 @@ enum nfsd4_op_flags {
         * These are ops which clear current state id.
         */
        OP_CLEAR_STATEID = 1 << 7,
+       /* Most ops return only an error on failure; some may do more: */
+       OP_NONTRIVIAL_ERROR_ENCODE = 1 << 8,
 };
 
 struct nfsd4_operation {