diff mbox series

[for-6.0,v2,4/8] hw/block/nvme: fix controller namespaces array indexing

Message ID 20210405175452.37578-5-its@irrelevant.dk
State New
Headers show
Series hw/block/nvme: misc fixes | expand

Commit Message

Klaus Jensen April 5, 2021, 5:54 p.m. UTC
From: Klaus Jensen <k.jensen@samsung.com>

The controller namespaces array being 0-indexed requires 'nsid - 1'
everywhere. Something that is easy to miss. Align the controller
namespaces array with the subsystem namespaces array such that both are
1-indexed.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
---
 hw/block/nvme.h | 8 ++++----
 hw/block/nvme.c | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

Comments

Philippe Mathieu-Daudé April 6, 2021, 7:01 a.m. UTC | #1
On 4/5/21 7:54 PM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
> 
> The controller namespaces array being 0-indexed requires 'nsid - 1'
> everywhere. Something that is easy to miss. Align the controller
> namespaces array with the subsystem namespaces array such that both are
> 1-indexed.

TBH I don't understand the justification. Assuming you hit a
bug and try to protect yourself, maybe now you should also
check for

  assert(n->namespaces[0] == NULL);

somewhere. In nvme_ns() maybe?

> 
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
> ---
>  hw/block/nvme.h | 8 ++++----
>  hw/block/nvme.c | 2 +-
>  2 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 9edc86d79e98..c610ab30dc5c 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -217,7 +217,7 @@ typedef struct NvmeCtrl {
>       * Attached namespaces to this controller.  If subsys is not given, all
>       * namespaces in this list will always be attached.
>       */
> -    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES];
> +    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES + 1];
>      NvmeSQueue      **sq;
>      NvmeCQueue      **cq;
>      NvmeSQueue      admin_sq;
> @@ -232,7 +232,7 @@ static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
>          return NULL;
>      }
>  
> -    return n->namespaces[nsid - 1];
> +    return n->namespaces[nsid];
>  }
>  
>  static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns)
> @@ -253,7 +253,7 @@ static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
>      uint32_t nsid = nvme_nsid(ns);
>      assert(nsid && nsid <= NVME_MAX_NAMESPACES);
>  
> -    n->namespaces[nsid - 1] = ns;
> +    n->namespaces[nsid] = ns;
>  }
>  
>  static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
> @@ -261,7 +261,7 @@ static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
>      uint32_t nsid = nvme_nsid(ns);
>      assert(nsid && nsid <= NVME_MAX_NAMESPACES);
>  
> -    n->namespaces[nsid - 1] = NULL;
> +    n->namespaces[nsid] = NULL;
>  }
>  
>  static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index c54ec3c9523c..6d31d5b17a0b 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -5915,7 +5915,7 @@ int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
>              return -1;
>          }
>      } else {
> -        if (n->namespaces[nsid - 1]) {
> +        if (n->namespaces[nsid]) {
>              error_setg(errp, "namespace id '%d' is already in use", nsid);
>              return -1;
>          }
>
Klaus Jensen April 6, 2021, 7:28 a.m. UTC | #2
On Apr  6 09:01, Philippe Mathieu-Daudé wrote:
> On 4/5/21 7:54 PM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> > 
> > The controller namespaces array being 0-indexed requires 'nsid - 1'
> > everywhere. Something that is easy to miss. Align the controller
> > namespaces array with the subsystem namespaces array such that both are
> > 1-indexed.
> 
> TBH I don't understand the justification.

Justification is mostly to align with the subsystem device. I like the
'1-indexed' approach better. And the -1 causes Coverity to complain
before the assert was added.

> Assuming you hit a
> bug and try to protect yourself, maybe now you should also
> check for
> 
>   assert(n->namespaces[0] == NULL);
> 
> somewhere. In nvme_ns() maybe?
> 

That is definitely a state that should always hold, I guess we can do
that, but we do already guard all "insertions" into the namespace array
by an assert on the nsid. Then again, asserting here makes sure that we
don't introduce something else that inserts on this invalid position.

So, good point, I'll add it.

> > 
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
> > ---
> >  hw/block/nvme.h | 8 ++++----
> >  hw/block/nvme.c | 2 +-
> >  2 files changed, 5 insertions(+), 5 deletions(-)
> > 
> > diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> > index 9edc86d79e98..c610ab30dc5c 100644
> > --- a/hw/block/nvme.h
> > +++ b/hw/block/nvme.h
> > @@ -217,7 +217,7 @@ typedef struct NvmeCtrl {
> >       * Attached namespaces to this controller.  If subsys is not given, all
> >       * namespaces in this list will always be attached.
> >       */
> > -    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES];
> > +    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES + 1];
> >      NvmeSQueue      **sq;
> >      NvmeCQueue      **cq;
> >      NvmeSQueue      admin_sq;
> > @@ -232,7 +232,7 @@ static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
> >          return NULL;
> >      }
> >  
> > -    return n->namespaces[nsid - 1];
> > +    return n->namespaces[nsid];
> >  }
> >  
> >  static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns)
> > @@ -253,7 +253,7 @@ static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
> >      uint32_t nsid = nvme_nsid(ns);
> >      assert(nsid && nsid <= NVME_MAX_NAMESPACES);
> >  
> > -    n->namespaces[nsid - 1] = ns;
> > +    n->namespaces[nsid] = ns;
> >  }
> >  
> >  static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
> > @@ -261,7 +261,7 @@ static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
> >      uint32_t nsid = nvme_nsid(ns);
> >      assert(nsid && nsid <= NVME_MAX_NAMESPACES);
> >  
> > -    n->namespaces[nsid - 1] = NULL;
> > +    n->namespaces[nsid] = NULL;
> >  }
> >  
> >  static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index c54ec3c9523c..6d31d5b17a0b 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -5915,7 +5915,7 @@ int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
> >              return -1;
> >          }
> >      } else {
> > -        if (n->namespaces[nsid - 1]) {
> > +        if (n->namespaces[nsid]) {
> >              error_setg(errp, "namespace id '%d' is already in use", nsid);
> >              return -1;
> >          }
> > 
> 
>
Klaus Jensen April 6, 2021, 6:21 p.m. UTC | #3
On Apr  6 09:28, Klaus Jensen wrote:
> On Apr  6 09:01, Philippe Mathieu-Daudé wrote:
> > On 4/5/21 7:54 PM, Klaus Jensen wrote:
> > > From: Klaus Jensen <k.jensen@samsung.com>
> > > 
> > > The controller namespaces array being 0-indexed requires 'nsid - 1'
> > > everywhere. Something that is easy to miss. Align the controller
> > > namespaces array with the subsystem namespaces array such that both are
> > > 1-indexed.
> > 
> > TBH I don't understand the justification.
> 
> Justification is mostly to align with the subsystem device. I like the
> '1-indexed' approach better. And the -1 causes Coverity to complain
> before the assert was added.
> 
> > Assuming you hit a
> > bug and try to protect yourself, maybe now you should also
> > check for
> > 
> >   assert(n->namespaces[0] == NULL);
> > 
> > somewhere. In nvme_ns() maybe?
> > 
> 
> That is definitely a state that should always hold, I guess we can do
> that, but we do already guard all "insertions" into the namespace array
> by an assert on the nsid. Then again, asserting here makes sure that we
> don't introduce something else that inserts on this invalid position.
> 
> So, good point, I'll add it.
> 

Then again again.

I don't see the reason for the assert. Even if something ends up there 
by mistake we will never return it. If something ends up there due to 
new code, that nvme_ns() will always return NULL when nsid is zero and 
that should weed out the bug easily.

I'll update the commit message to make it clear that this is about 
making both the subsystem and controller namespaces arrays 1-indexed. 
Them being indexed differently is a recipe for disaster I'd say.

In anycase, I it actually a stretch to call this a bug fix, so I'll drop 
it and queue it up for v6.1.
diff mbox series

Patch

diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 9edc86d79e98..c610ab30dc5c 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -217,7 +217,7 @@  typedef struct NvmeCtrl {
      * Attached namespaces to this controller.  If subsys is not given, all
      * namespaces in this list will always be attached.
      */
-    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES];
+    NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES + 1];
     NvmeSQueue      **sq;
     NvmeCQueue      **cq;
     NvmeSQueue      admin_sq;
@@ -232,7 +232,7 @@  static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
         return NULL;
     }
 
-    return n->namespaces[nsid - 1];
+    return n->namespaces[nsid];
 }
 
 static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns)
@@ -253,7 +253,7 @@  static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
     uint32_t nsid = nvme_nsid(ns);
     assert(nsid && nsid <= NVME_MAX_NAMESPACES);
 
-    n->namespaces[nsid - 1] = ns;
+    n->namespaces[nsid] = ns;
 }
 
 static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
@@ -261,7 +261,7 @@  static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
     uint32_t nsid = nvme_nsid(ns);
     assert(nsid && nsid <= NVME_MAX_NAMESPACES);
 
-    n->namespaces[nsid - 1] = NULL;
+    n->namespaces[nsid] = NULL;
 }
 
 static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index c54ec3c9523c..6d31d5b17a0b 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -5915,7 +5915,7 @@  int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
             return -1;
         }
     } else {
-        if (n->namespaces[nsid - 1]) {
+        if (n->namespaces[nsid]) {
             error_setg(errp, "namespace id '%d' is already in use", nsid);
             return -1;
         }