Commit 98141430 authored by Jens Axboe's avatar Jens Axboe
Browse files

Merge tag 'nvme-6.12-2024-09-06' of git://git.infradead.org/nvme into for-6.12/block

Pull NVMe updates from Keith:

"nvme updates for Linux 6.12

 - Asynchronous namespace scanning (Stuart)
 - TCP TLS updates (Hannes)
 - RDMA queue controller validation (Niklas)
 - Align field names to the spec (Anuj)
 - Metadata support validation (Puranjay)"

* tag 'nvme-6.12-2024-09-06' of git://git.infradead.org/nvme:
  nvme: fix metadata handling in nvme-passthrough
  nvme: rename apptag and appmask to lbat and lbatm
  nvme-rdma: send cntlid in the RDMA_CM_REQUEST Private Data
  nvme-target: do not check authentication status for admin commands twice
  nvmet-auth: allow to clear DH-HMAC-CHAP keys
  nvme-sysfs: add 'tls_keyring' attribute
  nvme-sysfs: add 'tls_configured_key' sysfs attribute
  nvme: split off TLS sysfs attributes into a separate group
  nvme: add a newline to the 'tls_key' sysfs attribute
  nvme-tcp: check for invalidated or revoked key
  nvme-tcp: sanitize TLS key handling
  nvme-keyring: restrict match length for version '1' identifiers
  nvme_core: scan namespaces asynchronously
parents 68d20eb6 7c2fd760
Loading
Loading
Loading
Loading
+48 −10
Original line number Diff line number Diff line
@@ -20,6 +20,28 @@ key_serial_t nvme_keyring_id(void)
}
EXPORT_SYMBOL_GPL(nvme_keyring_id);

static bool nvme_tls_psk_revoked(struct key *psk)
{
	return test_bit(KEY_FLAG_REVOKED, &psk->flags) ||
		test_bit(KEY_FLAG_INVALIDATED, &psk->flags);
}

struct key *nvme_tls_key_lookup(key_serial_t key_id)
{
	struct key *key = key_lookup(key_id);

	if (IS_ERR(key)) {
		pr_err("key id %08x not found\n", key_id);
		return key;
	}
	if (nvme_tls_psk_revoked(key)) {
		pr_err("key id %08x revoked\n", key_id);
		return ERR_PTR(-EKEYREVOKED);
	}
	return key;
}
EXPORT_SYMBOL_GPL(nvme_tls_key_lookup);

static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
{
	seq_puts(m, key->description);
@@ -36,14 +58,12 @@ static bool nvme_tls_psk_match(const struct key *key,
		pr_debug("%s: no key description\n", __func__);
		return false;
	}
	match_len = strlen(key->description);
	pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);

	if (!match_data->raw_data) {
		pr_debug("%s: no match data\n", __func__);
		return false;
	}
	match_id = match_data->raw_data;
	match_len = strlen(match_id);
	pr_debug("%s: match '%s' '%s' len %zd\n",
		 __func__, match_id, key->description, match_len);
	return !memcmp(key->description, match_id, match_len);
@@ -71,7 +91,7 @@ static struct key_type nvme_tls_psk_key_type = {

static struct key *nvme_tls_psk_lookup(struct key *keyring,
		const char *hostnqn, const char *subnqn,
		int hmac, bool generated)
		u8 hmac, u8 psk_ver, bool generated)
{
	char *identity;
	size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
@@ -82,8 +102,8 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
	if (!identity)
		return ERR_PTR(-ENOMEM);

	snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
		 generated ? 'G' : 'R', hmac, hostnqn, subnqn);
	snprintf(identity, identity_len, "NVMe%u%c%02u %s %s",
		 psk_ver, generated ? 'G' : 'R', hmac, hostnqn, subnqn);

	if (!keyring)
		keyring = nvme_keyring;
@@ -107,21 +127,38 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
/*
 * NVMe PSK priority list
 *
 * 'Retained' PSKs (ie 'generated == false')
 * should be preferred to 'generated' PSKs,
 * and SHA-384 should be preferred to SHA-256.
 * 'Retained' PSKs (ie 'generated == false') should be preferred to 'generated'
 * PSKs, PSKs with hash (psk_ver 1) should be preferred to PSKs without hash
 * (psk_ver 0), and SHA-384 should be preferred to SHA-256.
 */
static struct nvme_tls_psk_priority_list {
	bool generated;
	u8 psk_ver;
	enum nvme_tcp_tls_cipher cipher;
} nvme_tls_psk_prio[] = {
	{ .generated = false,
	  .psk_ver = 1,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
	{ .generated = false,
	  .psk_ver = 1,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
	{ .generated = false,
	  .psk_ver = 0,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
	{ .generated = false,
	  .psk_ver = 0,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
	{ .generated = true,
	  .psk_ver = 1,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
	{ .generated = true,
	  .psk_ver = 1,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
	{ .generated = true,
	  .psk_ver = 0,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
	{ .generated = true,
	  .psk_ver = 0,
	  .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
};

@@ -137,10 +174,11 @@ key_serial_t nvme_tls_psk_default(struct key *keyring,

	for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
		bool generated = nvme_tls_psk_prio[prio].generated;
		u8 ver = nvme_tls_psk_prio[prio].psk_ver;
		enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;

		tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
					      cipher, generated);
					      cipher, ver, generated);
		if (!IS_ERR(tls_key)) {
			tls_key_id = tls_key->serial;
			key_put(tls_key);
+1 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ config NVME_HOST_AUTH
	bool "NVMe over Fabrics In-Band Authentication in host side"
	depends on NVME_CORE
	select NVME_AUTH
	select NVME_KEYRING if NVME_TCP_TLS
	help
	  This provides support for NVMe over Fabrics In-Band Authentication in
	  host side.
+41 −4
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Copyright (c) 2011-2014, Intel Corporation.
 */

#include <linux/async.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/blk-integrity.h>
@@ -986,8 +987,8 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
	cmnd->rw.length =
		cpu_to_le16((blk_rq_bytes(req) >> ns->head->lba_shift) - 1);
	cmnd->rw.reftag = 0;
	cmnd->rw.apptag = 0;
	cmnd->rw.appmask = 0;
	cmnd->rw.lbat = 0;
	cmnd->rw.lbatm = 0;

	if (ns->head->ms) {
		/*
@@ -4040,6 +4041,35 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid)
	}
}

/**
 * struct async_scan_info - keeps track of controller & NSIDs to scan
 * @ctrl:	Controller on which namespaces are being scanned
 * @next_nsid:	Index of next NSID to scan in ns_list
 * @ns_list:	Pointer to list of NSIDs to scan
 *
 * Note: There is a single async_scan_info structure shared by all instances
 * of nvme_scan_ns_async() scanning a given controller, so the atomic
 * operations on next_nsid are critical to ensure each instance scans a unique
 * NSID.
 */
struct async_scan_info {
	struct nvme_ctrl *ctrl;
	atomic_t next_nsid;
	__le32 *ns_list;
};

static void nvme_scan_ns_async(void *data, async_cookie_t cookie)
{
	struct async_scan_info *scan_info = data;
	int idx;
	u32 nsid;

	idx = (u32)atomic_fetch_inc(&scan_info->next_nsid);
	nsid = le32_to_cpu(scan_info->ns_list[idx]);

	nvme_scan_ns(scan_info->ctrl, nsid);
}

static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
					unsigned nsid)
{
@@ -4066,11 +4096,15 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl)
	__le32 *ns_list;
	u32 prev = 0;
	int ret = 0, i;
	ASYNC_DOMAIN(domain);
	struct async_scan_info scan_info;

	ns_list = kzalloc(NVME_IDENTIFY_DATA_SIZE, GFP_KERNEL);
	if (!ns_list)
		return -ENOMEM;

	scan_info.ctrl = ctrl;
	scan_info.ns_list = ns_list;
	for (;;) {
		struct nvme_command cmd = {
			.identify.opcode	= nvme_admin_identify,
@@ -4086,19 +4120,23 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl)
			goto free;
		}

		atomic_set(&scan_info.next_nsid, 0);
		for (i = 0; i < nr_entries; i++) {
			u32 nsid = le32_to_cpu(ns_list[i]);

			if (!nsid)	/* end of the list? */
				goto out;
			nvme_scan_ns(ctrl, nsid);
			async_schedule_domain(nvme_scan_ns_async, &scan_info,
						&domain);
			while (++prev < nsid)
				nvme_ns_remove_by_nsid(ctrl, prev);
		}
		async_synchronize_full_domain(&domain);
	}
 out:
	nvme_remove_invalid_namespaces(ctrl, prev);
 free:
	async_synchronize_full_domain(&domain);
	kfree(ns_list);
	return ret;
}
@@ -4677,7 +4715,6 @@ static void nvme_free_ctrl(struct device *dev)

	if (!subsys || ctrl->instance != subsys->instance)
		ida_free(&nvme_instance_ida, ctrl->instance);
	key_put(ctrl->tls_key);
	nvme_free_cels(ctrl);
	nvme_mpath_uninit(ctrl);
	cleanup_srcu_struct(&ctrl->srcu);
+1 −1
Original line number Diff line number Diff line
@@ -665,7 +665,7 @@ static struct key *nvmf_parse_key(int key_id)
		return ERR_PTR(-EINVAL);
	}

	key = key_lookup(key_id);
	key = nvme_tls_key_lookup(key_id);
	if (IS_ERR(key))
		pr_err("key id %08x not found\n", key_id);
	else
+16 −10
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Copyright (c) 2017-2021 Christoph Hellwig.
 */
#include <linux/bio-integrity.h>
#include <linux/blk-integrity.h>
#include <linux/ptrace.h>	/* for force_successful_syscall_return */
#include <linux/nvme_ioctl.h>
#include <linux/io_uring/cmd.h>
@@ -119,9 +120,14 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
	struct request_queue *q = req->q;
	struct nvme_ns *ns = q->queuedata;
	struct block_device *bdev = ns ? ns->disk->part0 : NULL;
	bool supports_metadata = bdev && blk_get_integrity(bdev->bd_disk);
	bool has_metadata = meta_buffer && meta_len;
	struct bio *bio = NULL;
	int ret;

	if (has_metadata && !supports_metadata)
		return -EINVAL;

	if (ioucmd && (ioucmd->flags & IORING_URING_CMD_FIXED)) {
		struct iov_iter iter;

@@ -143,16 +149,16 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
		goto out;

	bio = req->bio;
	if (bdev) {
	if (bdev)
		bio_set_dev(bio, bdev);
		if (meta_buffer && meta_len) {

	if (has_metadata) {
		ret = bio_integrity_map_user(bio, meta_buffer, meta_len,
					     meta_seed);
		if (ret)
			goto out_unmap;
		req->cmd_flags |= REQ_INTEGRITY;
	}
	}

	return ret;

@@ -260,8 +266,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
	c.rw.control = cpu_to_le16(io.control);
	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
	c.rw.reftag = cpu_to_le32(io.reftag);
	c.rw.apptag = cpu_to_le16(io.apptag);
	c.rw.appmask = cpu_to_le16(io.appmask);
	c.rw.lbat = cpu_to_le16(io.apptag);
	c.rw.lbatm = cpu_to_le16(io.appmask);

	return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata,
			meta_len, lower_32_bits(io.slba), NULL, 0, 0);
Loading