Merge branch 'for-3.5/core' of git://git.kernel.dk/linux-block
[linux-block.git] / fs / nfs / nfs4xdr.c
index c54aae364beebd38833151f97328c3edfe7c2337..ee4a74db95d0b1b7ea49e8dd1263f0504f2fffa8 100644 (file)
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_idmap.h>
+
 #include "nfs4_fs.h"
 #include "internal.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
 
@@ -99,9 +101,12 @@ static int nfs4_stat_to_errno(int);
 #define nfs4_path_maxsz                (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
 #define nfs4_owner_maxsz       (1 + XDR_QUADLEN(IDMAP_NAMESZ))
 #define nfs4_group_maxsz       (1 + XDR_QUADLEN(IDMAP_NAMESZ))
+/* We support only one layout type per file system */
+#define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
 /* This is based on getfattr, which uses the most attributes: */
 #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
-                               3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
+                               3 + 3 + 3 + nfs4_owner_maxsz + \
+                               nfs4_group_maxsz + decode_mdsthreshold_maxsz))
 #define nfs4_fattr_maxsz       (nfs4_fattr_bitmap_maxsz + \
                                nfs4_fattr_value_maxsz)
 #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
@@ -321,8 +326,20 @@ static int nfs4_stat_to_errno(int);
                                     1 /* csr_flags */ + \
                                     decode_channel_attrs_maxsz + \
                                     decode_channel_attrs_maxsz)
+#define encode_bind_conn_to_session_maxsz  (op_encode_hdr_maxsz + \
+                                    /* bctsa_sessid */ \
+                                    XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
+                                    1 /* bctsa_dir */ + \
+                                    1 /* bctsa_use_conn_in_rdma_mode */)
+#define decode_bind_conn_to_session_maxsz  (op_decode_hdr_maxsz +      \
+                                    /* bctsr_sessid */ \
+                                    XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
+                                    1 /* bctsr_dir */ + \
+                                    1 /* bctsr_use_conn_in_rdma_mode */)
 #define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
 #define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
+#define encode_destroy_clientid_maxsz   (op_encode_hdr_maxsz + 2)
+#define decode_destroy_clientid_maxsz   (op_decode_hdr_maxsz)
 #define encode_sequence_maxsz  (op_encode_hdr_maxsz + \
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
 #define decode_sequence_maxsz  (op_decode_hdr_maxsz + \
@@ -421,30 +438,22 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_enc_commit_sz     (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_commit_maxsz + \
-                               encode_getattr_maxsz)
+                               encode_commit_maxsz)
 #define NFS4_dec_commit_sz     (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_commit_maxsz + \
-                               decode_getattr_maxsz)
+                               decode_commit_maxsz)
 #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_savefh_maxsz + \
                                encode_open_maxsz + \
                                encode_getfh_maxsz + \
-                               encode_getattr_maxsz + \
-                               encode_restorefh_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_savefh_maxsz + \
                                decode_open_maxsz + \
                                decode_getfh_maxsz + \
-                               decode_getattr_maxsz + \
-                               decode_restorefh_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_open_confirm_sz \
                                (compound_encode_hdr_maxsz + \
@@ -595,47 +604,37 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_enc_remove_sz     (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_remove_maxsz + \
-                               encode_getattr_maxsz)
+                               encode_remove_maxsz)
 #define NFS4_dec_remove_sz     (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_remove_maxsz + \
-                               decode_getattr_maxsz)
+                               decode_remove_maxsz)
 #define NFS4_enc_rename_sz     (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
                                encode_savefh_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_rename_maxsz + \
-                               encode_getattr_maxsz + \
-                               encode_restorefh_maxsz + \
-                               encode_getattr_maxsz)
+                               encode_rename_maxsz)
 #define NFS4_dec_rename_sz     (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
                                decode_savefh_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_rename_maxsz + \
-                               decode_getattr_maxsz + \
-                               decode_restorefh_maxsz + \
-                               decode_getattr_maxsz)
+                               decode_rename_maxsz)
 #define NFS4_enc_link_sz       (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
                                encode_savefh_maxsz + \
                                encode_putfh_maxsz + \
                                encode_link_maxsz + \
-                               decode_getattr_maxsz + \
                                encode_restorefh_maxsz + \
-                               decode_getattr_maxsz)
+                               encode_getattr_maxsz)
 #define NFS4_dec_link_sz       (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
                                decode_savefh_maxsz + \
                                decode_putfh_maxsz + \
                                decode_link_maxsz + \
-                               decode_getattr_maxsz + \
                                decode_restorefh_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_symlink_sz    (compound_encode_hdr_maxsz + \
@@ -653,20 +652,14 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_enc_create_sz     (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_savefh_maxsz + \
                                encode_create_maxsz + \
                                encode_getfh_maxsz + \
-                               encode_getattr_maxsz + \
-                               encode_restorefh_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_create_sz     (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_savefh_maxsz + \
                                decode_create_maxsz + \
                                decode_getfh_maxsz + \
-                               decode_getattr_maxsz + \
-                               decode_restorefh_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_pathconf_sz   (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
@@ -738,6 +731,12 @@ static int nfs4_stat_to_errno(int);
                                decode_putfh_maxsz + \
                                decode_secinfo_maxsz)
 #if defined(CONFIG_NFS_V4_1)
+#define NFS4_enc_bind_conn_to_session_sz \
+                               (compound_encode_hdr_maxsz + \
+                                encode_bind_conn_to_session_maxsz)
+#define NFS4_dec_bind_conn_to_session_sz \
+                               (compound_decode_hdr_maxsz + \
+                                decode_bind_conn_to_session_maxsz)
 #define NFS4_enc_exchange_id_sz \
                                (compound_encode_hdr_maxsz + \
                                 encode_exchange_id_maxsz)
@@ -754,6 +753,10 @@ static int nfs4_stat_to_errno(int);
                                         encode_destroy_session_maxsz)
 #define NFS4_dec_destroy_session_sz    (compound_decode_hdr_maxsz + \
                                         decode_destroy_session_maxsz)
+#define NFS4_enc_destroy_clientid_sz   (compound_encode_hdr_maxsz + \
+                                        encode_destroy_clientid_maxsz)
+#define NFS4_dec_destroy_clientid_sz   (compound_decode_hdr_maxsz + \
+                                        decode_destroy_clientid_maxsz)
 #define NFS4_enc_sequence_sz \
                                (compound_decode_hdr_maxsz + \
                                 encode_sequence_maxsz)
@@ -1103,7 +1106,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg
        encode_nfs4_stateid(xdr, arg->stateid);
 }
 
-static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
+static void encode_commit(struct xdr_stream *xdr, const struct nfs_commitargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
@@ -1194,6 +1197,16 @@ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct c
                           bitmask[1] & nfs4_fattr_bitmap[1], hdr);
 }
 
+static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
+                                struct compound_hdr *hdr)
+{
+       encode_getattr_three(xdr,
+                            bitmask[0] & nfs4_fattr_bitmap[0],
+                            bitmask[1] & nfs4_fattr_bitmap[1],
+                            bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD,
+                            hdr);
+}
+
 static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
        encode_getattr_three(xdr,
@@ -1678,6 +1691,20 @@ static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, stru
 
 #if defined(CONFIG_NFS_V4_1)
 /* NFSv4.1 operations */
+static void encode_bind_conn_to_session(struct xdr_stream *xdr,
+                                  struct nfs4_session *session,
+                                  struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       encode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION,
+               decode_bind_conn_to_session_maxsz, hdr);
+       encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
+       p = xdr_reserve_space(xdr, 8);
+       *p++ = cpu_to_be32(NFS4_CDFC4_BACK_OR_BOTH);
+       *p = 0; /* use_conn_in_rdma_mode = False */
+}
+
 static void encode_exchange_id(struct xdr_stream *xdr,
                               struct nfs41_exchange_id_args *args,
                               struct compound_hdr *hdr)
@@ -1726,6 +1753,7 @@ static void encode_create_session(struct xdr_stream *xdr,
        char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
        uint32_t len;
        struct nfs_client *clp = args->client;
+       struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
        u32 max_resp_sz_cached;
 
        /*
@@ -1767,7 +1795,7 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(RPC_AUTH_UNIX);                      /* auth_sys */
 
        /* authsys_parms rfc1831 */
-       *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);     /* stamp */
+       *p++ = (__be32)nn->boot_time.tv_nsec;           /* stamp */
        p = xdr_encode_opaque(p, machine_name, len);
        *p++ = cpu_to_be32(0);                          /* UID */
        *p++ = cpu_to_be32(0);                          /* GID */
@@ -1782,6 +1810,14 @@ static void encode_destroy_session(struct xdr_stream *xdr,
        encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
 }
 
+static void encode_destroy_clientid(struct xdr_stream *xdr,
+                                  uint64_t clientid,
+                                  struct compound_hdr *hdr)
+{
+       encode_op_hdr(xdr, OP_DESTROY_CLIENTID, decode_destroy_clientid_maxsz, hdr);
+       encode_uint64(xdr, clientid);
+}
+
 static void encode_reclaim_complete(struct xdr_stream *xdr,
                                    struct nfs41_reclaim_complete_args *args,
                                    struct compound_hdr *hdr)
@@ -2064,7 +2100,6 @@ static void nfs4_xdr_enc_remove(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        encode_remove(xdr, &args->name, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2084,9 +2119,6 @@ static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_savefh(xdr, &hdr);
        encode_putfh(xdr, args->new_dir, &hdr);
        encode_rename(xdr, args->old_name, args->new_name, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
-       encode_restorefh(xdr, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2106,7 +2138,6 @@ static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_savefh(xdr, &hdr);
        encode_putfh(xdr, args->dir_fh, &hdr);
        encode_link(xdr, args->name, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
        encode_restorefh(xdr, &hdr);
        encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
@@ -2125,12 +2156,9 @@ static void nfs4_xdr_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->dir_fh, &hdr);
-       encode_savefh(xdr, &hdr);
        encode_create(xdr, args, &hdr);
        encode_getfh(xdr, &hdr);
        encode_getfattr(xdr, args->bitmask, &hdr);
-       encode_restorefh(xdr, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2191,12 +2219,9 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
-       encode_savefh(xdr, &hdr);
        encode_open(xdr, args, &hdr);
        encode_getfh(xdr, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
-       encode_restorefh(xdr, &hdr);
-       encode_getfattr(xdr, args->dir_bitmask, &hdr);
+       encode_getfattr_open(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2448,7 +2473,7 @@ static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
  *  a COMMIT request
  */
 static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs_writeargs *args)
+                               struct nfs_commitargs *args)
 {
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
@@ -2458,8 +2483,6 @@ static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        encode_commit(xdr, args, &hdr);
-       if (args->bitmask)
-               encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2602,8 +2625,8 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fhandle, &hdr);
-       encode_delegreturn(xdr, args->stateid, &hdr);
        encode_getfattr(xdr, args->bitmask, &hdr);
+       encode_delegreturn(xdr, args->stateid, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2650,6 +2673,22 @@ static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ * BIND_CONN_TO_SESSION request
+ */
+static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req,
+                               struct xdr_stream *xdr,
+                               struct nfs_client *clp)
+{
+       struct compound_hdr hdr = {
+               .minorversion = clp->cl_mvops->minor_version,
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_bind_conn_to_session(xdr, clp->cl_session, &hdr);
+       encode_nops(&hdr);
+}
+
 /*
  * EXCHANGE_ID request
  */
@@ -2698,6 +2737,22 @@ static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+/*
+ * a DESTROY_CLIENTID request
+ */
+static void nfs4_xdr_enc_destroy_clientid(struct rpc_rqst *req,
+                                        struct xdr_stream *xdr,
+                                        struct nfs_client *clp)
+{
+       struct compound_hdr hdr = {
+               .minorversion = clp->cl_mvops->minor_version,
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_destroy_clientid(xdr, clp->cl_clientid, &hdr);
+       encode_nops(&hdr);
+}
+
 /*
  * a SEQUENCE request
  */
@@ -4102,7 +4157,7 @@ static int decode_verifier(struct xdr_stream *xdr, void *verifier)
        return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
-static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
+static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
 {
        int status;
 
@@ -4220,6 +4275,110 @@ xdr_error:
        return status;
 }
 
+static int decode_threshold_hint(struct xdr_stream *xdr,
+                                 uint32_t *bitmap,
+                                 uint64_t *res,
+                                 uint32_t hint_bit)
+{
+       __be32 *p;
+
+       *res = 0;
+       if (likely(bitmap[0] & hint_bit)) {
+               p = xdr_inline_decode(xdr, 8);
+               if (unlikely(!p))
+                       goto out_overflow;
+               xdr_decode_hyper(p, res);
+       }
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
+static int decode_first_threshold_item4(struct xdr_stream *xdr,
+                                       struct nfs4_threshold *res)
+{
+       __be32 *p, *savep;
+       uint32_t bitmap[3] = {0,}, attrlen;
+       int status;
+
+       /* layout type */
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p)) {
+               print_overflow_msg(__func__, xdr);
+               return -EIO;
+       }
+       res->l_type = be32_to_cpup(p);
+
+       /* thi_hintset bitmap */
+       status = decode_attr_bitmap(xdr, bitmap);
+       if (status < 0)
+               goto xdr_error;
+
+       /* thi_hintlist length */
+       status = decode_attr_length(xdr, &attrlen, &savep);
+       if (status < 0)
+               goto xdr_error;
+       /* thi_hintlist */
+       status = decode_threshold_hint(xdr, bitmap, &res->rd_sz, THRESHOLD_RD);
+       if (status < 0)
+               goto xdr_error;
+       status = decode_threshold_hint(xdr, bitmap, &res->wr_sz, THRESHOLD_WR);
+       if (status < 0)
+               goto xdr_error;
+       status = decode_threshold_hint(xdr, bitmap, &res->rd_io_sz,
+                                      THRESHOLD_RD_IO);
+       if (status < 0)
+               goto xdr_error;
+       status = decode_threshold_hint(xdr, bitmap, &res->wr_io_sz,
+                                      THRESHOLD_WR_IO);
+       if (status < 0)
+               goto xdr_error;
+
+       status = verify_attr_len(xdr, savep, attrlen);
+       res->bm = bitmap[0];
+
+       dprintk("%s bm=0x%x rd_sz=%llu wr_sz=%llu rd_io=%llu wr_io=%llu\n",
+                __func__, res->bm, res->rd_sz, res->wr_sz, res->rd_io_sz,
+               res->wr_io_sz);
+xdr_error:
+       dprintk("%s ret=%d!\n", __func__, status);
+       return status;
+}
+
+/*
+ * Thresholds on pNFS direct I/O vrs MDS I/O
+ */
+static int decode_attr_mdsthreshold(struct xdr_stream *xdr,
+                                   uint32_t *bitmap,
+                                   struct nfs4_threshold *res)
+{
+       __be32 *p;
+       int status = 0;
+       uint32_t num;
+
+       if (unlikely(bitmap[2] & (FATTR4_WORD2_MDSTHRESHOLD - 1U)))
+               return -EIO;
+       if (likely(bitmap[2] & FATTR4_WORD2_MDSTHRESHOLD)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               num = be32_to_cpup(p);
+               if (num == 0)
+                       return 0;
+               if (num > 1)
+                       printk(KERN_INFO "%s: Warning: Multiple pNFS layout "
+                               "drivers per filesystem not supported\n",
+                               __func__);
+
+               status = decode_first_threshold_item4(xdr, res);
+       }
+       return status;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                struct nfs_fattr *fattr, struct nfs_fh *fh,
                struct nfs4_fs_locations *fs_loc,
@@ -4326,6 +4485,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
+       status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold);
+       if (status < 0)
+               goto xdr_error;
+
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
        return status;
@@ -5156,7 +5319,6 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        uint32_t dummy;
        char *dummy_str;
        int status;
-       struct nfs_client *clp = res->client;
        uint32_t impl_id_count;
 
        status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
@@ -5166,36 +5328,39 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        p = xdr_inline_decode(xdr, 8);
        if (unlikely(!p))
                goto out_overflow;
-       xdr_decode_hyper(p, &clp->cl_clientid);
+       xdr_decode_hyper(p, &res->clientid);
        p = xdr_inline_decode(xdr, 12);
        if (unlikely(!p))
                goto out_overflow;
-       clp->cl_seqid = be32_to_cpup(p++);
-       clp->cl_exchange_flags = be32_to_cpup(p++);
+       res->seqid = be32_to_cpup(p++);
+       res->flags = be32_to_cpup(p++);
 
        /* We ask for SP4_NONE */
        dummy = be32_to_cpup(p);
        if (dummy != SP4_NONE)
                return -EIO;
 
-       /* Throw away minor_id */
+       /* server_owner4.so_minor_id */
        p = xdr_inline_decode(xdr, 8);
        if (unlikely(!p))
                goto out_overflow;
+       p = xdr_decode_hyper(p, &res->server_owner->minor_id);
 
-       /* Throw away Major id */
+       /* server_owner4.so_major_id */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
+       if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+               return -EIO;
+       memcpy(res->server_owner->major_id, dummy_str, dummy);
+       res->server_owner->major_id_sz = dummy;
 
-       /* Save server_scope */
+       /* server_scope4 */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
-
        if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
                return -EIO;
-
        memcpy(res->server_scope->server_scope, dummy_str, dummy);
        res->server_scope->server_scope_sz = dummy;
 
@@ -5276,6 +5441,37 @@ static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid)
        return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN);
 }
 
+static int decode_bind_conn_to_session(struct xdr_stream *xdr,
+                               struct nfs41_bind_conn_to_session_res *res)
+{
+       __be32 *p;
+       int status;
+
+       status = decode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION);
+       if (!status)
+               status = decode_sessionid(xdr, &res->session->sess_id);
+       if (unlikely(status))
+               return status;
+
+       /* dir flags, rdma mode bool */
+       p = xdr_inline_decode(xdr, 8);
+       if (unlikely(!p))
+               goto out_overflow;
+
+       res->dir = be32_to_cpup(p++);
+       if (res->dir == 0 || res->dir > NFS4_CDFS4_BOTH)
+               return -EIO;
+       if (be32_to_cpup(p) == 0)
+               res->use_conn_in_rdma_mode = false;
+       else
+               res->use_conn_in_rdma_mode = true;
+
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_create_session(struct xdr_stream *xdr,
                                 struct nfs41_create_session_res *res)
 {
@@ -5312,6 +5508,11 @@ static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
        return decode_op_hdr(xdr, OP_DESTROY_SESSION);
 }
 
+static int decode_destroy_clientid(struct xdr_stream *xdr, void *dummy)
+{
+       return decode_op_hdr(xdr, OP_DESTROY_CLIENTID);
+}
+
 static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
 {
        return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
@@ -5800,9 +6001,6 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        status = decode_remove(xdr, &res->cinfo);
-       if (status)
-               goto out;
-       decode_getfattr(xdr, res->dir_attr, res->server);
 out:
        return status;
 }
@@ -5832,15 +6030,6 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        status = decode_rename(xdr, &res->old_cinfo, &res->new_cinfo);
-       if (status)
-               goto out;
-       /* Current FH is target directory */
-       if (decode_getfattr(xdr, res->new_fattr, res->server))
-               goto out;
-       status = decode_restorefh(xdr);
-       if (status)
-               goto out;
-       decode_getfattr(xdr, res->old_fattr, res->server);
 out:
        return status;
 }
@@ -5876,8 +6065,6 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
         * Note order: OP_LINK leaves the directory as the current
         *             filehandle.
         */
-       if (decode_getfattr(xdr, res->dir_attr, res->server))
-               goto out;
        status = decode_restorefh(xdr);
        if (status)
                goto out;
@@ -5902,9 +6089,6 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        status = decode_putfh(xdr);
-       if (status)
-               goto out;
-       status = decode_savefh(xdr);
        if (status)
                goto out;
        status = decode_create(xdr, &res->dir_cinfo);
@@ -5913,12 +6097,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_getfh(xdr, res->fh);
        if (status)
                goto out;
-       if (decode_getfattr(xdr, res->fattr, res->server))
-               goto out;
-       status = decode_restorefh(xdr);
-       if (status)
-               goto out;
-       decode_getfattr(xdr, res->dir_fattr, res->server);
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6073,9 +6252,6 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        status = decode_putfh(xdr);
-       if (status)
-               goto out;
-       status = decode_savefh(xdr);
        if (status)
                goto out;
        status = decode_open(xdr, res);
@@ -6083,11 +6259,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
                goto out;
        if (decode_getfh(xdr, &res->fh) != 0)
                goto out;
-       if (decode_getfattr(xdr, res->f_attr, res->server) != 0)
-               goto out;
-       if (decode_restorefh(xdr) != 0)
-               goto out;
-       decode_getfattr(xdr, res->dir_attr, res->server);
+       decode_getfattr(xdr, res->f_attr, res->server);
 out:
        return status;
 }
@@ -6353,7 +6525,7 @@ out:
  * Decode COMMIT response
  */
 static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs_writeres *res)
+                              struct nfs_commitres *res)
 {
        struct compound_hdr hdr;
        int status;
@@ -6368,10 +6540,6 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        status = decode_commit(xdr, res);
-       if (status)
-               goto out;
-       if (res->fattr)
-               decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6527,10 +6695,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
        status = decode_putfh(xdr);
        if (status != 0)
                goto out;
-       status = decode_delegreturn(xdr);
+       status = decode_getfattr(xdr, res->fattr, res->server);
        if (status != 0)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server);
+       status = decode_delegreturn(xdr);
 out:
        return status;
 }
@@ -6590,6 +6758,22 @@ out:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ * Decode BIND_CONN_TO_SESSION response
+ */
+static int nfs4_xdr_dec_bind_conn_to_session(struct rpc_rqst *rqstp,
+                                       struct xdr_stream *xdr,
+                                       void *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (!status)
+               status = decode_bind_conn_to_session(xdr, res);
+       return status;
+}
+
 /*
  * Decode EXCHANGE_ID response
  */
@@ -6638,6 +6822,22 @@ static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp,
        return status;
 }
 
+/*
+ * Decode DESTROY_CLIENTID response
+ */
+static int nfs4_xdr_dec_destroy_clientid(struct rpc_rqst *rqstp,
+                                       struct xdr_stream *xdr,
+                                       void *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (!status)
+               status = decode_destroy_clientid(xdr, res);
+       return status;
+}
+
 /*
  * Decode SEQUENCE response
  */
@@ -7085,6 +7285,9 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(TEST_STATEID,      enc_test_stateid,       dec_test_stateid),
        PROC(FREE_STATEID,      enc_free_stateid,       dec_free_stateid),
        PROC(GETDEVICELIST,     enc_getdevicelist,      dec_getdevicelist),
+       PROC(BIND_CONN_TO_SESSION,
+                       enc_bind_conn_to_session, dec_bind_conn_to_session),
+       PROC(DESTROY_CLIENTID,  enc_destroy_clientid,   dec_destroy_clientid),
 #endif /* CONFIG_NFS_V4_1 */
 };