diff mbox series

[V3,1/8] hw/block/nvme: support namespace detach

Message ID 20210228161100.54015-2-minwoo.im.dev@gmail.com
State New
Headers show
Series hw/block/nvme: support namespace attachment | expand

Commit Message

Minwoo Im Feb. 28, 2021, 4:10 p.m. UTC
Given that now we have nvme-subsys device supported, we can manage
namespace allocated, but not attached: detached.  This patch introduced
a parameter for nvme-ns device named 'detached'.  This parameter
indicates whether the given namespace device is detached from
a entire NVMe subsystem('subsys' given case, shared namespace) or a
controller('bus' given case, private namespace).

- Allocated namespace

  1) Shared ns in the subsystem 'subsys0':

     -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,subsys=subsys0,detached=true

  2) Private ns for the controller 'nvme0' of the subsystem 'subsys0':

     -device nvme-subsys,id=subsys0
     -device nvme,serial=foo,id=nvme0,subsys=subsys0
     -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true

  3) (Invalid case) Controller 'nvme0' has no subsystem to manage ns:

     -device nvme,serial=foo,id=nvme0
     -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true

Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
Tested-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
---
 hw/block/nvme-ns.c     |  1 +
 hw/block/nvme-ns.h     |  1 +
 hw/block/nvme-subsys.h |  1 +
 hw/block/nvme.c        | 41 +++++++++++++++++++++++++++++++++++++++--
 hw/block/nvme.h        | 22 ++++++++++++++++++++++
 5 files changed, 64 insertions(+), 2 deletions(-)

Comments

Keqian Zhu March 15, 2021, 4:56 a.m. UTC | #1
Hi,

I don't dig into code logic, just some nit below.

On 2021/3/1 0:10, Minwoo Im wrote:
> Given that now we have nvme-subsys device supported, we can manage
> namespace allocated, but not attached: detached.  This patch introduced
s/introduced/introduces

> a parameter for nvme-ns device named 'detached'.  This parameter
> indicates whether the given namespace device is detached from
> a entire NVMe subsystem('subsys' given case, shared namespace) or a
> controller('bus' given case, private namespace).
> 
> - Allocated namespace
> 
>   1) Shared ns in the subsystem 'subsys0':
> 
>      -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,subsys=subsys0,detached=true
> 
>   2) Private ns for the controller 'nvme0' of the subsystem 'subsys0':
> 
>      -device nvme-subsys,id=subsys0
>      -device nvme,serial=foo,id=nvme0,subsys=subsys0
>      -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true
> 
>   3) (Invalid case) Controller 'nvme0' has no subsystem to manage ns:
> 
>      -device nvme,serial=foo,id=nvme0
>      -device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true
> 
> Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
> Tested-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
> ---
>  hw/block/nvme-ns.c     |  1 +
>  hw/block/nvme-ns.h     |  1 +
>  hw/block/nvme-subsys.h |  1 +
>  hw/block/nvme.c        | 41 +++++++++++++++++++++++++++++++++++++++--
>  hw/block/nvme.h        | 22 ++++++++++++++++++++++
>  5 files changed, 64 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
> index 0e8760020483..eda6a0c003a4 100644
> --- a/hw/block/nvme-ns.c
> +++ b/hw/block/nvme-ns.c
> @@ -399,6 +399,7 @@ static Property nvme_ns_props[] = {
>      DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
>      DEFINE_PROP_LINK("subsys", NvmeNamespace, subsys, TYPE_NVME_SUBSYS,
>                       NvmeSubsystem *),
> +    DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false),
>      DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
>      DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
>      DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128),
> diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
> index 7af6884862b5..b0c00e115d81 100644
> --- a/hw/block/nvme-ns.h
> +++ b/hw/block/nvme-ns.h
> @@ -26,6 +26,7 @@ typedef struct NvmeZone {
>  } NvmeZone;
>  
>  typedef struct NvmeNamespaceParams {
> +    bool     detached;
>      uint32_t nsid;
>      QemuUUID uuid;
>  
> diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h
> index ccf6a71398d3..890d118117dc 100644
> --- a/hw/block/nvme-subsys.h
> +++ b/hw/block/nvme-subsys.h
> @@ -23,6 +23,7 @@ typedef struct NvmeSubsystem {
>      uint8_t     subnqn[256];
>  
>      NvmeCtrl    *ctrls[NVME_SUBSYS_MAX_CTRLS];
> +    /* Allocated namespaces for this subsystem */
>      NvmeNamespace *namespaces[NVME_SUBSYS_MAX_NAMESPACES];
>  } NvmeSubsystem;
>  
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index edd0b85c10ce..f6aeae081840 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -23,7 +23,7 @@
>   *              max_ioqpairs=<N[optional]>, \
>   *              aerl=<N[optional]>, aer_max_queued=<N[optional]>, \
>   *              mdts=<N[optional]>,zoned.append_size_limit=<N[optional]>, \
> - *              subsys=<subsys_id> \
> + *              subsys=<subsys_id>,detached=<true|false[optional]>
>   *      -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
>   *              zoned=<true|false[optional]>, \
>   *              subsys=<subsys_id>
> @@ -82,6 +82,13 @@
>   *   controllers in the subsystem. Otherwise, `bus` must be given to attach
>   *   this namespace to a specified single controller as a non-shared namespace.
>   *
> + * - `detached`
> + *   Not to attach the namespace device to controllers in the NVMe subsystem
> + *   during boot-up. If not given, namespaces are all attahced to all
s/attahced/attached

> + *   controllers in the subsystem by default.
> + *   It's mutual exclusive with 'bus' parameter. It's only valid in case
> + *   `subsys` is provided.
> + *
>   * Setting `zoned` to true selects Zoned Command Set at the namespace.
>   * In this case, the following namespace properties are available to configure
>   * zoned operation:
> @@ -4613,6 +4620,20 @@ static void nvme_init_state(NvmeCtrl *n)
>      n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1);
>  }
>  
> +static int nvme_attach_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
> +{
> +    if (nvme_ns_is_attached(n, ns)) {
> +        error_setg(errp,
> +                   "namespace %d is already attached to controller %d",
> +                   nvme_nsid(ns), n->cntlid);
> +        return -1;
> +    }
> +
> +    nvme_ns_attach(n, ns);
> +
> +    return 0;
> +}
> +
>  int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
>  {
>      uint32_t nsid = nvme_nsid(ns);
> @@ -4644,7 +4665,23 @@ int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
>  
>      trace_pci_nvme_register_namespace(nsid);
>  
> -    n->namespaces[nsid - 1] = ns;
> +    /*
> +     * If subsys is not given, namespae is always attached to the controller
s/namespae/namespace

> +     * because there's no subsystem to manage namespace allocation.
> +     */
> +    if (!n->subsys) {
> +        if (ns->params.detached) {
> +            error_setg(errp,
> +                       "detached needs nvme-subsys specified nvme or nvme-ns");
> +            return -1;
> +        }
> +
> +        return nvme_attach_namespace(n, ns, errp);
> +    } else {
> +        if (!ns->params.detached) {
> +            return nvme_attach_namespace(n, ns, errp);
> +        }
> +    }
>  
>      return 0;
>  }
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index f45ace0cff5b..51b8739b4d1e 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -174,6 +174,10 @@ typedef struct NvmeCtrl {
>      NvmeSubsystem   *subsys;
>  
>      NvmeNamespace   namespace;
> +    /*
> +     * Attached namespaces to this controller.  If subsys is not given, all
> +     * namespaces in this list will always be attached.
> +     */
>      NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES];
>      NvmeSQueue      **sq;
>      NvmeCQueue      **cq;
> @@ -192,6 +196,24 @@ static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
>      return n->namespaces[nsid - 1];
>  }
>  
> +static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns)
> +{
> +    int nsid;
> +
> +    for (nsid = 1; nsid <= n->num_namespaces; nsid++) {
> +        if (nvme_ns(n, nsid) == ns) {
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
> +static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
> +{
> +    n->namespaces[nvme_nsid(ns) - 1] = ns;
> +}
> +
>  static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
>  {
>      NvmeSQueue *sq = req->sq;
>
Klaus Jensen March 16, 2021, 9:46 p.m. UTC | #2
On Mar 15 12:56, Keqian Zhu wrote:
> Hi,
> 
> I don't dig into code logic, just some nit below.
> 

Thanks! I'll cook up a fix with some corrections on these typos.
diff mbox series

Patch

diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index 0e8760020483..eda6a0c003a4 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -399,6 +399,7 @@  static Property nvme_ns_props[] = {
     DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
     DEFINE_PROP_LINK("subsys", NvmeNamespace, subsys, TYPE_NVME_SUBSYS,
                      NvmeSubsystem *),
+    DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false),
     DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
     DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
     DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128),
diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
index 7af6884862b5..b0c00e115d81 100644
--- a/hw/block/nvme-ns.h
+++ b/hw/block/nvme-ns.h
@@ -26,6 +26,7 @@  typedef struct NvmeZone {
 } NvmeZone;
 
 typedef struct NvmeNamespaceParams {
+    bool     detached;
     uint32_t nsid;
     QemuUUID uuid;
 
diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h
index ccf6a71398d3..890d118117dc 100644
--- a/hw/block/nvme-subsys.h
+++ b/hw/block/nvme-subsys.h
@@ -23,6 +23,7 @@  typedef struct NvmeSubsystem {
     uint8_t     subnqn[256];
 
     NvmeCtrl    *ctrls[NVME_SUBSYS_MAX_CTRLS];
+    /* Allocated namespaces for this subsystem */
     NvmeNamespace *namespaces[NVME_SUBSYS_MAX_NAMESPACES];
 } NvmeSubsystem;
 
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index edd0b85c10ce..f6aeae081840 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -23,7 +23,7 @@ 
  *              max_ioqpairs=<N[optional]>, \
  *              aerl=<N[optional]>, aer_max_queued=<N[optional]>, \
  *              mdts=<N[optional]>,zoned.append_size_limit=<N[optional]>, \
- *              subsys=<subsys_id> \
+ *              subsys=<subsys_id>,detached=<true|false[optional]>
  *      -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
  *              zoned=<true|false[optional]>, \
  *              subsys=<subsys_id>
@@ -82,6 +82,13 @@ 
  *   controllers in the subsystem. Otherwise, `bus` must be given to attach
  *   this namespace to a specified single controller as a non-shared namespace.
  *
+ * - `detached`
+ *   Not to attach the namespace device to controllers in the NVMe subsystem
+ *   during boot-up. If not given, namespaces are all attahced to all
+ *   controllers in the subsystem by default.
+ *   It's mutual exclusive with 'bus' parameter. It's only valid in case
+ *   `subsys` is provided.
+ *
  * Setting `zoned` to true selects Zoned Command Set at the namespace.
  * In this case, the following namespace properties are available to configure
  * zoned operation:
@@ -4613,6 +4620,20 @@  static void nvme_init_state(NvmeCtrl *n)
     n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1);
 }
 
+static int nvme_attach_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
+{
+    if (nvme_ns_is_attached(n, ns)) {
+        error_setg(errp,
+                   "namespace %d is already attached to controller %d",
+                   nvme_nsid(ns), n->cntlid);
+        return -1;
+    }
+
+    nvme_ns_attach(n, ns);
+
+    return 0;
+}
+
 int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
 {
     uint32_t nsid = nvme_nsid(ns);
@@ -4644,7 +4665,23 @@  int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
 
     trace_pci_nvme_register_namespace(nsid);
 
-    n->namespaces[nsid - 1] = ns;
+    /*
+     * If subsys is not given, namespae is always attached to the controller
+     * because there's no subsystem to manage namespace allocation.
+     */
+    if (!n->subsys) {
+        if (ns->params.detached) {
+            error_setg(errp,
+                       "detached needs nvme-subsys specified nvme or nvme-ns");
+            return -1;
+        }
+
+        return nvme_attach_namespace(n, ns, errp);
+    } else {
+        if (!ns->params.detached) {
+            return nvme_attach_namespace(n, ns, errp);
+        }
+    }
 
     return 0;
 }
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index f45ace0cff5b..51b8739b4d1e 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -174,6 +174,10 @@  typedef struct NvmeCtrl {
     NvmeSubsystem   *subsys;
 
     NvmeNamespace   namespace;
+    /*
+     * Attached namespaces to this controller.  If subsys is not given, all
+     * namespaces in this list will always be attached.
+     */
     NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES];
     NvmeSQueue      **sq;
     NvmeCQueue      **cq;
@@ -192,6 +196,24 @@  static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
     return n->namespaces[nsid - 1];
 }
 
+static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns)
+{
+    int nsid;
+
+    for (nsid = 1; nsid <= n->num_namespaces; nsid++) {
+        if (nvme_ns(n, nsid) == ns) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
+{
+    n->namespaces[nvme_nsid(ns) - 1] = ns;
+}
+
 static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
 {
     NvmeSQueue *sq = req->sq;