#include "cifs_debug.h"
 #include "cifs_fs_sb.h"
 #include "fscache.h"
-
+#include "smbdirect.h"
 
 static inline int cifs_convert_flags(unsigned int flags)
 {
 {
        struct cifs_readdata *rdata = container_of(refcount,
                                        struct cifs_readdata, refcount);
-
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       if (rdata->mr) {
+               smbd_deregister_mr(rdata->mr);
+               rdata->mr = NULL;
+       }
+#endif
        if (rdata->cfile)
                cifsFileInfo_put(rdata->cfile);
 
                }
                if (iter)
                        result = copy_page_from_iter(page, 0, n, iter);
+#ifdef CONFIG_CIFS_SMB_DIRECT
+               else if (rdata->mr)
+                       result = n;
+#endif
                else
                        result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
 
                if (iter)
                        result = copy_page_from_iter(page, 0, n, iter);
+#ifdef CONFIG_CIFS_SMB_DIRECT
+               else if (rdata->mr)
+                       result = n;
+#endif
                else
                        result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
 
        req->MinimumCount = 0;
        req->Length = cpu_to_le32(io_parms->length);
        req->Offset = cpu_to_le64(io_parms->offset);
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       /*
+        * If we want to do a RDMA write, fill in and append
+        * smbd_buffer_descriptor_v1 to the end of read request
+        */
+       if (server->rdma && rdata &&
+               rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) {
+
+               struct smbd_buffer_descriptor_v1 *v1;
+               bool need_invalidate =
+                       io_parms->tcon->ses->server->dialect == SMB30_PROT_ID;
+
+               rdata->mr = smbd_register_mr(
+                               server->smbd_conn, rdata->pages,
+                               rdata->nr_pages, rdata->tailsz,
+                               true, need_invalidate);
+               if (!rdata->mr)
+                       return -ENOBUFS;
+
+               req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE;
+               if (need_invalidate)
+                       req->Channel = SMB2_CHANNEL_RDMA_V1;
+               req->ReadChannelInfoOffset =
+                       offsetof(struct smb2_read_plain_req, Buffer);
+               req->ReadChannelInfoLength =
+                       sizeof(struct smbd_buffer_descriptor_v1);
+               v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0];
+               v1->offset = rdata->mr->mr->iova;
+               v1->token = rdata->mr->mr->rkey;
+               v1->length = rdata->mr->mr->length;
 
+               *total_len += sizeof(*v1) - 1;
+       }
+#endif
        if (request_type & CHAINED_REQUEST) {
                if (!(request_type & END_OF_CHAIN)) {
                        /* next 8-byte aligned request */
                if (rdata->result != -ENODATA)
                        rdata->result = -EIO;
        }
-
+#ifdef CONFIG_CIFS_SMB_DIRECT
+       /*
+        * If this rdata has a memmory registered, the MR can be freed
+        * MR needs to be freed as soon as I/O finishes to prevent deadlock
+        * because they have limited number and are used for future I/Os
+        */
+       if (rdata->mr) {
+               smbd_deregister_mr(rdata->mr);
+               rdata->mr = NULL;
+       }
+#endif
        if (rdata->result)
                cifs_stats_fail_inc(tcon, SMB2_READ_HE);