Re: [PATCH v5 22/26] nvme: support multiple namespaces
On Mon, 2020-03-16 at 00:55 -0700, Klaus Birkelund Jensen wrote: > On Feb 12 14:34, Maxim Levitsky wrote: > > On Tue, 2020-02-04 at 10:52 +0100, Klaus Jensen wrote: > > > This adds support for multiple namespaces by introducing a new 'nvme-ns' > > > device model. The nvme device creates a bus named from the device name > > > ('id'). The nvme-ns devices then connect to this and registers > > > themselves with the nvme device. > > > > > > This changes how an nvme device is created. Example with two namespaces: > > > > > > -drive file=nvme0n1.img,if=none,id=disk1 > > > -drive file=nvme0n2.img,if=none,id=disk2 > > > -device nvme,serial=deadbeef,id=nvme0 > > > -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 > > > -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 > > > > > > The drive property is kept on the nvme device to keep the change > > > backward compatible, but the property is now optional. Specifying a > > > drive for the nvme device will always create the namespace with nsid 1. > > > > Very reasonable way to do it. > > > > > > Signed-off-by: Klaus Jensen > > > Signed-off-by: Klaus Jensen > > > --- > > > hw/block/Makefile.objs | 2 +- > > > hw/block/nvme-ns.c | 158 +++ > > > hw/block/nvme-ns.h | 60 +++ > > > hw/block/nvme.c| 235 + > > > hw/block/nvme.h| 47 - > > > hw/block/trace-events | 6 +- > > > 6 files changed, 389 insertions(+), 119 deletions(-) > > > create mode 100644 hw/block/nvme-ns.c > > > create mode 100644 hw/block/nvme-ns.h > > > > > > diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs > > > index 28c2495a00dc..45f463462f1e 100644 > > > --- a/hw/block/Makefile.objs > > > +++ b/hw/block/Makefile.objs > > > @@ -7,7 +7,7 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o > > > common-obj-$(CONFIG_XEN) += xen-block.o > > > common-obj-$(CONFIG_ECC) += ecc.o > > > common-obj-$(CONFIG_ONENAND) += onenand.o > > > -common-obj-$(CONFIG_NVME_PCI) += nvme.o > > > +common-obj-$(CONFIG_NVME_PCI) += nvme.o nvme-ns.o > > > common-obj-$(CONFIG_SWIM) += swim.o > > > > > > obj-$(CONFIG_SH4) += tc58128.o > > > diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c > > > new file mode 100644 > > > index ..0e5be44486f4 > > > --- /dev/null > > > +++ b/hw/block/nvme-ns.c > > > @@ -0,0 +1,158 @@ > > > +#include "qemu/osdep.h" > > > +#include "qemu/units.h" > > > +#include "qemu/cutils.h" > > > +#include "qemu/log.h" > > > +#include "hw/block/block.h" > > > +#include "hw/pci/msix.h" > > > > Do you need this include? > > No, I needed hw/pci/pci.h instead :) I think it compiled without that include, but including pci.h for a pci device a a right thing anyway. > > > > +#include "sysemu/sysemu.h" > > > +#include "sysemu/block-backend.h" > > > +#include "qapi/error.h" > > > + > > > +#include "hw/qdev-properties.h" > > > +#include "hw/qdev-core.h" > > > + > > > +#include "nvme.h" > > > +#include "nvme-ns.h" > > > + > > > +static int nvme_ns_init(NvmeNamespace *ns) > > > +{ > > > +NvmeIdNs *id_ns = >id_ns; > > > + > > > +id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; > > > +id_ns->nuse = id_ns->ncap = id_ns->nsze = > > > +cpu_to_le64(nvme_ns_nlbas(ns)); > > > > Nitpick: To be honest I don't really like that chain assignment, > > especially since it forces to wrap the line, but that is just my > > personal taste. > > Fixed, and also added a comment as to why they are the same. > > > > + > > > +return 0; > > > +} > > > + > > > +static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, NvmeIdCtrl > > > *id, > > > +Error **errp) > > > +{ > > > +uint64_t perm, shared_perm; > > > + > > > +Error *local_err = NULL; > > > +int ret; > > > + > > > +perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; > > > +shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | > > > +BLK_PERM_GRAPH_MOD; > > > + > > > +ret = blk_set_perm(ns->blk, perm, shared_perm, _err); > > > +if (ret) { > > > +error_propagate_prepend(errp, local_err, "blk_set_perm: "); > > > +return ret; > > > +} > > > > You should consider using blkconf_apply_backend_options. > > Take a look at for example virtio_blk_device_realize. > > That will give you support for read only block devices as well. > > So, yeah. There is a reason for this. And I will add that as a comment, > but I will write it here for posterity. > > The problem is when the nvme-ns device starts getting more than just a > single drive attached (I have patches ready that will add a "metadata" > and a "state" drive). The blkconf_ functions work on a BlockConf that > embeds a BlockBackend, so you can't have one BlockConf with multiple > BlockBackend's. That is why I'm kinda copying the "good parts" of > the blkconf_apply_backend_options code here. All right. but I guess that eventually this code will need a review from someone that knows the block layer
Re: [PATCH v5 22/26] nvme: support multiple namespaces
On Feb 12 14:34, Maxim Levitsky wrote: > On Tue, 2020-02-04 at 10:52 +0100, Klaus Jensen wrote: > > This adds support for multiple namespaces by introducing a new 'nvme-ns' > > device model. The nvme device creates a bus named from the device name > > ('id'). The nvme-ns devices then connect to this and registers > > themselves with the nvme device. > > > > This changes how an nvme device is created. Example with two namespaces: > > > > -drive file=nvme0n1.img,if=none,id=disk1 > > -drive file=nvme0n2.img,if=none,id=disk2 > > -device nvme,serial=deadbeef,id=nvme0 > > -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 > > -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 > > > > The drive property is kept on the nvme device to keep the change > > backward compatible, but the property is now optional. Specifying a > > drive for the nvme device will always create the namespace with nsid 1. > Very reasonable way to do it. > > > > Signed-off-by: Klaus Jensen > > Signed-off-by: Klaus Jensen > > --- > > hw/block/Makefile.objs | 2 +- > > hw/block/nvme-ns.c | 158 +++ > > hw/block/nvme-ns.h | 60 +++ > > hw/block/nvme.c| 235 + > > hw/block/nvme.h| 47 - > > hw/block/trace-events | 6 +- > > 6 files changed, 389 insertions(+), 119 deletions(-) > > create mode 100644 hw/block/nvme-ns.c > > create mode 100644 hw/block/nvme-ns.h > > > > diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs > > index 28c2495a00dc..45f463462f1e 100644 > > --- a/hw/block/Makefile.objs > > +++ b/hw/block/Makefile.objs > > @@ -7,7 +7,7 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o > > common-obj-$(CONFIG_XEN) += xen-block.o > > common-obj-$(CONFIG_ECC) += ecc.o > > common-obj-$(CONFIG_ONENAND) += onenand.o > > -common-obj-$(CONFIG_NVME_PCI) += nvme.o > > +common-obj-$(CONFIG_NVME_PCI) += nvme.o nvme-ns.o > > common-obj-$(CONFIG_SWIM) += swim.o > > > > obj-$(CONFIG_SH4) += tc58128.o > > diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c > > new file mode 100644 > > index ..0e5be44486f4 > > --- /dev/null > > +++ b/hw/block/nvme-ns.c > > @@ -0,0 +1,158 @@ > > +#include "qemu/osdep.h" > > +#include "qemu/units.h" > > +#include "qemu/cutils.h" > > +#include "qemu/log.h" > > +#include "hw/block/block.h" > > +#include "hw/pci/msix.h" > Do you need this include? No, I needed hw/pci/pci.h instead :) > > +#include "sysemu/sysemu.h" > > +#include "sysemu/block-backend.h" > > +#include "qapi/error.h" > > + > > +#include "hw/qdev-properties.h" > > +#include "hw/qdev-core.h" > > + > > +#include "nvme.h" > > +#include "nvme-ns.h" > > + > > +static int nvme_ns_init(NvmeNamespace *ns) > > +{ > > +NvmeIdNs *id_ns = >id_ns; > > + > > +id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; > > +id_ns->nuse = id_ns->ncap = id_ns->nsze = > > +cpu_to_le64(nvme_ns_nlbas(ns)); > Nitpick: To be honest I don't really like that chain assignment, > especially since it forces to wrap the line, but that is just my > personal taste. Fixed, and also added a comment as to why they are the same. > > + > > +return 0; > > +} > > + > > +static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, NvmeIdCtrl *id, > > +Error **errp) > > +{ > > +uint64_t perm, shared_perm; > > + > > +Error *local_err = NULL; > > +int ret; > > + > > +perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; > > +shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | > > +BLK_PERM_GRAPH_MOD; > > + > > +ret = blk_set_perm(ns->blk, perm, shared_perm, _err); > > +if (ret) { > > +error_propagate_prepend(errp, local_err, "blk_set_perm: "); > > +return ret; > > +} > > You should consider using blkconf_apply_backend_options. > Take a look at for example virtio_blk_device_realize. > That will give you support for read only block devices as well. So, yeah. There is a reason for this. And I will add that as a comment, but I will write it here for posterity. The problem is when the nvme-ns device starts getting more than just a single drive attached (I have patches ready that will add a "metadata" and a "state" drive). The blkconf_ functions work on a BlockConf that embeds a BlockBackend, so you can't have one BlockConf with multiple BlockBackend's. That is why I'm kinda copying the "good parts" of the blkconf_apply_backend_options code here. > > I personally only once grazed the area of block permissions, > so I prefer someone from the block layer to review this as well. > > > + > > +ns->size = blk_getlength(ns->blk); > > +if (ns->size < 0) { > > +error_setg_errno(errp, -ns->size, "blk_getlength"); > > +return 1; > > +} > > + > > +switch (n->conf.wce) { > > +case ON_OFF_AUTO_ON: > > +n->features.volatile_wc = 1; > > +break; > > +case ON_OFF_AUTO_OFF: > > +n->features.volatile_wc = 0; > > +case
Re: [PATCH v5 22/26] nvme: support multiple namespaces
On Tue, 2020-02-04 at 10:52 +0100, Klaus Jensen wrote: > This adds support for multiple namespaces by introducing a new 'nvme-ns' > device model. The nvme device creates a bus named from the device name > ('id'). The nvme-ns devices then connect to this and registers > themselves with the nvme device. > > This changes how an nvme device is created. Example with two namespaces: > > -drive file=nvme0n1.img,if=none,id=disk1 > -drive file=nvme0n2.img,if=none,id=disk2 > -device nvme,serial=deadbeef,id=nvme0 > -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 > -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 > > The drive property is kept on the nvme device to keep the change > backward compatible, but the property is now optional. Specifying a > drive for the nvme device will always create the namespace with nsid 1. Very reasonable way to do it. > > Signed-off-by: Klaus Jensen > Signed-off-by: Klaus Jensen > --- > hw/block/Makefile.objs | 2 +- > hw/block/nvme-ns.c | 158 +++ > hw/block/nvme-ns.h | 60 +++ > hw/block/nvme.c| 235 + > hw/block/nvme.h| 47 - > hw/block/trace-events | 6 +- > 6 files changed, 389 insertions(+), 119 deletions(-) > create mode 100644 hw/block/nvme-ns.c > create mode 100644 hw/block/nvme-ns.h > > diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs > index 28c2495a00dc..45f463462f1e 100644 > --- a/hw/block/Makefile.objs > +++ b/hw/block/Makefile.objs > @@ -7,7 +7,7 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o > common-obj-$(CONFIG_XEN) += xen-block.o > common-obj-$(CONFIG_ECC) += ecc.o > common-obj-$(CONFIG_ONENAND) += onenand.o > -common-obj-$(CONFIG_NVME_PCI) += nvme.o > +common-obj-$(CONFIG_NVME_PCI) += nvme.o nvme-ns.o > common-obj-$(CONFIG_SWIM) += swim.o > > obj-$(CONFIG_SH4) += tc58128.o > diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c > new file mode 100644 > index ..0e5be44486f4 > --- /dev/null > +++ b/hw/block/nvme-ns.c > @@ -0,0 +1,158 @@ > +#include "qemu/osdep.h" > +#include "qemu/units.h" > +#include "qemu/cutils.h" > +#include "qemu/log.h" > +#include "hw/block/block.h" > +#include "hw/pci/msix.h" Do you need this include? > +#include "sysemu/sysemu.h" > +#include "sysemu/block-backend.h" > +#include "qapi/error.h" > + > +#include "hw/qdev-properties.h" > +#include "hw/qdev-core.h" > + > +#include "nvme.h" > +#include "nvme-ns.h" > + > +static int nvme_ns_init(NvmeNamespace *ns) > +{ > +NvmeIdNs *id_ns = >id_ns; > + > +id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; > +id_ns->nuse = id_ns->ncap = id_ns->nsze = > +cpu_to_le64(nvme_ns_nlbas(ns)); Nitpick: To be honest I don't really like that chain assignment, especially since it forces to wrap the line, but that is just my personal taste. > + > +return 0; > +} > + > +static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, NvmeIdCtrl *id, > +Error **errp) > +{ > +uint64_t perm, shared_perm; > + > +Error *local_err = NULL; > +int ret; > + > +perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; > +shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | > +BLK_PERM_GRAPH_MOD; > + > +ret = blk_set_perm(ns->blk, perm, shared_perm, _err); > +if (ret) { > +error_propagate_prepend(errp, local_err, "blk_set_perm: "); > +return ret; > +} You should consider using blkconf_apply_backend_options. Take a look at for example virtio_blk_device_realize. That will give you support for read only block devices as well. I personally only once grazed the area of block permissions, so I prefer someone from the block layer to review this as well. > + > +ns->size = blk_getlength(ns->blk); > +if (ns->size < 0) { > +error_setg_errno(errp, -ns->size, "blk_getlength"); > +return 1; > +} > + > +switch (n->conf.wce) { > +case ON_OFF_AUTO_ON: > +n->features.volatile_wc = 1; > +break; > +case ON_OFF_AUTO_OFF: > +n->features.volatile_wc = 0; > +case ON_OFF_AUTO_AUTO: > +n->features.volatile_wc = blk_enable_write_cache(ns->blk); > +break; > +default: > +abort(); > +} > + > +blk_set_enable_write_cache(ns->blk, n->features.volatile_wc); > + > +return 0; Nitpick: also I just noticed that you call the controller 'n' I didn't paid attention to this before. I think something like 'ctrl' or ctl would be more readable. > +} > + > +static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) > +{ > +if (!ns->blk) { > +error_setg(errp, "block backend not configured"); > +return 1; > +} > + > +return 0; > +} > + > +int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) > +{ > +Error *local_err = NULL; > + > +if (nvme_ns_check_constraints(ns, _err)) { > +error_propagate_prepend(errp, local_err, > +"nvme_ns_check_constraints: "); >
Re: [PATCH v5 22/26] nvme: support multiple namespaces
On Feb 5 01:31, Keith Busch wrote: > On Tue, Feb 04, 2020 at 10:52:04AM +0100, Klaus Jensen wrote: > > This adds support for multiple namespaces by introducing a new 'nvme-ns' > > device model. The nvme device creates a bus named from the device name > > ('id'). The nvme-ns devices then connect to this and registers > > themselves with the nvme device. > > > > This changes how an nvme device is created. Example with two namespaces: > > > > -drive file=nvme0n1.img,if=none,id=disk1 > > -drive file=nvme0n2.img,if=none,id=disk2 > > -device nvme,serial=deadbeef,id=nvme0 > > -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 > > -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 > > > > The drive property is kept on the nvme device to keep the change > > backward compatible, but the property is now optional. Specifying a > > drive for the nvme device will always create the namespace with nsid 1. > > > > Signed-off-by: Klaus Jensen > > Signed-off-by: Klaus Jensen > > I like this feature a lot, thanks for doing it. > > Reviewed-by: Keith Busch > > > @@ -1256,18 +1272,24 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, > > NvmeCmd *cmd, uint8_t rae, > > uint64_t units_read = 0, units_written = 0, read_commands = 0, > > write_commands = 0; > > NvmeSmartLog smart; > > -BlockAcctStats *s; > > > > if (nsid && nsid != 0x) { > > return NVME_INVALID_FIELD | NVME_DNR; > > } > > This is totally optional, but worth mentioning: this patch makes it > possible to remove this check and allow per-namespace smart logs. The > ID_CTRL.LPA would need to updated to reflect that if you wanted to > go that route. Yeah, I thought about that, but with NVMe v1.4 support arriving in a later series, there are no longer any namespace specific stuff in the log page anyway. The spec isn't really clear on what the preferred behavior for a 1.4 compliant device is. Either 1. LBA bit 0 set and just return the same page for each namespace or, 2. LBA bit 0 unset and fail when NSID is set
Re: [PATCH v5 22/26] nvme: support multiple namespaces
On Tue, Feb 04, 2020 at 10:52:04AM +0100, Klaus Jensen wrote: > This adds support for multiple namespaces by introducing a new 'nvme-ns' > device model. The nvme device creates a bus named from the device name > ('id'). The nvme-ns devices then connect to this and registers > themselves with the nvme device. > > This changes how an nvme device is created. Example with two namespaces: > > -drive file=nvme0n1.img,if=none,id=disk1 > -drive file=nvme0n2.img,if=none,id=disk2 > -device nvme,serial=deadbeef,id=nvme0 > -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 > -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 > > The drive property is kept on the nvme device to keep the change > backward compatible, but the property is now optional. Specifying a > drive for the nvme device will always create the namespace with nsid 1. > > Signed-off-by: Klaus Jensen > Signed-off-by: Klaus Jensen I like this feature a lot, thanks for doing it. Reviewed-by: Keith Busch > @@ -1256,18 +1272,24 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd > *cmd, uint8_t rae, > uint64_t units_read = 0, units_written = 0, read_commands = 0, > write_commands = 0; > NvmeSmartLog smart; > -BlockAcctStats *s; > > if (nsid && nsid != 0x) { > return NVME_INVALID_FIELD | NVME_DNR; > } This is totally optional, but worth mentioning: this patch makes it possible to remove this check and allow per-namespace smart logs. The ID_CTRL.LPA would need to updated to reflect that if you wanted to go that route.
[PATCH v5 22/26] nvme: support multiple namespaces
This adds support for multiple namespaces by introducing a new 'nvme-ns' device model. The nvme device creates a bus named from the device name ('id'). The nvme-ns devices then connect to this and registers themselves with the nvme device. This changes how an nvme device is created. Example with two namespaces: -drive file=nvme0n1.img,if=none,id=disk1 -drive file=nvme0n2.img,if=none,id=disk2 -device nvme,serial=deadbeef,id=nvme0 -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 The drive property is kept on the nvme device to keep the change backward compatible, but the property is now optional. Specifying a drive for the nvme device will always create the namespace with nsid 1. Signed-off-by: Klaus Jensen Signed-off-by: Klaus Jensen --- hw/block/Makefile.objs | 2 +- hw/block/nvme-ns.c | 158 +++ hw/block/nvme-ns.h | 60 +++ hw/block/nvme.c| 235 + hw/block/nvme.h| 47 - hw/block/trace-events | 6 +- 6 files changed, 389 insertions(+), 119 deletions(-) create mode 100644 hw/block/nvme-ns.c create mode 100644 hw/block/nvme-ns.h diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 28c2495a00dc..45f463462f1e 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -7,7 +7,7 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o common-obj-$(CONFIG_XEN) += xen-block.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o -common-obj-$(CONFIG_NVME_PCI) += nvme.o +common-obj-$(CONFIG_NVME_PCI) += nvme.o nvme-ns.o common-obj-$(CONFIG_SWIM) += swim.o obj-$(CONFIG_SH4) += tc58128.o diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c new file mode 100644 index ..0e5be44486f4 --- /dev/null +++ b/hw/block/nvme-ns.c @@ -0,0 +1,158 @@ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "hw/block/block.h" +#include "hw/pci/msix.h" +#include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" + +#include "hw/qdev-properties.h" +#include "hw/qdev-core.h" + +#include "nvme.h" +#include "nvme-ns.h" + +static int nvme_ns_init(NvmeNamespace *ns) +{ +NvmeIdNs *id_ns = >id_ns; + +id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; +id_ns->nuse = id_ns->ncap = id_ns->nsze = +cpu_to_le64(nvme_ns_nlbas(ns)); + +return 0; +} + +static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, NvmeIdCtrl *id, +Error **errp) +{ +uint64_t perm, shared_perm; + +Error *local_err = NULL; +int ret; + +perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; +shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | +BLK_PERM_GRAPH_MOD; + +ret = blk_set_perm(ns->blk, perm, shared_perm, _err); +if (ret) { +error_propagate_prepend(errp, local_err, "blk_set_perm: "); +return ret; +} + +ns->size = blk_getlength(ns->blk); +if (ns->size < 0) { +error_setg_errno(errp, -ns->size, "blk_getlength"); +return 1; +} + +switch (n->conf.wce) { +case ON_OFF_AUTO_ON: +n->features.volatile_wc = 1; +break; +case ON_OFF_AUTO_OFF: +n->features.volatile_wc = 0; +case ON_OFF_AUTO_AUTO: +n->features.volatile_wc = blk_enable_write_cache(ns->blk); +break; +default: +abort(); +} + +blk_set_enable_write_cache(ns->blk, n->features.volatile_wc); + +return 0; +} + +static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) +{ +if (!ns->blk) { +error_setg(errp, "block backend not configured"); +return 1; +} + +return 0; +} + +int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) +{ +Error *local_err = NULL; + +if (nvme_ns_check_constraints(ns, _err)) { +error_propagate_prepend(errp, local_err, +"nvme_ns_check_constraints: "); +return 1; +} + +if (nvme_ns_init_blk(n, ns, >id_ctrl, _err)) { +error_propagate_prepend(errp, local_err, "nvme_ns_init_blk: "); +return 1; +} + +nvme_ns_init(ns); +if (nvme_register_namespace(n, ns, _err)) { +error_propagate_prepend(errp, local_err, "nvme_register_namespace: "); +return 1; +} + +return 0; +} + +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); +Error *local_err = NULL; + +if (nvme_ns_setup(n, ns, _err)) { +error_propagate_prepend(errp, local_err, "nvme_ns_setup: "); +return; +} +} + +static Property nvme_ns_props[] = { +DEFINE_NVME_NS_PROPERTIES(NvmeNamespace, params), +DEFINE_PROP_END_OF_LIST(), +}; + +static void nvme_ns_class_init(ObjectClass *oc, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(oc); + +