[PATCH V3] nvme: enable char device per namespace
Keith Busch
kbusch at kernel.org
Wed Dec 16 11:26:31 EST 2020
On Wed, Dec 16, 2020 at 09:01:51AM +0100, Javier González wrote:
> > On 15 Dec 2020, at 23.46, Keith Busch <kbusch at kernel.org> wrote:
> > On Tue, Dec 15, 2020 at 08:55:57PM +0100, javier at javigon.com wrote:
> >> +static int nvme_alloc_chardev_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
> >> +{
> >> + char cdisk_name[DISK_NAME_LEN];
> >> + int ret;
> >> +
> >> + device_initialize(&ns->cdev_device);
> >> + ns->cdev_device.devt = MKDEV(MAJOR(nvme_ns_base_chr_devt),
> >> + ns->head->instance);
> >
> > Ah, I see now. We are making these generic handles for each path, but
> > the ns->head->instance is the same for all paths to a namespace, so it's
> > not unique for that. Further, that head->instance is allocated per
> > subsystem, so it's not unique from namespace heads seen in other
> > subsystems.
> >
> > So, I think you need to allocate a new dev_t for each subsystem rather
> > than the global nvme_ns_base_chr_devt, and I guess we also need a new
> > nvme_ns instance field assigned from yet another ida?
>
> Ok. I’ll look into it.
The suggestion may be overkill as we don't need unique majors for each
controller right now (that may change if people need more than a
million generic handles, but I think we're a ways off from that reality).
The following on top of your patch makes it all work for me. Also, I
don't think we should abort adding the namespace if the generic handle
fails, so that's included here too:
---
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index c1aa4bccdeb2..cc9eaf4eba32 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -86,6 +86,8 @@ static DEFINE_MUTEX(nvme_subsystems_lock);
static DEFINE_IDA(nvme_instance_ida);
static dev_t nvme_ctrl_base_chr_devt;
+
+static DEFINE_IDA(nvme_gen_minor_ida);
static dev_t nvme_ns_base_chr_devt;
static struct class *nvme_class;
static struct class *nvme_ns_class;
@@ -539,7 +541,8 @@ static void nvme_free_ns(struct kref *kref)
if (ns->ndev)
nvme_nvm_unregister(ns);
-
+ if (ns->minor)
+ ida_simple_remove(&nvme_gen_minor_ida, ns->minor - 1);
cdev_device_del(&ns->cdev, &ns->cdev_device);
put_disk(ns->disk);
nvme_put_ns_head(ns->head);
@@ -3932,9 +3935,13 @@ static int nvme_alloc_chardev_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
char cdisk_name[DISK_NAME_LEN];
int ret;
+ ret = ida_simple_get(&nvme_gen_minor_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+
+ ns->minor = ret + 1;
device_initialize(&ns->cdev_device);
- ns->cdev_device.devt = MKDEV(MAJOR(nvme_ns_base_chr_devt),
- ns->head->instance);
+ ns->cdev_device.devt = MKDEV(MAJOR(nvme_ns_base_chr_devt), ret);
ns->cdev_device.class = nvme_ns_class;
ns->cdev_device.parent = ctrl->device;
ns->cdev_device.groups = nvme_ns_char_id_attr_groups;
@@ -3945,15 +3952,22 @@ static int nvme_alloc_chardev_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
ret = dev_set_name(&ns->cdev_device, "%s", cdisk_name);
if (ret)
- return ret;
+ goto put_ida;
cdev_init(&ns->cdev, &nvme_cdev_fops);
ns->cdev.owner = ctrl->ops->module;
ret = cdev_device_add(&ns->cdev, &ns->cdev_device);
if (ret)
- kfree_const(ns->cdev_device.kobj.name);
+ goto free_kobj;
+
+ return ret;
+free_kobj:
+ kfree_const(ns->cdev_device.kobj.name);
+put_ida:
+ ida_simple_remove(&nvme_gen_minor_ida, ns->minor - 1);
+ ns->minor = 0;
return ret;
}
@@ -4023,7 +4037,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
if (nvme_alloc_chardev_ns(ctrl, ns))
- goto out_put_disk;
+ dev_warn(ctrl->device,
+ "failed to create generic handle for nsid:%d\n",
+ nsid);
kfree(id);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 168c7719cda4..ccfd49d2a030 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -435,6 +435,7 @@ struct nvme_ns {
struct device cdev_device; /* char device */
struct cdev cdev;
+ int minor;
int lba_shift;
u16 ms;
--
More information about the Linux-nvme
mailing list