CIFS: SMBD: Upper layer performs SMB write via RDMA read through memory registration
[sfrench/cifs-2.6.git] / fs / cifs / smb2pdu.c
index 544daec74de032fd70bbd401f7259a5ef9ba9557..908d7770d15a316c48604eeadf48abfd52e160da 100644 (file)
@@ -48,6 +48,7 @@
 #include "smb2glob.h"
 #include "cifspdu.h"
 #include "cifs_spnego.h"
+#include "smbdirect.h"
 
 /*
  *  The following table defines the expected "StructureSize" of SMB2 requests
@@ -319,54 +320,16 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
        *total_len = parmsize + sizeof(struct smb2_sync_hdr);
 }
 
-/* init request without RFC1001 length at the beginning */
-static int
-smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
-                   void **request_buf, unsigned int *total_len)
-{
-       int rc;
-       struct smb2_sync_hdr *shdr;
-
-       rc = smb2_reconnect(smb2_command, tcon);
-       if (rc)
-               return rc;
-
-       /* BB eventually switch this to SMB2 specific small buf size */
-       *request_buf = cifs_small_buf_get();
-       if (*request_buf == NULL) {
-               /* BB should we add a retry in here if not a writepage? */
-               return -ENOMEM;
-       }
-
-       shdr = (struct smb2_sync_hdr *)(*request_buf);
-
-       fill_small_buf(smb2_command, tcon, shdr, total_len);
-
-       if (tcon != NULL) {
-#ifdef CONFIG_CIFS_STATS2
-               uint16_t com_code = le16_to_cpu(smb2_command);
-
-               cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
-#endif
-               cifs_stats_inc(&tcon->num_smbs_sent);
-       }
-
-       return rc;
-}
-
 /*
  * Allocate and return pointer to an SMB request hdr, and set basic
  * SMB information in the SMB header. If the return code is zero, this
- * function must have filled in request_buf pointer. The returned buffer
- * has RFC1001 length at the beginning.
+ * function must have filled in request_buf pointer.
  */
 static int
-small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
-               void **request_buf)
+smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+                   void **request_buf, unsigned int *total_len)
 {
        int rc;
-       unsigned int total_len;
-       struct smb2_pdu *pdu;
 
        rc = smb2_reconnect(smb2_command, tcon);
        if (rc)
@@ -379,12 +342,9 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
                return -ENOMEM;
        }
 
-       pdu = (struct smb2_pdu *)(*request_buf);
-
-       fill_small_buf(smb2_command, tcon, get_sync_hdr(pdu), &total_len);
-
-       /* Note this is only network field converted to big endian */
-       pdu->hdr.smb2_buf_length = cpu_to_be32(total_len);
+       fill_small_buf(smb2_command, tcon,
+                      (struct smb2_sync_hdr *)(*request_buf),
+                      total_len);
 
        if (tcon != NULL) {
 #ifdef CONFIG_CIFS_STATS2
@@ -1525,11 +1485,10 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
        req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
        if (!req->CreateContextsOffset)
                req->CreateContextsOffset = cpu_to_le32(
-                               sizeof(struct smb2_create_req) - 4 +
+                               sizeof(struct smb2_create_req) +
                                iov[num - 1].iov_len);
        le32_add_cpu(&req->CreateContextsLength,
                     server->vals->create_lease_size);
-       inc_rfc1001_len(&req->hdr, server->vals->create_lease_size);
        *num_iovec = num + 1;
        return 0;
 }
@@ -1609,10 +1568,9 @@ add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
        iov[num].iov_len = sizeof(struct create_durable_v2);
        if (!req->CreateContextsOffset)
                req->CreateContextsOffset =
-                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                       cpu_to_le32(sizeof(struct smb2_create_req) +
                                                                iov[1].iov_len);
        le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
-       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2));
        *num_iovec = num + 1;
        return 0;
 }
@@ -1633,12 +1591,10 @@ add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
        iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
        if (!req->CreateContextsOffset)
                req->CreateContextsOffset =
-                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                       cpu_to_le32(sizeof(struct smb2_create_req) +
                                                                iov[1].iov_len);
        le32_add_cpu(&req->CreateContextsLength,
                        sizeof(struct create_durable_handle_reconnect_v2));
-       inc_rfc1001_len(&req->hdr,
-                       sizeof(struct create_durable_handle_reconnect_v2));
        *num_iovec = num + 1;
        return 0;
 }
@@ -1669,10 +1625,9 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
        iov[num].iov_len = sizeof(struct create_durable);
        if (!req->CreateContextsOffset)
                req->CreateContextsOffset =
-                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                       cpu_to_le32(sizeof(struct smb2_create_req) +
                                                                iov[1].iov_len);
        le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable));
-       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable));
        *num_iovec = num + 1;
        return 0;
 }
@@ -1743,6 +1698,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        __u32 file_attributes = 0;
        char *dhc_buf = NULL, *lc_buf = NULL;
        int flags = 0;
+       unsigned int total_len;
 
        cifs_dbg(FYI, "create/open\n");
 
@@ -1751,7 +1707,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        else
                return -EIO;
 
-       rc = small_smb2_init(SMB2_CREATE, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
+
        if (rc)
                return rc;
 
@@ -1772,12 +1729,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
 
        iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field */
-       iov[0].iov_len = get_rfc1002_length(req) + 4;
        /* -1 since last byte is buf[0] which is sent below (path) */
-       iov[0].iov_len--;
+       iov[0].iov_len = total_len - 1;
 
-       req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4);
+       req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
 
        /* [MS-SMB2] 2.2.13 NameOffset:
         * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
@@ -1790,7 +1745,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        if (tcon->share_flags & SHI1005_FLAGS_DFS) {
                int name_len;
 
-               req->hdr.sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
+               req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
                rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
                                                 &name_len,
                                                 tcon->treeName, path);
@@ -1817,8 +1772,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 
        iov[1].iov_len = uni_path_len;
        iov[1].iov_base = path;
-       /* -1 since last byte is buf[0] which was counted in smb2_buf_len */
-       inc_rfc1001_len(req, uni_path_len - 1);
 
        if (!server->oplocks)
                *oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -1856,7 +1809,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                dhc_buf = iov[n_iov-1].iov_base;
        }
 
-       rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags,
+                           &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
 
@@ -2200,13 +2154,15 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        int resp_buftype;
        struct cifs_ses *ses = tcon->ses;
        int flags = 0;
+       unsigned int total_len;
 
        cifs_dbg(FYI, "Query Info\n");
 
        if (!ses || !(ses->server))
                return -EIO;
 
-       rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
@@ -2223,15 +2179,14 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
         * We do not use the input buffer (do not send extra byte)
         */
        req->InputBufferOffset = 0;
-       inc_rfc1001_len(req, -1);
 
        req->OutputBufferLength = cpu_to_le32(output_len);
 
        iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field */
-       iov[0].iov_len = get_rfc1002_length(req) + 4;
+       /* 1 for Buffer */
+       iov[0].iov_len = total_len - 1;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
@@ -2439,13 +2394,14 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        int resp_buftype;
        int rc = 0;
        int flags = 0;
+       unsigned int total_len;
 
        cifs_dbg(FYI, "Flush\n");
 
        if (!ses || !(ses->server))
                return -EIO;
 
-       rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_FLUSH, tcon, (void **) &req, &total_len);
        if (rc)
                return rc;
 
@@ -2456,10 +2412,9 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        req->VolatileFileId = volatile_fid;
 
        iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field */
-       iov[0].iov_len = get_rfc1002_length(req) + 4;
+       iov[0].iov_len = total_len;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc != 0)
@@ -2475,18 +2430,21 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
  */
 static int
 smb2_new_read_req(void **buf, unsigned int *total_len,
-                 struct cifs_io_parms *io_parms, unsigned int remaining_bytes,
-                 int request_type)
+       struct cifs_io_parms *io_parms, struct cifs_readdata *rdata,
+       unsigned int remaining_bytes, int request_type)
 {
        int rc = -EACCES;
        struct smb2_read_plain_req *req = NULL;
        struct smb2_sync_hdr *shdr;
+       struct TCP_Server_Info *server;
 
        rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req,
                                 total_len);
        if (rc)
                return rc;
-       if (io_parms->tcon->ses->server == NULL)
+
+       server = io_parms->tcon->ses->server;
+       if (server == NULL)
                return -ECONNABORTED;
 
        shdr = &req->sync_hdr;
@@ -2614,7 +2572,8 @@ smb2_async_readv(struct cifs_readdata *rdata)
 
        server = io_parms.tcon->ses->server;
 
-       rc = smb2_new_read_req((void **) &buf, &total_len, &io_parms, 0, 0);
+       rc = smb2_new_read_req(
+               (void **) &buf, &total_len, &io_parms, rdata, 0, 0);
        if (rc) {
                if (rc == -EAGAIN && rdata->credits) {
                        /* credits was reset by reconnect */
@@ -2672,31 +2631,24 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
        struct smb2_read_plain_req *req = NULL;
        struct smb2_read_rsp *rsp = NULL;
        struct smb2_sync_hdr *shdr;
-       struct kvec iov[2];
+       struct kvec iov[1];
        struct kvec rsp_iov;
        unsigned int total_len;
-       __be32 req_len;
-       struct smb_rqst rqst = { .rq_iov = iov,
-                                .rq_nvec = 2 };
        int flags = CIFS_LOG_ERROR;
        struct cifs_ses *ses = io_parms->tcon->ses;
 
        *nbytes = 0;
-       rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0);
+       rc = smb2_new_read_req((void **)&req, &total_len, io_parms, NULL, 0, 0);
        if (rc)
                return rc;
 
        if (encryption_required(io_parms->tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req_len = cpu_to_be32(total_len);
-
-       iov[0].iov_base = &req_len;
-       iov[0].iov_len = sizeof(__be32);
-       iov[1].iov_base = req;
-       iov[1].iov_len = total_len;
+       iov[0].iov_base = (char *)req;
+       iov[0].iov_len = total_len;
 
-       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
@@ -2777,7 +2729,19 @@ smb2_writev_callback(struct mid_q_entry *mid)
                wdata->result = -EIO;
                break;
        }
-
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       /*
+        * If this wdata has a memory registered, the MR can be freed
+        * The number of MRs available is limited, it's important to recover
+        * used MR as soon as I/O is finished. Hold MR longer in the later
+        * I/O process can possibly result in I/O deadlock due to lack of MR
+        * to send request on I/O retry
+        */
+       if (wdata->mr) {
+               smbd_deregister_mr(wdata->mr);
+               wdata->mr = NULL;
+       }
+#endif
        if (wdata->result)
                cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
 
@@ -2798,8 +2762,10 @@ smb2_async_writev(struct cifs_writedata *wdata,
        struct TCP_Server_Info *server = tcon->ses->server;
        struct kvec iov[2];
        struct smb_rqst rqst = { };
+       unsigned int total_len;
+       __be32 rfc1002_marker;
 
-       rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
        if (rc) {
                if (rc == -EAGAIN && wdata->credits) {
                        /* credits was reset by reconnect */
@@ -2815,7 +2781,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       shdr = get_sync_hdr(req);
+       shdr = (struct smb2_sync_hdr *)req;
        shdr->ProcessId = cpu_to_le32(wdata->cfile->pid);
 
        req->PersistentFileId = wdata->cfile->fid.persistent_fid;
@@ -2824,16 +2790,51 @@ smb2_async_writev(struct cifs_writedata *wdata,
        req->WriteChannelInfoLength = 0;
        req->Channel = 0;
        req->Offset = cpu_to_le64(wdata->offset);
-       /* 4 for rfc1002 length field */
        req->DataOffset = cpu_to_le16(
-                               offsetof(struct smb2_write_req, Buffer) - 4);
+                               offsetof(struct smb2_write_req, Buffer));
        req->RemainingBytes = 0;
-
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       /*
+        * If we want to do a server RDMA read, fill in and append
+        * smbd_buffer_descriptor_v1 to the end of write request
+        */
+       if (server->rdma && wdata->bytes >=
+               server->smbd_conn->rdma_readwrite_threshold) {
+
+               struct smbd_buffer_descriptor_v1 *v1;
+               bool need_invalidate = server->dialect == SMB30_PROT_ID;
+
+               wdata->mr = smbd_register_mr(
+                               server->smbd_conn, wdata->pages,
+                               wdata->nr_pages, wdata->tailsz,
+                               false, need_invalidate);
+               if (!wdata->mr) {
+                       rc = -ENOBUFS;
+                       goto async_writev_out;
+               }
+               req->Length = 0;
+               req->DataOffset = 0;
+               req->RemainingBytes =
+                       (wdata->nr_pages-1)*PAGE_SIZE + wdata->tailsz;
+               req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE;
+               if (need_invalidate)
+                       req->Channel = SMB2_CHANNEL_RDMA_V1;
+               req->WriteChannelInfoOffset =
+                       offsetof(struct smb2_write_req, Buffer);
+               req->WriteChannelInfoLength =
+                       sizeof(struct smbd_buffer_descriptor_v1);
+               v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0];
+               v1->offset = wdata->mr->mr->iova;
+               v1->token = wdata->mr->mr->rkey;
+               v1->length = wdata->mr->mr->length;
+       }
+#endif
        /* 4 for rfc1002 length field and 1 for Buffer */
        iov[0].iov_len = 4;
-       iov[0].iov_base = req;
-       iov[1].iov_len = get_rfc1002_length(req) - 1;
-       iov[1].iov_base = (char *)req + 4;
+       rfc1002_marker = cpu_to_be32(total_len - 1 + wdata->bytes);
+       iov[0].iov_base = &rfc1002_marker;
+       iov[1].iov_len = total_len - 1;
+       iov[1].iov_base = (char *)req;
 
        rqst.rq_iov = iov;
        rqst.rq_nvec = 2;
@@ -2841,13 +2842,22 @@ smb2_async_writev(struct cifs_writedata *wdata,
        rqst.rq_npages = wdata->nr_pages;
        rqst.rq_pagesz = wdata->pagesz;
        rqst.rq_tailsz = wdata->tailsz;
-
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       if (wdata->mr) {
+               iov[1].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
+               rqst.rq_npages = 0;
+       }
+#endif
        cifs_dbg(FYI, "async write at %llu %u bytes\n",
                 wdata->offset, wdata->bytes);
 
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       /* For RDMA read, I/O size is in RemainingBytes not in Length */
+       if (!wdata->mr)
+               req->Length = cpu_to_le32(wdata->bytes);
+#else
        req->Length = cpu_to_le32(wdata->bytes);
-
-       inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
+#endif
 
        if (wdata->credits) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
@@ -2891,13 +2901,15 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        int resp_buftype;
        struct kvec rsp_iov;
        int flags = 0;
+       unsigned int total_len;
 
        *nbytes = 0;
 
        if (n_vec < 1)
                return rc;
 
-       rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
@@ -2907,7 +2919,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        if (encryption_required(io_parms->tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req->hdr.sync_hdr.ProcessId = cpu_to_le32(io_parms->pid);
+       req->sync_hdr.ProcessId = cpu_to_le32(io_parms->pid);
 
        req->PersistentFileId = io_parms->persistent_fid;
        req->VolatileFileId = io_parms->volatile_fid;
@@ -2916,20 +2928,16 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        req->Channel = 0;
        req->Length = cpu_to_le32(io_parms->length);
        req->Offset = cpu_to_le64(io_parms->offset);
-       /* 4 for rfc1002 length field */
        req->DataOffset = cpu_to_le16(
-                               offsetof(struct smb2_write_req, Buffer) - 4);
+                               offsetof(struct smb2_write_req, Buffer));
        req->RemainingBytes = 0;
 
        iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field and 1 for Buffer */
-       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
-
-       /* length of entire message including data to be written */
-       inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
+       /* 1 for Buffer */
+       iov[0].iov_len = total_len - 1;
 
-       rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
-                         &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, io_parms->tcon->ses, iov, n_vec + 1,
+                           &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
 
@@ -3006,13 +3014,15 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        unsigned int output_size = CIFSMaxBufSize;
        size_t info_buf_size;
        int flags = 0;
+       unsigned int total_len;
 
        if (ses && (ses->server))
                server = ses->server;
        else
                return -EIO;
 
-       rc = small_smb2_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
@@ -3044,7 +3054,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        memcpy(bufptr, &asteriks, len);
 
        req->FileNameOffset =
-               cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1 - 4);
+               cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1);
        req->FileNameLength = cpu_to_le16(len);
        /*
         * BB could be 30 bytes or so longer if we used SMB2 specific
@@ -3055,15 +3065,13 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        req->OutputBufferLength = cpu_to_le32(output_size);
 
        iov[0].iov_base = (char *)req;
-       /* 4 for RFC1001 length and 1 for Buffer */
-       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+       /* 1 for Buffer */
+       iov[0].iov_len = total_len - 1;
 
        iov[1].iov_base = (char *)(req->Buffer);
        iov[1].iov_len = len;
 
-       inc_rfc1001_len(req, len - 1 /* Buffer */);
-
-       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
 
@@ -3132,6 +3140,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        unsigned int i;
        struct cifs_ses *ses = tcon->ses;
        int flags = 0;
+       unsigned int total_len;
 
        if (!ses || !(ses->server))
                return -EIO;
@@ -3143,7 +3152,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (!iov)
                return -ENOMEM;
 
-       rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, (void **) &req, &total_len);
        if (rc) {
                kfree(iov);
                return rc;
@@ -3152,7 +3161,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
+       req->sync_hdr.ProcessId = cpu_to_le32(pid);
 
        req->InfoType = info_type;
        req->FileInfoClass = info_class;
@@ -3160,27 +3169,25 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        req->VolatileFileId = volatile_fid;
        req->AdditionalInformation = cpu_to_le32(additional_info);
 
-       /* 4 for RFC1001 length and 1 for Buffer */
        req->BufferOffset =
-                       cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
+                       cpu_to_le16(sizeof(struct smb2_set_info_req) - 1);
        req->BufferLength = cpu_to_le32(*size);
 
-       inc_rfc1001_len(req, *size - 1 /* Buffer */);
-
        memcpy(req->Buffer, *data, *size);
+       total_len += *size;
 
        iov[0].iov_base = (char *)req;
-       /* 4 for RFC1001 length */
-       iov[0].iov_len = get_rfc1002_length(req) + 4;
+       /* 1 for Buffer */
+       iov[0].iov_len = total_len - 1;
 
        for (i = 1; i < num; i++) {
-               inc_rfc1001_len(req, size[i]);
                le32_add_cpu(&req->BufferLength, size[i]);
                iov[i].iov_base = (char *)data[i];
                iov[i].iov_len = size[i];
        }
 
-       rc = SendReceive2(xid, ses, iov, num, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, iov, num, &resp_buftype, flags,
+                           &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
 
@@ -3332,11 +3339,17 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
                  __u8 oplock_level)
 {
        int rc;
-       struct smb2_oplock_break *req = NULL;
+       struct smb2_oplock_break_req *req = NULL;
+       struct cifs_ses *ses = tcon->ses;
        int flags = CIFS_OBREAK_OP;
+       unsigned int total_len;
+       struct kvec iov[1];
+       struct kvec rsp_iov;
+       int resp_buf_type;
 
        cifs_dbg(FYI, "SMB2_oplock_break\n");
-       rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
@@ -3346,9 +3359,14 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
        req->VolatileFid = volatile_fid;
        req->PersistentFid = persistent_fid;
        req->OplockLevel = oplock_level;
-       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
+       req->sync_hdr.CreditRequest = cpu_to_le16(1);
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+       flags |= CIFS_NO_RESP;
+
+       iov[0].iov_base = (char *)req;
+       iov[0].iov_len = total_len;
+
+       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc) {
@@ -3377,13 +3395,15 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
 {
        int rc;
        struct smb2_query_info_req *req;
+       unsigned int total_len;
 
        cifs_dbg(FYI, "Query FSInfo level %d\n", level);
 
        if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
                return -EIO;
 
-       rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
@@ -3391,15 +3411,14 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
        req->FileInfoClass = level;
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
-       /* 4 for rfc1002 length field and 1 for pad */
+       /* 1 for pad */
        req->InputBufferOffset =
-                       cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
+                       cpu_to_le16(sizeof(struct smb2_query_info_req) - 1);
        req->OutputBufferLength = cpu_to_le32(
                outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
 
        iov->iov_base = (char *)req;
-       /* 4 for rfc1002 length field */
-       iov->iov_len = get_rfc1002_length(req) + 4;
+       iov->iov_len = total_len;
        return 0;
 }
 
@@ -3425,7 +3444,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -3481,7 +3500,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -3527,34 +3546,33 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        int resp_buf_type;
        unsigned int count;
        int flags = CIFS_NO_RESP;
+       unsigned int total_len;
 
        cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
-       rc = small_smb2_init(SMB2_LOCK, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_LOCK, tcon, (void **) &req, &total_len);
        if (rc)
                return rc;
 
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
+       req->sync_hdr.ProcessId = cpu_to_le32(pid);
        req->LockCount = cpu_to_le16(num_lock);
 
        req->PersistentFileId = persist_fid;
        req->VolatileFileId = volatile_fid;
 
        count = num_lock * sizeof(struct smb2_lock_element);
-       inc_rfc1001_len(req, count - sizeof(struct smb2_lock_element));
 
        iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field and count for all locks */
-       iov[0].iov_len = get_rfc1002_length(req) + 4 - count;
+       iov[0].iov_len = total_len - sizeof(struct smb2_lock_element);
        iov[1].iov_base = (char *)buf;
        iov[1].iov_len = count;
 
        cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
-                         &rsp_iov);
+       rc = smb2_send_recv(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
+                           &rsp_iov);
        cifs_small_buf_release(req);
        if (rc) {
                cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
@@ -3587,24 +3605,35 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
 {
        int rc;
        struct smb2_lease_ack *req = NULL;
+       struct cifs_ses *ses = tcon->ses;
        int flags = CIFS_OBREAK_OP;
+       unsigned int total_len;
+       struct kvec iov[1];
+       struct kvec rsp_iov;
+       int resp_buf_type;
 
        cifs_dbg(FYI, "SMB2_lease_break\n");
-       rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req,
+                            &total_len);
        if (rc)
                return rc;
 
        if (encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
+       req->sync_hdr.CreditRequest = cpu_to_le16(1);
        req->StructureSize = cpu_to_le16(36);
-       inc_rfc1001_len(req, 12);
+       total_len += 12;
 
        memcpy(req->LeaseKey, lease_key, 16);
        req->LeaseState = lease_state;
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+       flags |= CIFS_NO_RESP;
+
+       iov[0].iov_base = (char *)req;
+       iov[0].iov_len = total_len;
+
+       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc) {