Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/nvme/tags/nvme-fixes-2021-04-07…
Browse files Browse the repository at this point in the history
…-pull-request' into staging

emulated nvme fixes for -rc3

v2:
  - added missing patches

# gpg: Signature made Wed 07 Apr 2021 06:42:51 BST
# gpg:                using RSA key 522833AA75E2DCE6A24766C04DE1AF316D4F0DE9
# gpg: Good signature from "Klaus Jensen <its@irrelevant.dk>" [unknown]
# gpg:                 aka "Klaus Jensen <k.jensen@samsung.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DDCA 4D9C 9EF9 31CC 3468  4272 63D5 6FC5 E55D A838
#      Subkey fingerprint: 5228 33AA 75E2 DCE6 A247  66C0 4DE1 AF31 6D4F 0DE9

* remotes/nvme/tags/nvme-fixes-2021-04-07-pull-request:
  hw/block/nvme: fix out-of-bounds read in nvme_subsys_ctrl
  hw/block/nvme: fix assert crash in nvme_subsys_ns
  hw/block/nvme: fix ns attachment out-of-bounds read
  hw/block/nvme: add missing copyright headers
  hw/block/nvme: fix handling of private namespaces
  hw/block/nvme: update dmsrl limit on namespace detachment
  hw/block/nvme: fix warning about legacy namespace configuration
  hw/block/nvme: fix the nsid 'invalid' value
  hw/block/nvme: fix missing string representation for ns attachment
  hw/block/nvme: fix pi constraint check

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Apr 7, 2021
2 parents d0d3dd4 + 5dd7930 commit 6afa421
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 177 deletions.
10 changes: 10 additions & 0 deletions hw/block/nvme-dif.c
@@ -1,3 +1,13 @@
/*
* QEMU NVM Express End-to-End Data Protection support
*
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Authors:
* Klaus Jensen <k.jensen@samsung.com>
* Gollu Appalanaidu <anaidu.gollu@samsung.com>
*/

#include "qemu/osdep.h"
#include "hw/block/block.h"
#include "sysemu/dma.h"
Expand Down
10 changes: 10 additions & 0 deletions hw/block/nvme-dif.h
@@ -1,3 +1,13 @@
/*
* QEMU NVM Express End-to-End Data Protection support
*
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Authors:
* Klaus Jensen <k.jensen@samsung.com>
* Gollu Appalanaidu <anaidu.gollu@samsung.com>
*/

#ifndef HW_NVME_DIF_H
#define HW_NVME_DIF_H

Expand Down
78 changes: 67 additions & 11 deletions hw/block/nvme-ns.c
Expand Up @@ -73,7 +73,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
/* support DULBE and I/O optimization fields */
id_ns->nsfeat |= (0x4 | 0x10);

if (nvme_ns_shared(ns)) {
if (ns->params.shared) {
id_ns->nmic |= NVME_NMIC_NS_SHARED;
}

Expand Down Expand Up @@ -387,25 +387,46 @@ static void nvme_zoned_ns_shutdown(NvmeNamespace *ns)
assert(ns->nr_open_zones == 0);
}

static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp)
static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns,
Error **errp)
{
if (!ns->blkconf.blk) {
error_setg(errp, "block backend not configured");
return -1;
}

if (ns->params.pi && !ns->params.ms) {
if (ns->params.pi && ns->params.ms < 8) {
error_setg(errp, "at least 8 bytes of metadata required to enable "
"protection information");
return -1;
}

if (ns->params.nsid > NVME_MAX_NAMESPACES) {
error_setg(errp, "invalid namespace id (must be between 0 and %d)",
NVME_MAX_NAMESPACES);
return -1;
}

if (!n->subsys) {
if (ns->params.detached) {
error_setg(errp, "detached requires that the nvme device is "
"linked to an nvme-subsys device");
return -1;
}

if (ns->params.shared) {
error_setg(errp, "shared requires that the nvme device is "
"linked to an nvme-subsys device");
return -1;
}
}

return 0;
}

int nvme_ns_setup(NvmeNamespace *ns, Error **errp)
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
{
if (nvme_ns_check_constraints(ns, errp)) {
if (nvme_ns_check_constraints(n, ns, errp)) {
return -1;
}

Expand Down Expand Up @@ -453,27 +474,62 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
NvmeNamespace *ns = NVME_NS(dev);
BusState *s = qdev_get_parent_bus(dev);
NvmeCtrl *n = NVME(s->parent);
NvmeSubsystem *subsys = n->subsys;
uint32_t nsid = ns->params.nsid;
int i;

if (nvme_ns_setup(ns, errp)) {
if (nvme_ns_setup(n, ns, errp)) {
return;
}

if (ns->subsys) {
if (nvme_subsys_register_ns(ns, errp)) {
if (!nsid) {
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
if (nvme_ns(n, i) || nvme_subsys_ns(subsys, i)) {
continue;
}

nsid = ns->params.nsid = i;
break;
}

if (!nsid) {
error_setg(errp, "no free namespace id");
return;
}
} else {
if (nvme_register_namespace(n, ns, errp)) {
if (nvme_ns(n, nsid) || nvme_subsys_ns(subsys, nsid)) {
error_setg(errp, "namespace id '%d' already allocated", nsid);
return;
}
}

if (subsys) {
subsys->namespaces[nsid] = ns;

if (ns->params.detached) {
return;
}

if (ns->params.shared) {
for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
NvmeCtrl *ctrl = subsys->ctrls[i];

if (ctrl) {
nvme_attach_ns(ctrl, ns);
}
}

return;
}
}

nvme_attach_ns(n, ns);
}

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_BOOL("shared", NvmeNamespace, params.shared, false),
DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
DEFINE_PROP_UINT16("ms", NvmeNamespace, params.ms, 0),
Expand Down
12 changes: 4 additions & 8 deletions hw/block/nvme-ns.h
Expand Up @@ -29,6 +29,7 @@ typedef struct NvmeZone {

typedef struct NvmeNamespaceParams {
bool detached;
bool shared;
uint32_t nsid;
QemuUUID uuid;

Expand Down Expand Up @@ -60,8 +61,8 @@ typedef struct NvmeNamespace {
const uint32_t *iocs;
uint8_t csi;
uint16_t status;
int attached;

NvmeSubsystem *subsys;
QTAILQ_ENTRY(NvmeNamespace) entry;

NvmeIdNsZoned *id_ns_zoned;
Expand Down Expand Up @@ -96,12 +97,7 @@ static inline uint32_t nvme_nsid(NvmeNamespace *ns)
return ns->params.nsid;
}

return -1;
}

static inline bool nvme_ns_shared(NvmeNamespace *ns)
{
return !!ns->subsys;
return 0;
}

static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
Expand Down Expand Up @@ -225,7 +221,7 @@ static inline void nvme_aor_dec_active(NvmeNamespace *ns)
}

void nvme_ns_init_format(NvmeNamespace *ns);
int nvme_ns_setup(NvmeNamespace *ns, Error **errp);
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
void nvme_ns_drain(NvmeNamespace *ns);
void nvme_ns_shutdown(NvmeNamespace *ns);
void nvme_ns_cleanup(NvmeNamespace *ns);
Expand Down
28 changes: 0 additions & 28 deletions hw/block/nvme-subsys.c
Expand Up @@ -43,34 +43,6 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
return cntlid;
}

int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp)
{
NvmeSubsystem *subsys = ns->subsys;
NvmeCtrl *n;
uint32_t nsid = nvme_nsid(ns);
int i;

assert(nsid && nsid <= NVME_SUBSYS_MAX_NAMESPACES);

if (subsys->namespaces[nsid]) {
error_setg(errp, "namespace %d already registerd to subsy %s",
nvme_nsid(ns), subsys->parent_obj.id);
return -1;
}

subsys->namespaces[nsid] = ns;

for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
n = subsys->ctrls[i];

if (n && nvme_register_namespace(n, ns, errp)) {
return -1;
}
}

return 0;
}

static void nvme_subsys_setup(NvmeSubsystem *subsys)
{
const char *nqn = subsys->params.nqn ?
Expand Down
11 changes: 4 additions & 7 deletions hw/block/nvme-subsys.h
Expand Up @@ -14,7 +14,7 @@
OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)

#define NVME_SUBSYS_MAX_CTRLS 32
#define NVME_SUBSYS_MAX_NAMESPACES 256
#define NVME_MAX_NAMESPACES 256

typedef struct NvmeCtrl NvmeCtrl;
typedef struct NvmeNamespace NvmeNamespace;
Expand All @@ -24,20 +24,19 @@ typedef struct NvmeSubsystem {

NvmeCtrl *ctrls[NVME_SUBSYS_MAX_CTRLS];
/* Allocated namespaces for this subsystem */
NvmeNamespace *namespaces[NVME_SUBSYS_MAX_NAMESPACES + 1];
NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];

struct {
char *nqn;
} params;
} NvmeSubsystem;

int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp);
int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp);

static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
uint32_t cntlid)
{
if (!subsys) {
if (!subsys || cntlid >= NVME_SUBSYS_MAX_CTRLS) {
return NULL;
}

Expand All @@ -50,12 +49,10 @@ static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys,
uint32_t nsid)
{
if (!subsys) {
if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) {
return NULL;
}

assert(nsid && nsid <= NVME_SUBSYS_MAX_NAMESPACES);

return subsys->namespaces[nsid];
}

Expand Down

0 comments on commit 6afa421

Please sign in to comment.