]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Dec 2023 14:22:02 +0000 (15:22 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Dec 2023 14:22:02 +0000 (15:22 +0100)
added patches:
ib-isert-fix-unaligned-immediate-data-handling.patch

queue-4.19/ib-isert-fix-unaligned-immediate-data-handling.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/ib-isert-fix-unaligned-immediate-data-handling.patch b/queue-4.19/ib-isert-fix-unaligned-immediate-data-handling.patch
new file mode 100644 (file)
index 0000000..20bcaa4
--- /dev/null
@@ -0,0 +1,386 @@
+From 0b089c1ef7047652b13b4cdfdb1e0e7dbdb8c9ab Mon Sep 17 00:00:00 2001
+From: Sagi Grimberg <sagi@grimberg.me>
+Date: Fri, 4 Sep 2020 12:50:39 -0700
+Subject: IB/isert: Fix unaligned immediate-data handling
+
+From: Sagi Grimberg <sagi@grimberg.me>
+
+commit 0b089c1ef7047652b13b4cdfdb1e0e7dbdb8c9ab upstream.
+
+Currently we allocate rx buffers in a single contiguous buffers for
+headers (iser and iscsi) and data trailer. This means that most likely the
+data starting offset is aligned to 76 bytes (size of both headers).
+
+This worked fine for years, but at some point this broke, resulting in
+data corruptions in isert when a command comes with immediate data and the
+underlying backend device assumes 512 bytes buffer alignment.
+
+We assume a hard-requirement for all direct I/O buffers to be 512 bytes
+aligned. To fix this, we should avoid passing unaligned buffers for I/O.
+
+Instead, we allocate our recv buffers with some extra space such that we
+can have the data portion align to 512 byte boundary. This also means that
+we cannot reference headers or data using structure but rather
+accessors (as they may move based on alignment). Also, get rid of the
+wrong __packed annotation from iser_rx_desc as this has only harmful
+effects (not aligned to anything).
+
+This affects the rx descriptors for iscsi login and data plane.
+
+Fixes: 3d75ca0adef4 ("block: introduce multi-page bvec helpers")
+Link: https://lore.kernel.org/r/20200904195039.31687-1-sagi@grimberg.me
+Reported-by: Stephen Rust <srust@blockbridge.com>
+Tested-by: Doug Dumitru <doug@dumitru.com>
+Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/ulp/isert/ib_isert.c |   93 ++++++++++++++++----------------
+ drivers/infiniband/ulp/isert/ib_isert.h |   41 ++++++++++----
+ 2 files changed, 78 insertions(+), 56 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -190,15 +190,15 @@ isert_alloc_rx_descriptors(struct isert_
+       rx_desc = isert_conn->rx_descs;
+       for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
+-              dma_addr = ib_dma_map_single(ib_dev, (void *)rx_desc,
+-                                      ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++              dma_addr = ib_dma_map_single(ib_dev, rx_desc->buf,
++                                      ISER_RX_SIZE, DMA_FROM_DEVICE);
+               if (ib_dma_mapping_error(ib_dev, dma_addr))
+                       goto dma_map_fail;
+               rx_desc->dma_addr = dma_addr;
+               rx_sg = &rx_desc->rx_sg;
+-              rx_sg->addr = rx_desc->dma_addr;
++              rx_sg->addr = rx_desc->dma_addr + isert_get_hdr_offset(rx_desc);
+               rx_sg->length = ISER_RX_PAYLOAD_SIZE;
+               rx_sg->lkey = device->pd->local_dma_lkey;
+               rx_desc->rx_cqe.done = isert_recv_done;
+@@ -210,7 +210,7 @@ dma_map_fail:
+       rx_desc = isert_conn->rx_descs;
+       for (j = 0; j < i; j++, rx_desc++) {
+               ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
+-                                  ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++                                  ISER_RX_SIZE, DMA_FROM_DEVICE);
+       }
+       kfree(isert_conn->rx_descs);
+       isert_conn->rx_descs = NULL;
+@@ -231,7 +231,7 @@ isert_free_rx_descriptors(struct isert_c
+       rx_desc = isert_conn->rx_descs;
+       for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
+               ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
+-                                  ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++                                  ISER_RX_SIZE, DMA_FROM_DEVICE);
+       }
+       kfree(isert_conn->rx_descs);
+@@ -416,10 +416,9 @@ isert_free_login_buf(struct isert_conn *
+                           ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE);
+       kfree(isert_conn->login_rsp_buf);
+-      ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+-                          ISER_RX_PAYLOAD_SIZE,
+-                          DMA_FROM_DEVICE);
+-      kfree(isert_conn->login_req_buf);
++      ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
++                          ISER_RX_SIZE, DMA_FROM_DEVICE);
++      kfree(isert_conn->login_desc);
+ }
+ static int
+@@ -428,25 +427,25 @@ isert_alloc_login_buf(struct isert_conn
+ {
+       int ret;
+-      isert_conn->login_req_buf = kzalloc(sizeof(*isert_conn->login_req_buf),
++      isert_conn->login_desc = kzalloc(sizeof(*isert_conn->login_desc),
+                       GFP_KERNEL);
+-      if (!isert_conn->login_req_buf)
++      if (!isert_conn->login_desc)
+               return -ENOMEM;
+-      isert_conn->login_req_dma = ib_dma_map_single(ib_dev,
+-                              isert_conn->login_req_buf,
+-                              ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+-      ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma);
++      isert_conn->login_desc->dma_addr = ib_dma_map_single(ib_dev,
++                              isert_conn->login_desc->buf,
++                              ISER_RX_SIZE, DMA_FROM_DEVICE);
++      ret = ib_dma_mapping_error(ib_dev, isert_conn->login_desc->dma_addr);
+       if (ret) {
+-              isert_err("login_req_dma mapping error: %d\n", ret);
+-              isert_conn->login_req_dma = 0;
+-              goto out_free_login_req_buf;
++              isert_err("login_desc dma mapping error: %d\n", ret);
++              isert_conn->login_desc->dma_addr = 0;
++              goto out_free_login_desc;
+       }
+       isert_conn->login_rsp_buf = kzalloc(ISER_RX_PAYLOAD_SIZE, GFP_KERNEL);
+       if (!isert_conn->login_rsp_buf) {
+               ret = -ENOMEM;
+-              goto out_unmap_login_req_buf;
++              goto out_unmap_login_desc;
+       }
+       isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev,
+@@ -463,11 +462,11 @@ isert_alloc_login_buf(struct isert_conn
+ out_free_login_rsp_buf:
+       kfree(isert_conn->login_rsp_buf);
+-out_unmap_login_req_buf:
+-      ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+-                          ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+-out_free_login_req_buf:
+-      kfree(isert_conn->login_req_buf);
++out_unmap_login_desc:
++      ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
++                          ISER_RX_SIZE, DMA_FROM_DEVICE);
++out_free_login_desc:
++      kfree(isert_conn->login_desc);
+       return ret;
+ }
+@@ -586,7 +585,7 @@ isert_connect_release(struct isert_conn
+               ib_destroy_qp(isert_conn->qp);
+       }
+-      if (isert_conn->login_req_buf)
++      if (isert_conn->login_desc)
+               isert_free_login_buf(isert_conn);
+       isert_device_put(device);
+@@ -976,17 +975,18 @@ isert_login_post_recv(struct isert_conn
+       int ret;
+       memset(&sge, 0, sizeof(struct ib_sge));
+-      sge.addr = isert_conn->login_req_dma;
++      sge.addr = isert_conn->login_desc->dma_addr +
++              isert_get_hdr_offset(isert_conn->login_desc);
+       sge.length = ISER_RX_PAYLOAD_SIZE;
+       sge.lkey = isert_conn->device->pd->local_dma_lkey;
+       isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n",
+               sge.addr, sge.length, sge.lkey);
+-      isert_conn->login_req_buf->rx_cqe.done = isert_login_recv_done;
++      isert_conn->login_desc->rx_cqe.done = isert_login_recv_done;
+       memset(&rx_wr, 0, sizeof(struct ib_recv_wr));
+-      rx_wr.wr_cqe = &isert_conn->login_req_buf->rx_cqe;
++      rx_wr.wr_cqe = &isert_conn->login_desc->rx_cqe;
+       rx_wr.sg_list = &sge;
+       rx_wr.num_sge = 1;
+@@ -1063,7 +1063,7 @@ post_send:
+ static void
+ isert_rx_login_req(struct isert_conn *isert_conn)
+ {
+-      struct iser_rx_desc *rx_desc = isert_conn->login_req_buf;
++      struct iser_rx_desc *rx_desc = isert_conn->login_desc;
+       int rx_buflen = isert_conn->login_req_len;
+       struct iscsi_conn *conn = isert_conn->conn;
+       struct iscsi_login *login = conn->conn_login;
+@@ -1075,7 +1075,7 @@ isert_rx_login_req(struct isert_conn *is
+       if (login->first_request) {
+               struct iscsi_login_req *login_req =
+-                      (struct iscsi_login_req *)&rx_desc->iscsi_header;
++                      (struct iscsi_login_req *)isert_get_iscsi_hdr(rx_desc);
+               /*
+                * Setup the initial iscsi_login values from the leading
+                * login request PDU.
+@@ -1094,13 +1094,13 @@ isert_rx_login_req(struct isert_conn *is
+               login->tsih             = be16_to_cpu(login_req->tsih);
+       }
+-      memcpy(&login->req[0], (void *)&rx_desc->iscsi_header, ISCSI_HDR_LEN);
++      memcpy(&login->req[0], isert_get_iscsi_hdr(rx_desc), ISCSI_HDR_LEN);
+       size = min(rx_buflen, MAX_KEY_VALUE_PAIRS);
+       isert_dbg("Using login payload size: %d, rx_buflen: %d "
+                 "MAX_KEY_VALUE_PAIRS: %d\n", size, rx_buflen,
+                 MAX_KEY_VALUE_PAIRS);
+-      memcpy(login->req_buf, &rx_desc->data[0], size);
++      memcpy(login->req_buf, isert_get_data(rx_desc), size);
+       if (login->first_request) {
+               complete(&isert_conn->login_comp);
+@@ -1165,14 +1165,15 @@ isert_handle_scsi_cmd(struct isert_conn
+       if (imm_data_len != data_len) {
+               sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE));
+               sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents,
+-                                  &rx_desc->data[0], imm_data_len);
++                                  isert_get_data(rx_desc), imm_data_len);
+               isert_dbg("Copy Immediate sg_nents: %u imm_data_len: %d\n",
+                         sg_nents, imm_data_len);
+       } else {
+               sg_init_table(&isert_cmd->sg, 1);
+               cmd->se_cmd.t_data_sg = &isert_cmd->sg;
+               cmd->se_cmd.t_data_nents = 1;
+-              sg_set_buf(&isert_cmd->sg, &rx_desc->data[0], imm_data_len);
++              sg_set_buf(&isert_cmd->sg, isert_get_data(rx_desc),
++                              imm_data_len);
+               isert_dbg("Transfer Immediate imm_data_len: %d\n",
+                         imm_data_len);
+       }
+@@ -1241,9 +1242,9 @@ isert_handle_iscsi_dataout(struct isert_
+       }
+       isert_dbg("Copying DataOut: sg_start: %p, sg_off: %u "
+                 "sg_nents: %u from %p %u\n", sg_start, sg_off,
+-                sg_nents, &rx_desc->data[0], unsol_data_len);
++                sg_nents, isert_get_data(rx_desc), unsol_data_len);
+-      sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0],
++      sg_copy_from_buffer(sg_start, sg_nents, isert_get_data(rx_desc),
+                           unsol_data_len);
+       rc = iscsit_check_dataout_payload(cmd, hdr, false);
+@@ -1302,7 +1303,7 @@ isert_handle_text_cmd(struct isert_conn
+       }
+       cmd->text_in_ptr = text_in;
+-      memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
++      memcpy(cmd->text_in_ptr, isert_get_data(rx_desc), payload_length);
+       return iscsit_process_text_cmd(conn, cmd, hdr);
+ }
+@@ -1312,7 +1313,7 @@ isert_rx_opcode(struct isert_conn *isert
+               uint32_t read_stag, uint64_t read_va,
+               uint32_t write_stag, uint64_t write_va)
+ {
+-      struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
++      struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
+       struct iscsi_conn *conn = isert_conn->conn;
+       struct iscsi_cmd *cmd;
+       struct isert_cmd *isert_cmd;
+@@ -1410,8 +1411,8 @@ isert_recv_done(struct ib_cq *cq, struct
+       struct isert_conn *isert_conn = wc->qp->qp_context;
+       struct ib_device *ib_dev = isert_conn->cm_id->device;
+       struct iser_rx_desc *rx_desc = cqe_to_rx_desc(wc->wr_cqe);
+-      struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
+-      struct iser_ctrl *iser_ctrl = &rx_desc->iser_header;
++      struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
++      struct iser_ctrl *iser_ctrl = isert_get_iser_hdr(rx_desc);
+       uint64_t read_va = 0, write_va = 0;
+       uint32_t read_stag = 0, write_stag = 0;
+@@ -1425,7 +1426,7 @@ isert_recv_done(struct ib_cq *cq, struct
+       rx_desc->in_use = true;
+       ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr,
+-                      ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++                      ISER_RX_SIZE, DMA_FROM_DEVICE);
+       isert_dbg("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n",
+                rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags,
+@@ -1460,7 +1461,7 @@ isert_recv_done(struct ib_cq *cq, struct
+                       read_stag, read_va, write_stag, write_va);
+       ib_dma_sync_single_for_device(ib_dev, rx_desc->dma_addr,
+-                      ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++                      ISER_RX_SIZE, DMA_FROM_DEVICE);
+ }
+ static void
+@@ -1474,8 +1475,8 @@ isert_login_recv_done(struct ib_cq *cq,
+               return;
+       }
+-      ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_req_dma,
+-                      ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++      ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr,
++                      ISER_RX_SIZE, DMA_FROM_DEVICE);
+       isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN;
+@@ -1490,8 +1491,8 @@ isert_login_recv_done(struct ib_cq *cq,
+       complete(&isert_conn->login_req_comp);
+       mutex_unlock(&isert_conn->mutex);
+-      ib_dma_sync_single_for_device(ib_dev, isert_conn->login_req_dma,
+-                              ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
++      ib_dma_sync_single_for_device(ib_dev, isert_conn->login_desc->dma_addr,
++                              ISER_RX_SIZE, DMA_FROM_DEVICE);
+ }
+ static void
+--- a/drivers/infiniband/ulp/isert/ib_isert.h
++++ b/drivers/infiniband/ulp/isert/ib_isert.h
+@@ -59,9 +59,11 @@
+                               ISERT_MAX_TX_MISC_PDUS  + \
+                               ISERT_MAX_RX_MISC_PDUS)
+-#define ISER_RX_PAD_SIZE      (ISCSI_DEF_MAX_RECV_SEG_LEN + 4096 - \
+-              (ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge) + \
+-               sizeof(struct ib_cqe) + sizeof(bool)))
++/*
++ * RX size is default of 8k plus headers, but data needs to align to
++ * 512 boundary, so use 1024 to have the extra space for alignment.
++ */
++#define ISER_RX_SIZE          (ISCSI_DEF_MAX_RECV_SEG_LEN + 1024)
+ #define ISCSI_ISER_SG_TABLESIZE               256
+@@ -80,21 +82,41 @@ enum iser_conn_state {
+ };
+ struct iser_rx_desc {
+-      struct iser_ctrl iser_header;
+-      struct iscsi_hdr iscsi_header;
+-      char            data[ISCSI_DEF_MAX_RECV_SEG_LEN];
++      char            buf[ISER_RX_SIZE];
+       u64             dma_addr;
+       struct ib_sge   rx_sg;
+       struct ib_cqe   rx_cqe;
+       bool            in_use;
+-      char            pad[ISER_RX_PAD_SIZE];
+-} __packed;
++};
+ static inline struct iser_rx_desc *cqe_to_rx_desc(struct ib_cqe *cqe)
+ {
+       return container_of(cqe, struct iser_rx_desc, rx_cqe);
+ }
++static void *isert_get_iser_hdr(struct iser_rx_desc *desc)
++{
++      return PTR_ALIGN(desc->buf + ISER_HEADERS_LEN, 512) - ISER_HEADERS_LEN;
++}
++
++static size_t isert_get_hdr_offset(struct iser_rx_desc *desc)
++{
++      return isert_get_iser_hdr(desc) - (void *)desc->buf;
++}
++
++static void *isert_get_iscsi_hdr(struct iser_rx_desc *desc)
++{
++      return isert_get_iser_hdr(desc) + sizeof(struct iser_ctrl);
++}
++
++static void *isert_get_data(struct iser_rx_desc *desc)
++{
++      void *data = isert_get_iser_hdr(desc) + ISER_HEADERS_LEN;
++
++      WARN_ON((uintptr_t)data & 511);
++      return data;
++}
++
+ struct iser_tx_desc {
+       struct iser_ctrl iser_header;
+       struct iscsi_hdr iscsi_header;
+@@ -141,9 +163,8 @@ struct isert_conn {
+       u32                     responder_resources;
+       u32                     initiator_depth;
+       bool                    pi_support;
+-      struct iser_rx_desc     *login_req_buf;
++      struct iser_rx_desc     *login_desc;
+       char                    *login_rsp_buf;
+-      u64                     login_req_dma;
+       int                     login_req_len;
+       u64                     login_rsp_dma;
+       struct iser_rx_desc     *rx_descs;
index 1a0dd89905e38f61553e2ac2b7c08e459b68e430..8163c56018147b6b8b08f15a15dc639e8ff05567 100644 (file)
@@ -51,3 +51,4 @@ genetlink-add-cap_net_admin-test-for-multicast-bind.patch
 psample-require-cap_net_admin-when-joining-packets-group.patch
 drop_monitor-require-cap_sys_admin-when-joining-events-group.patch
 tools-headers-uapi-sync-linux-perf_event.h-with-the-kernel-sources.patch
+ib-isert-fix-unaligned-immediate-data-handling.patch