[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH v3] hw/nvme:Adding Support for namespace management
From: |
Lukasz Maniak |
Subject: |
Re: [RFC PATCH v3] hw/nvme:Adding Support for namespace management |
Date: |
Wed, 24 Nov 2021 19:46:38 +0100 |
On Tue, Nov 23, 2021 at 11:11:37AM +0100, Lukasz Maniak wrote:
> On Wed, Nov 10, 2021 at 04:56:29PM +0530, Naveen wrote:
> > From: Naveen Nagar <naveen.n1@samsung.com>
> >
> > This patch supports namespace management : create and delete operations
> > This patch has been tested with the following command and size of image
> > file for unallocated namespaces is taken as 0GB. ns_create will look into
> > the list of unallocated namespaces and it will initialize the same and
> > return the nsid of the same. A new mandatory field has been added called
> > tnvmcap and we have ensured that the total capacity of namespace created
> > does not exceed tnvmcap
> >
> > -device nvme-subsys,id=subsys0,tnvmcap=8
> > -device nvme,serial=foo,id=nvme0,subsys=subsys0
> > -device nvme,serial=bar,id=nvme1,subsys=subsys0
> >
> > -drive id=ns1,file=ns1.img,if=none
> > -device nvme-ns,drive=ns1,bus=nvme0,nsid=1,zoned=false,shared=true
> > -drive id=ns2,file=ns2.img,if=none
> > -device nvme-ns,drive=ns2,bus=nvme0,nsid=2,zoned=false,shared=true
> > -drive id=ns3,file=ns3.img,if=none
> > -device nvme-ns,drive=ns3,bus=nvme0,nsid=3,zoned=false,shared=true
> > -drive id=ns4,file=ns4.img,if=none
> > -device nvme-ns,drive=ns4,bus=nvme0,nsid=4,zoned=false,shared=true
> >
> > Please review and suggest if any changes are required.
> >
> > Signed-off-by: Naveen Nagar <naveen.n1@samsung.com>
> >
> > Since v2:
> > -Lukasz Maniak found a bug in namespace attachment and proposed
> > solution is added
> >
>
> Hi Naveen,
>
> The current implementation is inconsistent and thus has a bug related to
> unvmcap support.
>
> Namespaces are pre-allocated after boot, and the initial namespace size
> is the size of the associated blockdev. If the blockdevs are non-zero
> sized then the first deletion of the namespaces associated with them
> will increment unvmcap by their size. This will make unvmcap greater
> than tnvmcap.
>
> While the easiest way would be to prohibit the use of non-zero sized
> blockdev with namespace management, doing so would limit the
> functionality of the namespaces itself, which we would like to avoid.
>
> This fix below addresses issues related to unvmcap and non-zero block
> devices. The unvmcap value will be properly updated on both the first
> and subsequent controllers added to the subsystem regardless of the
> order in which nvme-ns is defined on the command line before or after
> the controller definition. Additionally, if the block device size of any
> namespace causes the unvmcap to be exceeded, an error will be returned
> at the namespace definition point.
>
> The fix is based on v3 based on v6.1.0, as v3 does not apply to master.
>
> ---
> hw/nvme/ctrl.c | 7 +++++++
> hw/nvme/ns.c | 23 ++++++++++++++++++++---
> 2 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
> index 63ea2fcb14..dc0ad4155b 100644
> --- a/hw/nvme/ctrl.c
> +++ b/hw/nvme/ctrl.c
> @@ -6594,6 +6594,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice
> *pci_dev)
> NvmeIdCtrl *id = &n->id_ctrl;
> uint8_t *pci_conf = pci_dev->config;
> uint64_t cap = ldq_le_p(&n->bar.cap);
> + int i;
>
> id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
> id->ssvid = cpu_to_le16(pci_get_word(pci_conf +
> PCI_SUBSYSTEM_VENDOR_ID));
> @@ -6672,6 +6673,12 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice
> *pci_dev)
> id->cmic |= NVME_CMIC_MULTI_CTRL;
> id->tnvmcap = n->subsys->params.tnvmcap * GiB;
> id->unvmcap = n->subsys->params.tnvmcap * GiB;
> +
> + for (i = 0; i < ARRAY_SIZE(n->subsys->namespaces); i++) {
> + if (n->subsys->namespaces[i]) {
> + id->unvmcap -= le64_to_cpu(n->subsys->namespaces[i]->size);
> + }
> + }
> }
>
> NVME_CAP_SET_MQES(cap, 0x7ff);
> diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
> index f62a695132..c87d7f5bd6 100644
> --- a/hw/nvme/ns.c
> +++ b/hw/nvme/ns.c
> @@ -140,9 +140,12 @@ lbaf_found:
> return 0;
> }
>
> -static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
> +static int nvme_ns_init_blk(NvmeNamespace *ns, NvmeSubsystem *subsys,
> + Error **errp)
> {
> bool read_only;
> + NvmeCtrl *ctrl;
> + int i;
>
> if (!blkconf_blocksizes(&ns->blkconf, errp)) {
> return -1;
> @@ -164,6 +167,21 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error
> **errp)
> return -1;
> }
>
> + if (subsys) {
> + for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
> + ctrl = nvme_subsys_ctrl(subsys, i);
> +
> + if (ctrl) {
> + if (ctrl->id_ctrl.unvmcap < le64_to_cpu(ns->size)) {
> + error_setg(errp, "blockdev size %ld exceeds subsystem's "
> + "unallocated capacity", ns->size);
> + } else {
> + ctrl->id_ctrl.unvmcap -= le64_to_cpu(ns->size);
> + }
> + }
> + }
> + }
> +
> return 0;
> }
>
> @@ -480,7 +498,7 @@ static void nvme_ns_realize(DeviceState *dev, Error
> **errp)
> }
> }
>
> - if (nvme_ns_init_blk(ns, errp)) {
> + if (nvme_ns_init_blk(ns, subsys, errp)) {
> return;
> }
>
> @@ -527,7 +545,6 @@ static void nvme_ns_realize(DeviceState *dev, Error
> **errp)
>
> if (ctrl) {
> nvme_attach_ns(ctrl, ns);
> - ctrl->id_ctrl.unvmcap -= le64_to_cpu(ns->size);
> }
> }
>
> --
> 2.25.1
>
Fixing unvmcap support brought another concern to attention.
Here is another little patch on top of the previous one to truncate the
block device to 0 when the associated namespace is deleted.
Instead, it may fail to re-launch QEMU with the blockdevs from the
previous execution when the sum of the blockdev sizes after namespace
management exceeds unvmcap.
---
hw/nvme/ctrl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index dc0ad4155b..f84f682d36 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -5320,6 +5320,7 @@ static void nvme_namespace_delete(NvmeCtrl *n,
NvmeNamespace *ns, uint32_t nsid)
{
NvmeCtrl *ctrl;
NvmeSubsystem *subsys = n->subsys;
+ int ret;
subsys->namespaces[nsid] = NULL;
QSLIST_INSERT_HEAD(&subsys->unallocated_namespaces, ns, entry);
@@ -5334,6 +5335,9 @@ static void nvme_namespace_delete(NvmeCtrl *n,
NvmeNamespace *ns, uint32_t nsid)
nvme_ns_attr_changed_aer(ctrl, nsid);
}
}
+
+ ret = nvme_blk_truncate(ns->blkconf.blk, 0, NULL);
+ assert(!ret);
}
static uint16_t nvme_ns_management(NvmeCtrl *n, NvmeRequest *req)
--
2.25.1