From: Leon Romanovsky <leon@kernel.org>
To: Jason Gunthorpe <jgg@nvidia.com>
Cc: Israel Rukshin <israelr@nvidia.com>,
Bryan Tan <bryantan@vmware.com>, Christoph Hellwig <hch@lst.de>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Jens Axboe <axboe@fb.com>,
Keith Busch <kbusch@kernel.org>,
linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org,
linux-rdma@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
Masami Hiramatsu <mhiramat@kernel.org>,
Max Gurtovoy <mgurtovoy@nvidia.com>,
netdev@vger.kernel.org, Paolo Abeni <pabeni@redhat.com>,
Saeed Mahameed <saeedm@nvidia.com>,
Sagi Grimberg <sagi@grimberg.me>,
Selvin Xavier <selvin.xavier@broadcom.com>,
Steven Rostedt <rostedt@goodmis.org>,
Vishnu Dasa <vdasa@vmware.com>, Yishai Hadas <yishaih@nvidia.com>
Subject: [PATCH rdma-next 13/13] nvme-rdma: Add inline encryption support
Date: Mon, 16 Jan 2023 15:06:00 +0200 [thread overview]
Message-ID: <ab0817fac98d498372fd32e950d1ca6e157b575d.1673873422.git.leon@kernel.org> (raw)
In-Reply-To: <cover.1673873422.git.leon@kernel.org>
From: Israel Rukshin <israelr@nvidia.com>
Add support for inline encryption/decryption of the data at a
similar way like integrity is used via a unique Mkey. The feature
is enabled only when CONFIG_BLK_INLINE_ENCRYPTION is configured.
There is no special configuration to enable crypto at nvme modules.
The code was tested with fscrypt and BF-3 HW, which had more than
50% CPU utilization improvement at 64K and bigger I/O sizes when
comparing to the SW only solution at this case.
Signed-off-by: Israel Rukshin <israelr@nvidia.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
---
drivers/nvme/host/rdma.c | 236 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 232 insertions(+), 4 deletions(-)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index bbad26b82b56..8bea38eb976f 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -40,6 +40,10 @@
#define NVME_RDMA_METADATA_SGL_SIZE \
(sizeof(struct scatterlist) * NVME_INLINE_METADATA_SG_CNT)
+#define NVME_RDMA_NUM_CRYPTO_KEYSLOTS (32U)
+/* Bitmask for 512B and 4K data unit sizes */
+#define NVME_RDMA_DATA_UNIT_SIZES (512U | 4096U)
+
struct nvme_rdma_device {
struct ib_device *dev;
struct ib_pd *pd;
@@ -75,6 +79,7 @@ struct nvme_rdma_request {
struct nvme_rdma_sgl data_sgl;
struct nvme_rdma_sgl *metadata_sgl;
bool use_sig_mr;
+ bool use_crypto;
};
enum nvme_rdma_queue_flags {
@@ -97,6 +102,7 @@ struct nvme_rdma_queue {
int cm_error;
struct completion cm_done;
bool pi_support;
+ bool crypto_support;
int cq_size;
struct mutex queue_lock;
};
@@ -126,6 +132,8 @@ struct nvme_rdma_ctrl {
struct nvme_ctrl ctrl;
bool use_inline_data;
u32 io_queues[HCTX_MAX_TYPES];
+
+ struct ib_dek *dek[NVME_RDMA_NUM_CRYPTO_KEYSLOTS];
};
static inline struct nvme_rdma_ctrl *to_rdma_ctrl(struct nvme_ctrl *ctrl)
@@ -275,6 +283,8 @@ static int nvme_rdma_create_qp(struct nvme_rdma_queue *queue, const int factor)
init_attr.recv_cq = queue->ib_cq;
if (queue->pi_support)
init_attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN;
+ if (queue->crypto_support)
+ init_attr.create_flags |= IB_QP_CREATE_CRYPTO_EN;
init_attr.qp_context = queue;
ret = rdma_create_qp(queue->cm_id, dev->pd, &init_attr);
@@ -364,6 +374,77 @@ static int nvme_rdma_dev_get(struct nvme_rdma_device *dev)
return kref_get_unless_zero(&dev->ref);
}
+static int nvme_rdma_crypto_keyslot_program(struct blk_crypto_profile *profile,
+ const struct blk_crypto_key *key,
+ unsigned int slot)
+{
+ struct nvme_ctrl *nctrl =
+ container_of(profile, struct nvme_ctrl, crypto_profile);
+ struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
+ struct ib_dek_attr dek_attr = { };
+ int err = 0;
+
+ if (slot > NVME_RDMA_NUM_CRYPTO_KEYSLOTS) {
+ dev_err(nctrl->device, "slot index reached the limit %d/%d",
+ slot, NVME_RDMA_NUM_CRYPTO_KEYSLOTS);
+ return -EOPNOTSUPP;
+ }
+
+ if (WARN_ON_ONCE(key->crypto_cfg.crypto_mode !=
+ BLK_ENCRYPTION_MODE_AES_256_XTS))
+ return -EOPNOTSUPP;
+
+ if (ctrl->dek[slot]) {
+ dev_dbg(nctrl->device, "slot %d is taken, free DEK ID %d\n",
+ slot, ctrl->dek[slot]->id);
+ ib_destroy_dek(ctrl->dek[slot]);
+ }
+
+ dek_attr.key_blob = key->raw;
+ dek_attr.key_blob_size = key->size;
+ dek_attr.key_type = IB_CRYPTO_KEY_TYPE_AES_XTS;
+ ctrl->dek[slot] = ib_create_dek(ctrl->device->pd, &dek_attr);
+ if (IS_ERR(ctrl->dek[slot])) {
+ err = PTR_ERR(ctrl->dek[slot]);
+ dev_err(nctrl->device,
+ "failed to create DEK at slot %d, err %d\n", slot, err);
+ ctrl->dek[slot] = NULL;
+ } else {
+ dev_dbg(nctrl->device, "DEK ID %d was created at slot %d\n",
+ ctrl->dek[slot]->id, slot);
+ }
+
+ return err;
+}
+
+static int nvme_rdma_crypto_keyslot_evict(struct blk_crypto_profile *profile,
+ const struct blk_crypto_key *key,
+ unsigned int slot)
+{
+ struct nvme_ctrl *nctrl =
+ container_of(profile, struct nvme_ctrl, crypto_profile);
+ struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
+
+ if (slot > NVME_RDMA_NUM_CRYPTO_KEYSLOTS) {
+ dev_err(nctrl->device, "slot index reached the limit %d/%d\n",
+ slot, NVME_RDMA_NUM_CRYPTO_KEYSLOTS);
+ return -EOPNOTSUPP;
+ }
+
+ if (!ctrl->dek[slot]) {
+ dev_err(nctrl->device, "slot %d is empty\n", slot);
+ return -EINVAL;
+ }
+
+ dev_dbg(nctrl->device, "Destroy DEK ID %d slot %d\n",
+ ctrl->dek[slot]->id, slot);
+
+ ib_destroy_dek(ctrl->dek[slot]);
+ ctrl->dek[slot] = NULL;
+
+ return 0;
+}
+
static struct nvme_rdma_device *
nvme_rdma_find_get_device(struct rdma_cm_id *cm_id)
{
@@ -430,6 +511,8 @@ static void nvme_rdma_destroy_queue_ib(struct nvme_rdma_queue *queue)
dev = queue->device;
ibdev = dev->dev;
+ if (queue->crypto_support)
+ ib_mr_pool_destroy(queue->qp, &queue->qp->crypto_mrs);
if (queue->pi_support)
ib_mr_pool_destroy(queue->qp, &queue->qp->sig_mrs);
ib_mr_pool_destroy(queue->qp, &queue->qp->rdma_mrs);
@@ -553,10 +636,24 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
}
}
+ if (queue->crypto_support) {
+ ret = ib_mr_pool_init(queue->qp, &queue->qp->crypto_mrs,
+ queue->queue_size, IB_MR_TYPE_CRYPTO,
+ pages_per_mr, 0);
+ if (ret) {
+ dev_err(queue->ctrl->ctrl.device,
+ "failed to initialize crypto MR pool sized %d for QID %d\n",
+ queue->queue_size, nvme_rdma_queue_idx(queue));
+ goto out_destroy_sig_mr_pool;
+ }
+ }
+
set_bit(NVME_RDMA_Q_TR_READY, &queue->flags);
return 0;
+out_destroy_sig_mr_pool:
+ ib_mr_pool_destroy(queue->qp, &queue->qp->sig_mrs);
out_destroy_mr_pool:
ib_mr_pool_destroy(queue->qp, &queue->qp->rdma_mrs);
out_destroy_ring:
@@ -585,6 +682,9 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
queue->pi_support = true;
else
queue->pi_support = false;
+
+ queue->crypto_support = idx && ctrl->ctrl.crypto_enable;
+
init_completion(&queue->cm_done);
if (idx > 0)
@@ -805,15 +905,109 @@ static int nvme_rdma_alloc_tag_set(struct nvme_ctrl *ctrl)
static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl)
{
+ unsigned int i;
+
if (ctrl->async_event_sqe.data) {
cancel_work_sync(&ctrl->ctrl.async_event_work);
nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
sizeof(struct nvme_command), DMA_TO_DEVICE);
ctrl->async_event_sqe.data = NULL;
}
+
+ for (i = 0; i < NVME_RDMA_NUM_CRYPTO_KEYSLOTS; i++) {
+ if (!ctrl->dek[i])
+ continue;
+ ib_destroy_dek(ctrl->dek[i]);
+ ctrl->dek[i] = NULL;
+ }
+
nvme_rdma_free_queue(&ctrl->queues[0]);
}
+#ifdef CONFIG_BLK_INLINE_ENCRYPTION
+static const struct blk_crypto_ll_ops nvme_rdma_crypto_ops = {
+ .keyslot_program = nvme_rdma_crypto_keyslot_program,
+ .keyslot_evict = nvme_rdma_crypto_keyslot_evict,
+};
+
+static int nvme_rdma_crypto_profile_init(struct nvme_rdma_ctrl *ctrl, bool new)
+{
+ struct blk_crypto_profile *profile = &ctrl->ctrl.crypto_profile;
+ int ret;
+
+ if (!new) {
+ blk_crypto_reprogram_all_keys(profile);
+ return 0;
+ }
+
+ ret = devm_blk_crypto_profile_init(ctrl->ctrl.device, profile,
+ NVME_RDMA_NUM_CRYPTO_KEYSLOTS);
+ if (ret) {
+ dev_err(ctrl->ctrl.device,
+ "devm_blk_crypto_profile_init failed err %d\n", ret);
+ return ret;
+ }
+
+ profile->ll_ops = nvme_rdma_crypto_ops;
+ profile->dev = ctrl->ctrl.device;
+ profile->max_dun_bytes_supported = IB_CRYPTO_XTS_TWEAK_MAX_SIZE;
+ profile->modes_supported[BLK_ENCRYPTION_MODE_AES_256_XTS] =
+ NVME_RDMA_DATA_UNIT_SIZES;
+
+ return 0;
+}
+
+static void nvme_rdma_set_crypto_attrs(struct ib_crypto_attrs *crypto_attrs,
+ struct nvme_rdma_queue *queue, struct nvme_rdma_request *req)
+{
+ struct request *rq = blk_mq_rq_from_pdu(req);
+ u32 slot_idx = blk_crypto_keyslot_index(rq->crypt_keyslot);
+
+ memset(crypto_attrs, 0, sizeof(*crypto_attrs));
+
+ crypto_attrs->encrypt_domain = IB_CRYPTO_ENCRYPTED_WIRE_DOMAIN;
+ crypto_attrs->encrypt_standard = IB_CRYPTO_AES_XTS;
+ crypto_attrs->data_unit_size =
+ rq->crypt_ctx->bc_key->crypto_cfg.data_unit_size;
+ crypto_attrs->dek = queue->ctrl->dek[slot_idx]->id;
+ memcpy(crypto_attrs->xts_init_tweak, rq->crypt_ctx->bc_dun,
+ sizeof(crypto_attrs->xts_init_tweak));
+}
+
+static int nvme_rdma_fill_crypto_caps(struct nvme_rdma_ctrl *ctrl, bool new)
+{
+ struct ib_crypto_caps *caps = &ctrl->device->dev->attrs.crypto_caps;
+
+ if (caps->crypto_engines & IB_CRYPTO_ENGINES_CAP_AES_XTS) {
+ ctrl->ctrl.crypto_enable = true;
+ return 0;
+ }
+
+ if (!new && ctrl->ctrl.crypto_enable) {
+ dev_err(ctrl->ctrl.device, "Must support crypto!\n");
+ return -EOPNOTSUPP;
+ }
+ ctrl->ctrl.crypto_enable = false;
+
+ return 0;
+}
+#else
+static int nvme_rdma_crypto_profile_init(struct nvme_rdma_ctrl *ctrl, bool new)
+{
+ return -EOPNOTSUPP;
+}
+
+static void nvme_rdma_set_crypto_attrs(struct ib_crypto_attrs *crypto_attrs,
+ struct nvme_rdma_queue *queue, struct nvme_rdma_request *req)
+{
+}
+
+static int nvme_rdma_fill_crypto_caps(struct nvme_rdma_ctrl *ctrl, bool new)
+{
+ return 0;
+}
+#endif /* CONFIG_BLK_INLINE_ENCRYPTION */
+
static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
bool new)
{
@@ -835,6 +1029,10 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
ctrl->max_fr_pages = nvme_rdma_get_max_fr_pages(ctrl->device->dev,
pi_capable);
+ error = nvme_rdma_fill_crypto_caps(ctrl, new);
+ if (error)
+ goto out_free_queue;
+
/*
* Bind the async event SQE DMA mapping to the admin queue lifetime.
* It's safe, since any chage in the underlying RDMA device will issue
@@ -870,6 +1068,12 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
else
ctrl->ctrl.max_integrity_segments = 0;
+ if (ctrl->ctrl.crypto_enable) {
+ error = nvme_rdma_crypto_profile_init(ctrl, new);
+ if (error)
+ goto out_quiesce_queue;
+ }
+
nvme_unquiesce_admin_queue(&ctrl->ctrl);
error = nvme_init_ctrl_finish(&ctrl->ctrl, false);
@@ -1268,6 +1472,8 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
if (req->use_sig_mr)
pool = &queue->qp->sig_mrs;
+ else if (req->use_crypto)
+ pool = &queue->qp->crypto_mrs;
if (req->mr) {
ib_mr_pool_put(queue->qp, pool, req->mr);
@@ -1331,9 +1537,13 @@ static int nvme_rdma_map_sg_fr(struct nvme_rdma_queue *queue,
int count)
{
struct nvme_keyed_sgl_desc *sg = &c->common.dptr.ksgl;
+ struct list_head *pool = &queue->qp->rdma_mrs;
int nr;
- req->mr = ib_mr_pool_get(queue->qp, &queue->qp->rdma_mrs);
+ if (req->use_crypto)
+ pool = &queue->qp->crypto_mrs;
+
+ req->mr = ib_mr_pool_get(queue->qp, pool);
if (WARN_ON_ONCE(!req->mr))
return -EAGAIN;
@@ -1344,18 +1554,24 @@ static int nvme_rdma_map_sg_fr(struct nvme_rdma_queue *queue,
nr = ib_map_mr_sg(req->mr, req->data_sgl.sg_table.sgl, count, NULL,
SZ_4K);
if (unlikely(nr < count)) {
- ib_mr_pool_put(queue->qp, &queue->qp->rdma_mrs, req->mr);
+ ib_mr_pool_put(queue->qp, pool, req->mr);
req->mr = NULL;
if (nr < 0)
return nr;
return -EINVAL;
}
+ if (req->use_crypto)
+ nvme_rdma_set_crypto_attrs(req->mr->crypto_attrs, queue, req);
+
ib_update_fast_reg_key(req->mr, ib_inc_rkey(req->mr->rkey));
req->reg_cqe.done = nvme_rdma_memreg_done;
memset(&req->reg_wr, 0, sizeof(req->reg_wr));
- req->reg_wr.wr.opcode = IB_WR_REG_MR;
+ if (req->use_crypto)
+ req->reg_wr.wr.opcode = IB_WR_REG_MR_CRYPTO;
+ else
+ req->reg_wr.wr.opcode = IB_WR_REG_MR;
req->reg_wr.wr.wr_cqe = &req->reg_cqe;
req->reg_wr.wr.num_sge = 0;
req->reg_wr.mr = req->mr;
@@ -1571,7 +1787,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
goto out;
}
- if (count <= dev->num_inline_segments) {
+ if (count <= dev->num_inline_segments && !req->use_crypto) {
if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) &&
queue->ctrl->use_inline_data &&
blk_rq_payload_bytes(rq) <=
@@ -2052,6 +2268,18 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
else
req->use_sig_mr = false;
+#ifdef CONFIG_BLK_INLINE_ENCRYPTION
+ if (rq->crypt_ctx) {
+ if (WARN_ON_ONCE(!queue->crypto_support)) {
+ err = -EIO;
+ goto err;
+ }
+ req->use_crypto = true;
+ } else {
+ req->use_crypto = false;
+ }
+#endif
+
err = nvme_rdma_map_data(queue, rq, c);
if (unlikely(err < 0)) {
dev_err(queue->ctrl->ctrl.device,
--
2.39.0
next prev parent reply other threads:[~2023-01-16 13:07 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-16 13:05 [PATCH rdma-next 00/13] Add RDMA inline crypto support Leon Romanovsky
2023-01-16 13:05 ` [PATCH mlx5-next 01/13] net/mlx5: Introduce crypto IFC bits and structures Leon Romanovsky
2023-01-16 13:05 ` [PATCH mlx5-next 02/13] net/mlx5: Introduce crypto capabilities macro Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 03/13] RDMA: Split kernel-only create QP flags from uverbs create QP flags Leon Romanovsky
2023-01-16 17:39 ` Jason Gunthorpe
2023-01-17 12:03 ` Leon Romanovsky
2023-01-17 13:49 ` Jason Gunthorpe
2023-01-17 14:14 ` Leon Romanovsky
2023-01-17 14:21 ` Jason Gunthorpe
2023-01-17 14:34 ` Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 04/13] RDMA/core: Add cryptographic device capabilities Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 05/13] RDMA/core: Add DEK management API Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 06/13] RDMA/core: Introduce MR type for crypto operations Leon Romanovsky
2023-01-17 19:40 ` Steven Rostedt
2023-01-16 13:05 ` [PATCH rdma-next 07/13] RDMA/core: Add support for creating crypto enabled QPs Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 08/13] RDMA/mlx5: Add cryptographic device capabilities Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 09/13] RDMA/mlx5: Add DEK management API Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 10/13] RDMA/mlx5: Add AES-XTS crypto support Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 11/13] nvme: Introduce a local variable Leon Romanovsky
2023-01-17 0:32 ` Chaitanya Kulkarni
2023-01-17 11:59 ` Leon Romanovsky
2023-01-16 13:05 ` [PATCH rdma-next 12/13] nvme: Add crypto profile at nvme controller Leon Romanovsky
2023-01-17 0:31 ` Chaitanya Kulkarni
2023-01-17 11:59 ` Leon Romanovsky
2023-01-16 13:06 ` Leon Romanovsky [this message]
2023-01-18 6:47 ` [PATCH rdma-next 00/13] Add RDMA inline crypto support Eric Biggers
2023-01-18 7:14 ` Chaitanya Kulkarni
2023-01-18 7:17 ` Eric Biggers
2023-01-18 8:22 ` Leon Romanovsky
2023-01-18 8:58 ` Israel Rukshin
2023-01-18 7:36 ` Christoph Hellwig
2023-01-18 14:20 ` Max Gurtovoy
2023-01-30 12:35 ` Christoph Hellwig
2023-01-30 14:33 ` Max Gurtovoy
2023-02-14 10:01 ` Sagi Grimberg
2023-01-23 11:27 ` Sagi Grimberg
2023-01-23 12:57 ` Israel Rukshin
2023-01-30 12:36 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ab0817fac98d498372fd32e950d1ca6e157b575d.1673873422.git.leon@kernel.org \
--to=leon@kernel.org \
--cc=axboe@fb.com \
--cc=bryantan@vmware.com \
--cc=edumazet@google.com \
--cc=hch@lst.de \
--cc=israelr@nvidia.com \
--cc=jgg@nvidia.com \
--cc=kbusch@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mgurtovoy@nvidia.com \
--cc=mhiramat@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rostedt@goodmis.org \
--cc=saeedm@nvidia.com \
--cc=sagi@grimberg.me \
--cc=selvin.xavier@broadcom.com \
--cc=vdasa@vmware.com \
--cc=yishaih@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).