Skip to content

Commit ba76af6

Browse files
lsgunthChristoph Hellwig
authored andcommitted
nvmet: Add passthru enable/disable helpers
This patch adds helper functions which are used in the NVMeOF configfs when the user is configuring the passthru subsystem. Here we ensure that only one subsys is assigned to each nvme_ctrl by using an xarray on the cntlid. The subsystem's version number is overridden by the passed through controller's version. However, if that version is less than 1.2.1, then we bump the advertised version to that and print a warning in dmesg. Based-on-a-patch-by: Chaitanya Kulkarni <[email protected]> Signed-off-by: Logan Gunthorpe <[email protected]> Reviewed-by: Keith Busch <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent c1fef73 commit ba76af6

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

drivers/nvme/target/configfs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
879879
int major, minor, tertiary = 0;
880880
int ret;
881881

882+
/* passthru subsystems use the underlying controller's version */
883+
if (nvmet_passthru_ctrl(subsys))
884+
return -EINVAL;
885+
882886
ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
883887
if (ret != 2 && ret != 3)
884888
return -EINVAL;

drivers/nvme/target/core.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,12 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
544544

545545
mutex_lock(&subsys->lock);
546546
ret = 0;
547+
548+
if (nvmet_passthru_ctrl(subsys)) {
549+
pr_info("cannot enable both passthru and regular namespaces for a single subsystem");
550+
goto out_unlock;
551+
}
552+
547553
if (ns->enabled)
548554
goto out_unlock;
549555

@@ -1473,7 +1479,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
14731479
if (!subsys)
14741480
return ERR_PTR(-ENOMEM);
14751481

1476-
subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
1482+
subsys->ver = NVMET_DEFAULT_VS;
14771483
/* generate a random serial number as our controllers are ephemeral: */
14781484
get_random_bytes(&subsys->serial, sizeof(subsys->serial));
14791485

@@ -1516,6 +1522,8 @@ static void nvmet_subsys_free(struct kref *ref)
15161522
WARN_ON_ONCE(!xa_empty(&subsys->namespaces));
15171523

15181524
xa_destroy(&subsys->namespaces);
1525+
nvmet_passthru_subsys_free(subsys);
1526+
15191527
kfree(subsys->subsysnqn);
15201528
kfree_rcu(subsys->model, rcuhead);
15211529
kfree(subsys);

drivers/nvme/target/nvmet.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <linux/radix-tree.h>
2222
#include <linux/t10-pi.h>
2323

24+
#define NVMET_DEFAULT_VS NVME_VS(1, 3, 0)
25+
2426
#define NVMET_ASYNC_EVENTS 4
2527
#define NVMET_ERROR_LOG_SLOTS 128
2628
#define NVMET_NO_ERROR_LOC ((u16)-1)
@@ -245,6 +247,7 @@ struct nvmet_subsys {
245247

246248
#ifdef CONFIG_NVME_TARGET_PASSTHRU
247249
struct nvme_ctrl *passthru_ctrl;
250+
char *passthru_ctrl_path;
248251
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
249252
};
250253

@@ -544,13 +547,22 @@ static inline u32 nvmet_dsm_len(struct nvmet_req *req)
544547
}
545548

546549
#ifdef CONFIG_NVME_TARGET_PASSTHRU
550+
void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys);
551+
int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys);
552+
void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys);
547553
u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req);
548554
u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req);
549555
static inline struct nvme_ctrl *nvmet_passthru_ctrl(struct nvmet_subsys *subsys)
550556
{
551557
return subsys->passthru_ctrl;
552558
}
553559
#else /* CONFIG_NVME_TARGET_PASSTHRU */
560+
static inline void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys)
561+
{
562+
}
563+
static inline void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
564+
{
565+
}
554566
static inline u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
555567
{
556568
return 0;

drivers/nvme/target/passthru.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616
MODULE_IMPORT_NS(NVME_TARGET_PASSTHRU);
1717

18+
/*
19+
* xarray to maintain one passthru subsystem per nvme controller.
20+
*/
21+
static DEFINE_XARRAY(passthru_subsystems);
22+
1823
static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
1924
{
2025
struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -456,3 +461,84 @@ u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
456461
return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
457462
}
458463
}
464+
465+
int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys)
466+
{
467+
struct nvme_ctrl *ctrl;
468+
int ret = -EINVAL;
469+
void *old;
470+
471+
mutex_lock(&subsys->lock);
472+
if (!subsys->passthru_ctrl_path)
473+
goto out_unlock;
474+
if (subsys->passthru_ctrl)
475+
goto out_unlock;
476+
477+
if (subsys->nr_namespaces) {
478+
pr_info("cannot enable both passthru and regular namespaces for a single subsystem");
479+
goto out_unlock;
480+
}
481+
482+
ctrl = nvme_ctrl_get_by_path(subsys->passthru_ctrl_path);
483+
if (IS_ERR(ctrl)) {
484+
ret = PTR_ERR(ctrl);
485+
pr_err("failed to open nvme controller %s\n",
486+
subsys->passthru_ctrl_path);
487+
488+
goto out_unlock;
489+
}
490+
491+
old = xa_cmpxchg(&passthru_subsystems, ctrl->cntlid, NULL,
492+
subsys, GFP_KERNEL);
493+
if (xa_is_err(old)) {
494+
ret = xa_err(old);
495+
goto out_put_ctrl;
496+
}
497+
498+
if (old)
499+
goto out_put_ctrl;
500+
501+
subsys->passthru_ctrl = ctrl;
502+
subsys->ver = ctrl->vs;
503+
504+
if (subsys->ver < NVME_VS(1, 2, 1)) {
505+
pr_warn("nvme controller version is too old: %llu.%llu.%llu, advertising 1.2.1\n",
506+
NVME_MAJOR(subsys->ver), NVME_MINOR(subsys->ver),
507+
NVME_TERTIARY(subsys->ver));
508+
subsys->ver = NVME_VS(1, 2, 1);
509+
}
510+
511+
mutex_unlock(&subsys->lock);
512+
return 0;
513+
514+
out_put_ctrl:
515+
nvme_put_ctrl(ctrl);
516+
out_unlock:
517+
mutex_unlock(&subsys->lock);
518+
return ret;
519+
}
520+
521+
static void __nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
522+
{
523+
if (subsys->passthru_ctrl) {
524+
xa_erase(&passthru_subsystems, subsys->passthru_ctrl->cntlid);
525+
nvme_put_ctrl(subsys->passthru_ctrl);
526+
}
527+
subsys->passthru_ctrl = NULL;
528+
subsys->ver = NVMET_DEFAULT_VS;
529+
}
530+
531+
void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
532+
{
533+
mutex_lock(&subsys->lock);
534+
__nvmet_passthru_ctrl_disable(subsys);
535+
mutex_unlock(&subsys->lock);
536+
}
537+
538+
void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys)
539+
{
540+
mutex_lock(&subsys->lock);
541+
__nvmet_passthru_ctrl_disable(subsys);
542+
mutex_unlock(&subsys->lock);
543+
kfree(subsys->passthru_ctrl_path);
544+
}

0 commit comments

Comments
 (0)