Re: [PATCH 11/17] hw/block/nvme: add remaining mandatory controller parameters

2020-07-02 Thread Klaus Jensen
On Jul  3 00:46, Dmitry Fomichev wrote:
> LGTM with one small nit (see below)...
> 
> Reviewed-by: Dmitry Fomichev 
> 
> On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> > From: Klaus Jensen 
> > 
> > Add support for any remaining mandatory controller operating parameters
> > (features).
> > 
> > Signed-off-by: Klaus Jensen 
> > ---
> >  hw/block/nvme.c   | 39 +--
> >  hw/block/nvme.h   | 18 ++
> >  hw/block/trace-events |  2 ++
> >  include/block/nvme.h  |  7 +++
> >  4 files changed, 60 insertions(+), 6 deletions(-)
> > 
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index da13ca1ddb60..647f408854ae 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -1057,8 +1057,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, 
> > NvmeCmd *cmd, NvmeRequest *req)
> >  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >  uint32_t result;
> > +uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> > +uint16_t iv;
> >  
> > -switch (dw10) {
> > +trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> > +
> > +if (!nvme_feature_support[fid]) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +switch (fid) {
> >  case NVME_TEMPERATURE_THRESHOLD:
> >  result = 0;
> >  
> > @@ -1089,14 +1097,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, 
> > NvmeCmd *cmd, NvmeRequest *req)
> >   ((n->params.max_ioqpairs - 1) << 16));
> >  trace_pci_nvme_getfeat_numq(result);
> >  break;
> > +case NVME_INTERRUPT_VECTOR_CONF:
> > +iv = dw11 & 0x;
> > +if (iv >= n->params.max_ioqpairs + 1) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +result = iv;
> > +if (iv == n->admin_cq.vector) {
> > +result |= NVME_INTVC_NOCOALESCING;
> > +}
> > +
> > +result = cpu_to_le32(result);
> > +break;
> >  case NVME_ASYNCHRONOUS_EVENT_CONF:
> >  result = cpu_to_le32(n->features.async_config);
> >  break;
> >  case NVME_TIMESTAMP:
> >  return nvme_get_feature_timestamp(n, cmd);
> >  default:
> > -trace_pci_nvme_err_invalid_getfeat(dw10);
> > -return NVME_INVALID_FIELD | NVME_DNR;
> > +result = cpu_to_le32(nvme_feature_default[fid]);
> > +break;
> >  }
> >  
> >  req->cqe.result = result;
> > @@ -1125,8 +1146,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, 
> > NvmeCmd *cmd, NvmeRequest *req)
> >  {
> >  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> > +uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >  
> > -switch (dw10) {
> > +trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> > +
> > +if (!nvme_feature_support[fid]) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +switch (fid) {
> >  case NVME_TEMPERATURE_THRESHOLD:
> >  if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> >  break;
> > @@ -1173,8 +1201,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> > *cmd, NvmeRequest *req)
> >  case NVME_TIMESTAMP:
> >  return nvme_set_feature_timestamp(n, cmd);
> >  default:
> > -trace_pci_nvme_err_invalid_setfeat(dw10);
> > -return NVME_INVALID_FIELD | NVME_DNR;
> > +return NVME_FEAT_NOT_CHANGABLE | NVME_DNR;
> 
> In spec, it is "Changeable", could as well add that 'e' here

Good catch, typo fixed.

> 
> >  }
> >  return NVME_SUCCESS;
> >  }
> > diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> > index 16a254d30b4e..d0763eb59e5d 100644
> > --- a/hw/block/nvme.h
> > +++ b/hw/block/nvme.h
> > @@ -90,6 +90,24 @@ typedef struct NvmeFeatureVal {
> >  uint32_tasync_config;
> >  } NvmeFeatureVal;
> >  
> > +static const uint32_t nvme_feature_default[0x100] = {
> > +[NVME_ARBITRATION]   = NVME_ARB_AB_NOLIMIT,
> > +};
> > +
> > +static const bool nvme_feature_support[0x100] = {
> > +[NVME_ARBITRATION]  = true,
> > +[NVME_POWER_MANAGEMENT] = true,
> > +[NVME_TEMPERATURE_THRESHOLD]= true,
> > +[NVME_ERROR_RECOVERY]   = true,
> > +[NVME_VOLATILE_WRITE_CACHE] = true,
> > +[NVME_NUMBER_OF_QUEUES] = true,
> > +[NVME_INTERRUPT_COALESCING] = true,
> > +[NVME_INTERRUPT_VECTOR_CONF]= true,
> > +[NVME_WRITE_ATOMICITY]  = true,
> > +[NVME_ASYNCHRONOUS_EVENT_CONF]  = true,
> > +[NVME_TIMESTAMP]= true,
> > +};
> > +
> >  typedef struct NvmeCtrl {
> >  PCIDeviceparent_obj;
> >  MemoryRegion iomem;
> > diff --git a/hw/block/trace-events b/hw/block/trace-events
> > index 091af16ca7d7..42e62f4649f8 100644
> > --- a/hw/block/trace-events
> > +++ b/hw/block/trace-events
> > @@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
> > 

Re: [PATCH 06/17] hw/block/nvme: add support for the get log page command

2020-07-02 Thread Klaus Jensen
On Jul  3 00:45, Dmitry Fomichev wrote:
> On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> > From: Klaus Jensen 
> > 
> > Add support for the Get Log Page command and basic implementations of
> > the mandatory Error Information, SMART / Health Information and Firmware
> > Slot Information log pages.
> > 
> > In violation of the specification, the SMART / Health Information log
> > page does not persist information over the lifetime of the controller
> > because the device has no place to store such persistent state.
> > 
> > Note that the LPA field in the Identify Controller data structure
> > intentionally has bit 0 cleared because there is no namespace specific
> > information in the SMART / Health information log page.
> > 
> > Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d,
> > Section 5.14 ("Get Log Page command").
> > 
> > Signed-off-by: Klaus Jensen 
> > Signed-off-by: Klaus Jensen 
> > Acked-by: Keith Busch 
> > ---
> >  hw/block/nvme.c   | 141 +-
> >  hw/block/nvme.h   |   2 +
> >  hw/block/trace-events |   2 +
> >  include/block/nvme.h  |   4 ++
> >  4 files changed, 148 insertions(+), 1 deletion(-)
> > 
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index f8e91a6965ed..fe5d052ab159 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -592,6 +592,141 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd 
> > *cmd)
> >  return NVME_SUCCESS;
> >  }
> >  
> > +static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t 
> > buf_len,
> > +uint64_t off, NvmeRequest *req)
> > +{
> > +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> > +uint32_t nsid = le32_to_cpu(cmd->nsid);
> > +
> > +uint32_t trans_len;
> > +time_t current_ms;
> > +uint64_t units_read = 0, units_written = 0;
> > +uint64_t read_commands = 0, write_commands = 0;
> > +NvmeSmartLog smart;
> > +BlockAcctStats *s;
> > +
> > +if (nsid && nsid != 0x) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +s = blk_get_stats(n->conf.blk);
> > +
> > +units_read = s->nr_bytes[BLOCK_ACCT_READ] >> BDRV_SECTOR_BITS;
> > +units_written = s->nr_bytes[BLOCK_ACCT_WRITE] >> BDRV_SECTOR_BITS;
> > +read_commands = s->nr_ops[BLOCK_ACCT_READ];
> > +write_commands = s->nr_ops[BLOCK_ACCT_WRITE];
> > +
> > +if (off > sizeof(smart)) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +trans_len = MIN(sizeof(smart) - off, buf_len);
> > +
> > +memset(, 0x0, sizeof(smart));
> > +
> > +smart.data_units_read[0] = cpu_to_le64(units_read / 1000);
> > +smart.data_units_written[0] = cpu_to_le64(units_written / 1000);
> > +smart.host_read_commands[0] = cpu_to_le64(read_commands);
> > +smart.host_write_commands[0] = cpu_to_le64(write_commands);
> > +
> > +smart.temperature[0] = n->temperature & 0xff;
> > +smart.temperature[1] = (n->temperature >> 8) & 0xff;
> 
> Why not change temperature[2] in NvmeSmartLog to uint16_t and use 
> cpu_to_le16() here?
> 

It's because of the wierd alignment. But you are right and I changed it
to uint16_t and added the QEMU_PACKED attribute to the struct. It should
be there anyway.

> > +if ((n->temperature >= n->features.temp_thresh_hi) ||
> > +(n->temperature <= n->features.temp_thresh_low)) {
> > +smart.critical_warning |= NVME_SMART_TEMPERATURE;
> > +}
> > +
> > +current_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
> > +smart.power_on_hours[0] =
> > +cpu_to_le64current_ms - n->starttime_ms) / 1000) / 60) / 60);
> > +
> > +return nvme_dma_read_prp(n, (uint8_t *)  + off, trans_len, prp1,
> > + prp2);
> > +}
> > +
> > +static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t 
> > buf_len,
> > + uint64_t off, NvmeRequest *req)
> > +{
> > +uint32_t trans_len;
> > +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> > +NvmeFwSlotInfoLog fw_log = {
> > +.afi = 0x1,
> > +};
> > +
> > +strpadcpy((char *)_log.frs1, sizeof(fw_log.frs1), "1.0", ' ');
> > +
> > +if (off > sizeof(fw_log)) {
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +trans_len = MIN(sizeof(fw_log) - off, buf_len);
> > +
> > +return nvme_dma_read_prp(n, (uint8_t *) _log + off, trans_len, prp1,
> > + prp2);
> > +}
> > +
> > +static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t 
> > buf_len,
> > +uint64_t off, NvmeRequest *req)
> > +{
> > +uint32_t trans_len;
> > +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> > +NvmeErrorLog errlog;
> > +
> > +if (off > sizeof(errlog)) {
> > + 

Re: [PATCH 04/17] hw/block/nvme: add temperature threshold feature

2020-07-02 Thread Klaus Jensen
On Jul  3 00:44, Dmitry Fomichev wrote:
> On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> > From: Klaus Jensen 
> > 
> > It might seem weird to implement this feature for an emulated device,
> > but it is mandatory to support and the feature is useful for testing
> > asynchronous event request support, which will be added in a later
> > patch.
> > 
> > Signed-off-by: Klaus Jensen 
> > Acked-by: Keith Busch 
> > Reviewed-by: Maxim Levitsky 
> > ---
> >  hw/block/nvme.c  | 48 
> >  hw/block/nvme.h  |  1 +
> >  include/block/nvme.h |  8 +++-
> >  3 files changed, 56 insertions(+), 1 deletion(-)
> > 
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index b7037a7d3504..5ca50646369e 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -59,6 +59,9 @@
> >  #define NVME_DB_SIZE  4
> >  #define NVME_CMB_BIR 2
> >  #define NVME_PMR_BIR 2
> > +#define NVME_TEMPERATURE 0x143
> > +#define NVME_TEMPERATURE_WARNING 0x157
> > +#define NVME_TEMPERATURE_CRITICAL 0x175
> >  
> >  #define NVME_GUEST_ERR(trace, fmt, ...) \
> >  do { \
> > @@ -827,9 +830,31 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl 
> > *n, NvmeCmd *cmd)
> >  static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest 
> > *req)
> >  {
> >  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> > +uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >  uint32_t result;
> >  
> >  switch (dw10) {
> > +case NVME_TEMPERATURE_THRESHOLD:
> > +result = 0;
> > +
> > +/*
> > + * The controller only implements the Composite Temperature 
> > sensor, so
> > + * return 0 for all other sensors.
> > + */
> > +if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> > +break;
> > +}
> > +
> > +switch (NVME_TEMP_THSEL(dw11)) {
> > +case NVME_TEMP_THSEL_OVER:
> > +result = cpu_to_le16(n->features.temp_thresh_hi);
> > +break;
> > +case NVME_TEMP_THSEL_UNDER:
> > +result = cpu_to_le16(n->features.temp_thresh_low);
> > +break;
> > +}
> > +
> > +break;
> > 
> > >  case NVME_VOLATILE_WRITE_CACHE:
> >  result = blk_enable_write_cache(n->conf.blk);
> >  trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> > @@ -874,6 +899,23 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> > *cmd, NvmeRequest *req)
> >  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >  
> >  switch (dw10) {
> > +case NVME_TEMPERATURE_THRESHOLD:
> > +if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> > +break;
> > +}
> > +
> > +switch (NVME_TEMP_THSEL(dw11)) {
> > +case NVME_TEMP_THSEL_OVER:
> > +n->features.temp_thresh_hi = NVME_TEMP_TMPTH(dw11);
> > +break;
> > +case NVME_TEMP_THSEL_UNDER:
> > +n->features.temp_thresh_low = NVME_TEMP_TMPTH(dw11);
> > +break;
> > +default:
> > +return NVME_INVALID_FIELD | NVME_DNR;
> > +}
> > +
> > +break;
> >  case NVME_VOLATILE_WRITE_CACHE:
> >  blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
> >  break;
> > @@ -1454,6 +1496,7 @@ static void nvme_init_state(NvmeCtrl *n)
> >  n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
> >  n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
> >  n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
> > +n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
> >  }
> >  
> >  static void nvme_init_blk(NvmeCtrl *n, Error **errp)
> > @@ -1611,6 +1654,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> > *pci_dev)
> >  id->acl = 3;
> >  id->frmw = 7 << 1;
> >  id->lpa = 1 << 0;
> > +
> > +/* recommended default value (~70 C) */
> > +id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> > +id->cctemp = cpu_to_le16(NVME_TEMPERATURE_CRITICAL);
> > +
> >  id->sqes = (0x6 << 4) | 0x6;
> >  id->cqes = (0x4 << 4) | 0x4;
> >  id->nn = cpu_to_le32(n->num_namespaces);
> > diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> > index 1bf5c80ed843..3acde10e1d2a 100644
> > --- a/hw/block/nvme.h
> > +++ b/hw/block/nvme.h
> > @@ -107,6 +107,7 @@ typedef struct NvmeCtrl {
> >  NvmeSQueue  admin_sq;
> >  NvmeCQueue  admin_cq;
> >  NvmeIdCtrl  id_ctrl;
> > +NvmeFeatureVal  features;
> >  } NvmeCtrl;
> >  
> >  /* calculate the number of LBAs that the namespace can accomodate */
> > diff --git a/include/block/nvme.h b/include/block/nvme.h
> > index 6d1fa6ff2228..bb651d0cbf5a 100644
> > --- a/include/block/nvme.h
> > +++ b/include/block/nvme.h
> > @@ -860,7 +860,13 @@ enum NvmeIdCtrlOncs {
> >  typedef struct NvmeFeatureVal {
> >  uint32_tarbitration;
> >  uint32_tpower_mgmt;
> > -uint32_ttemp_thresh;
> > +union {
> > +struct {
> > +

Re: [PATCH 01/17] hw/block/nvme: bump spec data structures to v1.3

2020-07-02 Thread Klaus Jensen
On Jul  3 00:44, Dmitry Fomichev wrote:
> On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> > From: Klaus Jensen 
> > 
> > Add missing fields in the Identify Controller and Identify Namespace
> > data structures to bring them in line with NVMe v1.3.
> > 
> > This also adds data structures and defines for SGL support which
> > requires a couple of trivial changes to the nvme block driver as well.
> > 
> > Signed-off-by: Klaus Jensen 
> > Acked-by: Fam Zheng 
> > Reviewed-by: Maxim Levitsky 
> > ---
> >  block/nvme.c |  18 ++---
> >  hw/block/nvme.c  |  12 ++--
> >  include/block/nvme.h | 154 ++-
> >  3 files changed, 152 insertions(+), 32 deletions(-)
> > 
> > diff --git a/block/nvme.c b/block/nvme.c
> > index eb2f54dd9dc9..29e90557c428 100644
> > --- a/block/nvme.c
> > +++ b/block/nvme.c
> > @@ -446,7 +446,7 @@ static void nvme_identify(BlockDriverState *bs, int 
> > namespace, Error **errp)
> >  error_setg(errp, "Cannot map buffer for DMA");
> >  goto out;
> >  }
> > -cmd.prp1 = cpu_to_le64(iova);
> > +cmd.dptr.prp1 = cpu_to_le64(iova);
> >  
> >  if (nvme_cmd_sync(bs, s->queues[0], )) {
> >  error_setg(errp, "Failed to identify controller");
> > @@ -545,7 +545,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, 
> > Error **errp)
> >  }
> >  cmd = (NvmeCmd) {
> >  .opcode = NVME_ADM_CMD_CREATE_CQ,
> > -.prp1 = cpu_to_le64(q->cq.iova),
> > +.dptr.prp1 = cpu_to_le64(q->cq.iova),
> >  .cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0x)),
> >  .cdw11 = cpu_to_le32(0x3),
> >  };
> > @@ -556,7 +556,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, 
> > Error **errp)
> >  }
> >  cmd = (NvmeCmd) {
> >  .opcode = NVME_ADM_CMD_CREATE_SQ,
> > -.prp1 = cpu_to_le64(q->sq.iova),
> > +.dptr.prp1 = cpu_to_le64(q->sq.iova),
> >  .cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0x)),
> >  .cdw11 = cpu_to_le32(0x1 | (n << 16)),
> >  };
> > @@ -904,16 +904,16 @@ try_map:
> >  case 0:
> >  abort();
> >  case 1:
> > -cmd->prp1 = pagelist[0];
> > -cmd->prp2 = 0;
> > +cmd->dptr.prp1 = pagelist[0];
> > +cmd->dptr.prp2 = 0;
> >  break;
> >  case 2:
> > -cmd->prp1 = pagelist[0];
> > -cmd->prp2 = pagelist[1];
> > +cmd->dptr.prp1 = pagelist[0];
> > +cmd->dptr.prp2 = pagelist[1];
> >  break;
> >  default:
> > -cmd->prp1 = pagelist[0];
> > -cmd->prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
> > +cmd->dptr.prp1 = pagelist[0];
> > +cmd->dptr.prp2 = cpu_to_le64(req->prp_list_iova + 
> > sizeof(uint64_t));
> >  break;
> >  }
> >  trace_nvme_cmd_map_qiov(s, cmd, req, qiov, entries);
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index 1aee042d4cb2..71b388aa0e20 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -397,8 +397,8 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, 
> > NvmeCmd *cmd,
> >  NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
> >  uint32_t nlb  = le32_to_cpu(rw->nlb) + 1;
> >  uint64_t slba = le64_to_cpu(rw->slba);
> > -uint64_t prp1 = le64_to_cpu(rw->prp1);
> > -uint64_t prp2 = le64_to_cpu(rw->prp2);
> > +uint64_t prp1 = le64_to_cpu(rw->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(rw->dptr.prp2);
> >  
> >  uint8_t lba_index  = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
> >  uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
> > @@ -795,8 +795,8 @@ static inline uint64_t nvme_get_timestamp(const 
> > NvmeCtrl *n)
> >  
> >  static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
> >  {
> > -uint64_t prp1 = le64_to_cpu(cmd->prp1);
> > -uint64_t prp2 = le64_to_cpu(cmd->prp2);
> > +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> >  
> >  uint64_t timestamp = nvme_get_timestamp(n);
> >  
> > @@ -834,8 +834,8 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, 
> > NvmeCmd *cmd)
> >  {
> >  uint16_t ret;
> >  uint64_t timestamp;
> > -uint64_t prp1 = le64_to_cpu(cmd->prp1);
> > -uint64_t prp2 = le64_to_cpu(cmd->prp2);
> > +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> > +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> >  
> >  ret = nvme_dma_write_prp(n, (uint8_t *),
> >  sizeof(timestamp), prp1, prp2);
> > diff --git a/include/block/nvme.h b/include/block/nvme.h
> > index 1720ee1d5158..6d1fa6ff2228 100644
> > --- a/include/block/nvme.h
> > +++ b/include/block/nvme.h
> > @@ -377,15 +377,53 @@ enum NvmePmrmscMask {
> >  #define NVME_PMRMSC_SET_CBA(pmrmsc, val)   \
> >  (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
> >  
> > +enum NvmeSglDescriptorType {
> > +NVME_SGL_DESCR_TYPE_DATA_BLOCK  = 0x0,
> > +  

Re: [PATCH 13/17] hw/block/nvme: make sure ncqr and nsqr is valid

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> 0x is not an allowed value for NCQR and NSQR in Set Features on
> Number of Queues.
> 
> Signed-off-by: Klaus Jensen 
> Acked-by: Keith Busch 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c | 8 
>  1 file changed, 8 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index a41665746d33..2279d8395aaa 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1257,6 +1257,14 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
>  break;
>  case NVME_NUMBER_OF_QUEUES:
> +/*
> + * NVMe v1.3, Section 5.21.1.7: 0x is not an allowed value for 
> NCQR
> + * and NSQR.
> + */
> +if ((dw11 & 0x) == 0x || ((dw11 >> 16) & 0x) == 0x) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
>  trace_pci_nvme_setfeat_numq((dw11 & 0x) + 1,
>  ((dw11 >> 16) & 0x) + 1,
>  n->params.max_ioqpairs,


Re: [PATCH 17/17] hw/block/nvme: bump supported version to v1.3

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Bump the supported NVM Express version to v1.3.
> 
> Signed-off-by: Klaus Jensen 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 9f0b9de73307..fbe9b2d50895 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -57,6 +57,7 @@
>  #define NVME_MAX_IOQPAIRS 0x
>  #define NVME_REG_SIZE 0x1000
>  #define NVME_DB_SIZE  4
> +#define NVME_SPEC_VER 0x00010300
>  #define NVME_CMB_BIR 2
>  #define NVME_PMR_BIR 2
>  #define NVME_TEMPERATURE 0x143
> @@ -2103,6 +2104,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  id->ieee[0] = 0x00;
>  id->ieee[1] = 0x02;
>  id->ieee[2] = 0xb3;
> +id->ver = cpu_to_le32(NVME_SPEC_VER);
>  id->oacs = cpu_to_le16(0);
>  
>  /*
> @@ -2148,7 +2150,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  NVME_CAP_SET_CSS(n->bar.cap, 1);
>  NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
>  
> -n->bar.vs = 0x00010200;
> +n->bar.vs = NVME_SPEC_VER;
>  n->bar.intmc = n->bar.intms = 0;
>  }
>  


Re: [PATCH 10/17] hw/block/nvme: fix missing endian conversion

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Fix a missing cpu_to conversion.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index c2507d8836fd..da13ca1ddb60 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1081,7 +1081,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  
>  break;
>  case NVME_VOLATILE_WRITE_CACHE:
> -result = blk_enable_write_cache(n->conf.blk);
> +result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
>  trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
>  break;
>  case NVME_NUMBER_OF_QUEUES:


Re: [PATCH 14/17] hw/block/nvme: support identify namespace descriptor list

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Since we are not providing the NGUID or EUI64 fields, we must support
> the Namespace UUID. We do not have any way of storing a persistent
> unique identifier, so conjure up a UUID that is just the namespace id.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c   | 41 +
>  hw/block/trace-events |  1 +
>  2 files changed, 42 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 2279d8395aaa..8a816b558eeb 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -972,6 +972,45 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, 
> NvmeIdentify *c)
>  return ret;
>  }
>  
> +static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeIdentify *c)
> +{
> +uint32_t nsid = le32_to_cpu(c->nsid);
> +uint64_t prp1 = le64_to_cpu(c->prp1);
> +uint64_t prp2 = le64_to_cpu(c->prp2);
> +
> +uint8_t list[NVME_IDENTIFY_DATA_SIZE];
> +
> +struct data {
> +struct {
> +NvmeIdNsDescr hdr;
> +uint8_t v[16];
> +} uuid;
> +};
> +
> +struct data *ns_descrs = (struct data *)list;
> +
> +trace_pci_nvme_identify_ns_descr_list(nsid);
> +
> +if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
> +trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
> +return NVME_INVALID_NSID | NVME_DNR;
> +}
> +
> +memset(list, 0x0, sizeof(list));
> +
> +/*
> + * Because the NGUID and EUI64 fields are 0 in the Identify Namespace 
> data
> + * structure, a Namespace UUID (nidt = 0x3) must be reported in the
> + * Namespace Identification Descriptor. Add a very basic Namespace UUID
> + * here.
> + */
> +ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID;
> +ns_descrs->uuid.hdr.nidl = NVME_NIDT_UUID_LEN;
> +stl_be_p(_descrs->uuid.v, nsid);
> +
> +return nvme_dma_read_prp(n, list, NVME_IDENTIFY_DATA_SIZE, prp1, prp2);
> +}
> +
>  static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
>  {
>  NvmeIdentify *c = (NvmeIdentify *)cmd;
> @@ -983,6 +1022,8 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
>  return nvme_identify_ctrl(n, c);
>  case NVME_ID_CNS_NS_ACTIVE_LIST:
>  return nvme_identify_nslist(n, c);
> +case NVME_ID_CNS_NS_DESCR_LIST:
> +return nvme_identify_ns_descr_list(n, c);
>  default:
>  trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
>  return NVME_INVALID_FIELD | NVME_DNR;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 4a4ef34071df..7b7303cab1dd 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -45,6 +45,7 @@ pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, 
> cqid=%"PRIu16""
>  pci_nvme_identify_ctrl(void) "identify controller"
>  pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
>  pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> +pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32""
>  pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, 
> uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 
> 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
>  pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint8_t sel, uint32_t cdw11) 
> "cid %"PRIu16" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
>  pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint8_t save, uint32_t cdw11) 
> "cid %"PRIu16" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""


Re: [PATCH 12/17] hw/block/nvme: support the get/set features select and save fields

2020-07-02 Thread Dmitry Fomichev
On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Since the device does not have any persistance state storage, no
> features are "saveable" and setting the Save (SV) field in any Set
> Features command will result in a Feature Identifier Not Saveable status
> code.
> 
> Similarly, if the Select (SEL) field is set to request saved values, the
> devices will (as it should) return the default values instead.
> 
> Since this also introduces "Supported Capabilities", the nsid field is
> now also checked for validity wrt. the feature being get/set'ed.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c   | 87 +++
>  hw/block/nvme.h   |  8 
>  hw/block/trace-events |  4 +-
>  include/block/nvme.h  | 27 +-
>  4 files changed, 115 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 647f408854ae..a41665746d33 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1056,16 +1056,43 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  {
>  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> +uint32_t nsid = le32_to_cpu(cmd->nsid);
>  uint32_t result;
>  uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> +NvmeGetFeatureSelect sel = NVME_GETFEAT_SELECT(dw10);
>  uint16_t iv;
>  
> -trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> +trace_pci_nvme_getfeat(nvme_cid(req), fid, sel, dw11);
>  
>  if (!nvme_feature_support[fid]) {
>  return NVME_INVALID_FIELD | NVME_DNR;
>  }
>  
> +if (nvme_feature_cap[fid] & NVME_FEAT_CAP_NS) {
> +if (!nsid || nsid > n->num_namespaces) {
> +/*
> + * The Reservation Notification Mask and Reservation Persistence
> + * features require a status code of Invalid Field in Command 
> when
> + * NSID is 0x. Since the device does not support those
> + * features we can always return Invalid Namespace or Format as 
> we
> + * should do for all other features.
> + */
> +return NVME_INVALID_NSID | NVME_DNR;
> +}
> +}
> +
> +switch (sel) {
> +case NVME_GETFEAT_SELECT_CURRENT:
> +break;
> +case NVME_GETFEAT_SELECT_SAVED:
> +/* no features are saveable by the controller; fallthrough */
> +case NVME_GETFEAT_SELECT_DEFAULT:
> +goto defaults;
> +case NVME_GETFEAT_SELECT_CAP:
> +result = cpu_to_le32(nvme_feature_cap[fid]);
> +goto out;
> +}
> +
>  switch (fid) {
>  case NVME_TEMPERATURE_THRESHOLD:
>  result = 0;
> @@ -1091,6 +1118,29 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  case NVME_VOLATILE_WRITE_CACHE:
>  result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
>  trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> +break;
> +case NVME_ASYNCHRONOUS_EVENT_CONF:
> +result = cpu_to_le32(n->features.async_config);
> +break;
> +case NVME_TIMESTAMP:
> +return nvme_get_feature_timestamp(n, cmd);
> +default:
> +break;
> +}
> +
> +defaults:
> +switch (fid) {
> +case NVME_TEMPERATURE_THRESHOLD:
> +result = 0;

This will reset the high or low threshold value set earlier in this function.
You could do the following to avoid this -

@ -1163,7 +1163,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
*cmd, NvmeRequest *req)
 break;
 }
 
-break;
+goto out;
 case NVME_VOLATILE_WRITE_CACHE:
 result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
 trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");

> +
> +if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> +break;
> +}
> +
> +if (NVME_TEMP_THSEL(dw11) == NVME_TEMP_THSEL_OVER) {
> +result = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> +}
> +
>  break;
>  case NVME_NUMBER_OF_QUEUES:
>  result = cpu_to_le32((n->params.max_ioqpairs - 1) |
> @@ -1110,16 +1160,12 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  
>  result = cpu_to_le32(result);
>  break;
> -case NVME_ASYNCHRONOUS_EVENT_CONF:
> -result = cpu_to_le32(n->features.async_config);
> -break;
> -case NVME_TIMESTAMP:
> -return nvme_get_feature_timestamp(n, cmd);
>  default:
>  result = cpu_to_le32(nvme_feature_default[fid]);
>  break;
>  }
>  
> +out:
>  req->cqe.result = result;
>  return NVME_SUCCESS;
>  }
> @@ -1146,14 +1192,37 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  {
>  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> +uint32_t 

Re: [PATCH 16/17] hw/block/nvme: provide the mandatory subnqn field

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> The SUBNQN field is mandatory in NVM Express 1.3.
> 
> Signed-off-by: Klaus Jensen 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 798f6f30e7da..9f0b9de73307 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -2131,6 +2131,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP |
> NVME_ONCS_FEATURES);
>  
> +pstrcpy((char *) id->subnqn, sizeof(id->subnqn), 
> "nqn.2019-08.org.qemu:");
> +pstrcat((char *) id->subnqn, sizeof(id->subnqn), n->params.serial);
> +
>  id->psd[0].mp = cpu_to_le16(0x9c4);
>  id->psd[0].enlat = cpu_to_le32(0x10);
>  id->psd[0].exlat = cpu_to_le32(0x4);


Re: [PATCH 09/17] hw/block/nvme: flush write cache when disabled

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> If the write cache is disabled with a Set Features command, flush it if
> currently enabled.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c | 4 
>  1 file changed, 4 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 39e680a15c56..c2507d8836fd 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1153,6 +1153,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  
>  break;
>  case NVME_VOLATILE_WRITE_CACHE:
> +if (!(dw11 & 0x1) && blk_enable_write_cache(n->conf.blk)) {
> +blk_flush(n->conf.blk);
> +}
> +
>  blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
>  break;
>  case NVME_NUMBER_OF_QUEUES:


Re: [PATCH 15/17] hw/block/nvme: enforce valid queue creation sequence

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Support returning Command Sequence Error if Set Features on Number of
> Queues is called after queues have been created.
> 
> Signed-off-by: Klaus Jensen 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c | 12 
>  hw/block/nvme.h |  1 +
>  2 files changed, 13 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 8a816b558eeb..798f6f30e7da 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -911,6 +911,13 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
>  cq = g_malloc0(sizeof(*cq));
>  nvme_init_cq(cq, n, prp1, cqid, vector, qsize + 1,
>  NVME_CQ_FLAGS_IEN(qflags));
> +
> +/*
> + * It is only required to set qs_created when creating a completion 
> queue;
> + * creating a submission queue without a matching completion queue will
> + * fail.
> + */
> +n->qs_created = true;
>  return NVME_SUCCESS;
>  }
>  
> @@ -1298,6 +1305,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
>  break;
>  case NVME_NUMBER_OF_QUEUES:
> +if (n->qs_created) {
> +return NVME_CMD_SEQ_ERROR | NVME_DNR;
> +}
> +
>  /*
>   * NVMe v1.3, Section 5.21.1.7: 0x is not an allowed value for 
> NCQR
>   * and NSQR.
> @@ -1430,6 +1441,7 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
>  
>  n->aer_queued = 0;
>  n->outstanding_aers = 0;
> +n->qs_created = false;
>  
>  blk_flush(n->conf.blk);
>  n->bar.cc = 0;
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 34a29d96..54ec54f491bf 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -124,6 +124,7 @@ typedef struct NvmeCtrl {
>  BlockConfconf;
>  NvmeParams   params;
>  
> +boolqs_created;
>  uint32_tpage_size;
>  uint16_tpage_bits;
>  uint16_tmax_prp_ents;


Re: [PATCH 11/17] hw/block/nvme: add remaining mandatory controller parameters

2020-07-02 Thread Dmitry Fomichev
LGTM with one small nit (see below)...

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Add support for any remaining mandatory controller operating parameters
> (features).
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c   | 39 +--
>  hw/block/nvme.h   | 18 ++
>  hw/block/trace-events |  2 ++
>  include/block/nvme.h  |  7 +++
>  4 files changed, 60 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index da13ca1ddb60..647f408854ae 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1057,8 +1057,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>  uint32_t result;
> +uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> +uint16_t iv;
>  
> -switch (dw10) {
> +trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> +
> +if (!nvme_feature_support[fid]) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +switch (fid) {
>  case NVME_TEMPERATURE_THRESHOLD:
>  result = 0;
>  
> @@ -1089,14 +1097,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>   ((n->params.max_ioqpairs - 1) << 16));
>  trace_pci_nvme_getfeat_numq(result);
>  break;
> +case NVME_INTERRUPT_VECTOR_CONF:
> +iv = dw11 & 0x;
> +if (iv >= n->params.max_ioqpairs + 1) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +result = iv;
> +if (iv == n->admin_cq.vector) {
> +result |= NVME_INTVC_NOCOALESCING;
> +}
> +
> +result = cpu_to_le32(result);
> +break;
>  case NVME_ASYNCHRONOUS_EVENT_CONF:
>  result = cpu_to_le32(n->features.async_config);
>  break;
>  case NVME_TIMESTAMP:
>  return nvme_get_feature_timestamp(n, cmd);
>  default:
> -trace_pci_nvme_err_invalid_getfeat(dw10);
> -return NVME_INVALID_FIELD | NVME_DNR;
> +result = cpu_to_le32(nvme_feature_default[fid]);
> +break;
>  }
>  
>  req->cqe.result = result;
> @@ -1125,8 +1146,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  {
>  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> +uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>  
> -switch (dw10) {
> +trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> +
> +if (!nvme_feature_support[fid]) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +switch (fid) {
>  case NVME_TEMPERATURE_THRESHOLD:
>  if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
>  break;
> @@ -1173,8 +1201,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  case NVME_TIMESTAMP:
>  return nvme_set_feature_timestamp(n, cmd);
>  default:
> -trace_pci_nvme_err_invalid_setfeat(dw10);
> -return NVME_INVALID_FIELD | NVME_DNR;
> +return NVME_FEAT_NOT_CHANGABLE | NVME_DNR;

In spec, it is "Changeable", could as well add that 'e' here

>  }
>  return NVME_SUCCESS;
>  }
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 16a254d30b4e..d0763eb59e5d 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -90,6 +90,24 @@ typedef struct NvmeFeatureVal {
>  uint32_tasync_config;
>  } NvmeFeatureVal;
>  
> +static const uint32_t nvme_feature_default[0x100] = {
> +[NVME_ARBITRATION]   = NVME_ARB_AB_NOLIMIT,
> +};
> +
> +static const bool nvme_feature_support[0x100] = {
> +[NVME_ARBITRATION]  = true,
> +[NVME_POWER_MANAGEMENT] = true,
> +[NVME_TEMPERATURE_THRESHOLD]= true,
> +[NVME_ERROR_RECOVERY]   = true,
> +[NVME_VOLATILE_WRITE_CACHE] = true,
> +[NVME_NUMBER_OF_QUEUES] = true,
> +[NVME_INTERRUPT_COALESCING] = true,
> +[NVME_INTERRUPT_VECTOR_CONF]= true,
> +[NVME_WRITE_ATOMICITY]  = true,
> +[NVME_ASYNCHRONOUS_EVENT_CONF]  = true,
> +[NVME_TIMESTAMP]= true,
> +};
> +
>  typedef struct NvmeCtrl {
>  PCIDeviceparent_obj;
>  MemoryRegion iomem;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 091af16ca7d7..42e62f4649f8 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
>  pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
>  pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
>  pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, 
> uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 
> 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
> +pci_nvme_getfeat(uint16_t cid, 

Re: [PATCH 07/17] hw/block/nvme: add support for the asynchronous event request command

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Add support for the Asynchronous Event Request command. Required for
> compliance with NVMe revision 1.3d. See NVM Express 1.3d, Section 5.2
> ("Asynchronous Event Request command").
> 
> Mostly imported from Keith's qemu-nvme tree. Modified with a max number
> of queued events (controllable with the aer_max_queued device
> parameter). The spec states that the controller *should* retain
> events, so we do best effort here.
> 
> Signed-off-by: Klaus Jensen 
> Signed-off-by: Klaus Jensen 
> Acked-by: Keith Busch 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c   | 180 --
>  hw/block/nvme.h   |  10 ++-
>  hw/block/trace-events |   9 +++
>  include/block/nvme.h  |   8 +-
>  4 files changed, 198 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index fe5d052ab159..39e680a15c56 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -342,6 +342,85 @@ static void nvme_enqueue_req_completion(NvmeCQueue *cq, 
> NvmeRequest *req)
>  timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
>  }
>  
> +static void nvme_process_aers(void *opaque)
> +{
> +NvmeCtrl *n = opaque;
> +NvmeAsyncEvent *event, *next;
> +
> +trace_pci_nvme_process_aers(n->aer_queued);
> +
> +QTAILQ_FOREACH_SAFE(event, >aer_queue, entry, next) {
> +NvmeRequest *req;
> +NvmeAerResult *result;
> +
> +/* can't post cqe if there is nothing to complete */
> +if (!n->outstanding_aers) {
> +trace_pci_nvme_no_outstanding_aers();
> +break;
> +}
> +
> +/* ignore if masked (cqe posted, but event not cleared) */
> +if (n->aer_mask & (1 << event->result.event_type)) {
> +trace_pci_nvme_aer_masked(event->result.event_type, n->aer_mask);
> +continue;
> +}
> +
> +QTAILQ_REMOVE(>aer_queue, event, entry);
> +n->aer_queued--;
> +
> +n->aer_mask |= 1 << event->result.event_type;
> +n->outstanding_aers--;
> +
> +req = n->aer_reqs[n->outstanding_aers];
> +
> +result = (NvmeAerResult *) >cqe.result;
> +result->event_type = event->result.event_type;
> +result->event_info = event->result.event_info;
> +result->log_page = event->result.log_page;
> +g_free(event);
> +
> +req->status = NVME_SUCCESS;
> +
> +trace_pci_nvme_aer_post_cqe(result->event_type, result->event_info,
> +result->log_page);
> +
> +nvme_enqueue_req_completion(>admin_cq, req);
> +}
> +}
> +
> +static void nvme_enqueue_event(NvmeCtrl *n, uint8_t event_type,
> +   uint8_t event_info, uint8_t log_page)
> +{
> +NvmeAsyncEvent *event;
> +
> +trace_pci_nvme_enqueue_event(event_type, event_info, log_page);
> +
> +if (n->aer_queued == n->params.aer_max_queued) {
> +trace_pci_nvme_enqueue_event_noqueue(n->aer_queued);
> +return;
> +}
> +
> +event = g_new(NvmeAsyncEvent, 1);
> +event->result = (NvmeAerResult) {
> +.event_type = event_type,
> +.event_info = event_info,
> +.log_page   = log_page,
> +};
> +
> +QTAILQ_INSERT_TAIL(>aer_queue, event, entry);
> +n->aer_queued++;
> +
> +nvme_process_aers(n);
> +}
> +
> +static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type)
> +{
> +n->aer_mask &= ~(1 << event_type);
> +if (!QTAILQ_EMPTY(>aer_queue)) {
> +nvme_process_aers(n);
> +}
> +}
> +
>  static void nvme_rw_cb(void *opaque, int ret)
>  {
>  NvmeRequest *req = opaque;
> @@ -592,8 +671,9 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
>  return NVME_SUCCESS;
>  }
>  
> -static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> -uint64_t off, NvmeRequest *req)
> +static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint8_t rae,
> +uint32_t buf_len, uint64_t off,
> +NvmeRequest *req)
>  {
>  uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
>  uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> @@ -642,6 +722,10 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd 
> *cmd, uint32_t buf_len,
>  smart.power_on_hours[0] =
>  cpu_to_le64current_ms - n->starttime_ms) / 1000) / 60) / 60);
>  
> +if (!rae) {
> +nvme_clear_events(n, NVME_AER_TYPE_SMART);
> +}
> +
>  return nvme_dma_read_prp(n, (uint8_t *)  + off, trans_len, prp1,
>   prp2);
>  }
> @@ -668,14 +752,19 @@ static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd 
> *cmd, uint32_t buf_len,
>   prp2);
>  }
>  
> -static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> -  

Re: [PATCH 05/17] hw/block/nvme: mark fw slot 1 as read-only

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Mark firmware slot 1 as read-only and only support that slot.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c  | 3 ++-
>  include/block/nvme.h | 4 
>  2 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 5ca50646369e..f8e91a6965ed 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -62,6 +62,7 @@
>  #define NVME_TEMPERATURE 0x143
>  #define NVME_TEMPERATURE_WARNING 0x157
>  #define NVME_TEMPERATURE_CRITICAL 0x175
> +#define NVME_NUM_FW_SLOTS 1
>  
>  #define NVME_GUEST_ERR(trace, fmt, ...) \
>  do { \
> @@ -1652,7 +1653,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>   * inconsequential.
>   */
>  id->acl = 3;
> -id->frmw = 7 << 1;
> +id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
>  id->lpa = 1 << 0;
>  
>  /* recommended default value (~70 C) */
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index bb651d0cbf5a..003b15af9cd9 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -842,6 +842,10 @@ enum NvmeIdCtrlOncs {
>  NVME_ONCS_TIMESTAMP = 1 << 6,
>  };
>  
> +enum NvmeIdCtrlFrmw {
> +NVME_FRMW_SLOT1_RO = 1 << 0,
> +};
> +
>  #define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
>  #define NVME_CTRL_SQES_MAX(sqes) (((sqes) >> 4) & 0xf)
>  #define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf)


Re: [PATCH 06/17] hw/block/nvme: add support for the get log page command

2020-07-02 Thread Dmitry Fomichev
On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Add support for the Get Log Page command and basic implementations of
> the mandatory Error Information, SMART / Health Information and Firmware
> Slot Information log pages.
> 
> In violation of the specification, the SMART / Health Information log
> page does not persist information over the lifetime of the controller
> because the device has no place to store such persistent state.
> 
> Note that the LPA field in the Identify Controller data structure
> intentionally has bit 0 cleared because there is no namespace specific
> information in the SMART / Health information log page.
> 
> Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d,
> Section 5.14 ("Get Log Page command").
> 
> Signed-off-by: Klaus Jensen 
> Signed-off-by: Klaus Jensen 
> Acked-by: Keith Busch 
> ---
>  hw/block/nvme.c   | 141 +-
>  hw/block/nvme.h   |   2 +
>  hw/block/trace-events |   2 +
>  include/block/nvme.h  |   4 ++
>  4 files changed, 148 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index f8e91a6965ed..fe5d052ab159 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -592,6 +592,141 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd 
> *cmd)
>  return NVME_SUCCESS;
>  }
>  
> +static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> +uint64_t off, NvmeRequest *req)
> +{
> +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +uint32_t nsid = le32_to_cpu(cmd->nsid);
> +
> +uint32_t trans_len;
> +time_t current_ms;
> +uint64_t units_read = 0, units_written = 0;
> +uint64_t read_commands = 0, write_commands = 0;
> +NvmeSmartLog smart;
> +BlockAcctStats *s;
> +
> +if (nsid && nsid != 0x) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +s = blk_get_stats(n->conf.blk);
> +
> +units_read = s->nr_bytes[BLOCK_ACCT_READ] >> BDRV_SECTOR_BITS;
> +units_written = s->nr_bytes[BLOCK_ACCT_WRITE] >> BDRV_SECTOR_BITS;
> +read_commands = s->nr_ops[BLOCK_ACCT_READ];
> +write_commands = s->nr_ops[BLOCK_ACCT_WRITE];
> +
> +if (off > sizeof(smart)) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +trans_len = MIN(sizeof(smart) - off, buf_len);
> +
> +memset(, 0x0, sizeof(smart));
> +
> +smart.data_units_read[0] = cpu_to_le64(units_read / 1000);
> +smart.data_units_written[0] = cpu_to_le64(units_written / 1000);
> +smart.host_read_commands[0] = cpu_to_le64(read_commands);
> +smart.host_write_commands[0] = cpu_to_le64(write_commands);
> +
> +smart.temperature[0] = n->temperature & 0xff;
> +smart.temperature[1] = (n->temperature >> 8) & 0xff;

Why not change temperature[2] in NvmeSmartLog to uint16_t and use cpu_to_le16() 
here?

> +if ((n->temperature >= n->features.temp_thresh_hi) ||
> +(n->temperature <= n->features.temp_thresh_low)) {
> +smart.critical_warning |= NVME_SMART_TEMPERATURE;
> +}
> +
> +current_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
> +smart.power_on_hours[0] =
> +cpu_to_le64current_ms - n->starttime_ms) / 1000) / 60) / 60);
> +
> +return nvme_dma_read_prp(n, (uint8_t *)  + off, trans_len, prp1,
> + prp2);
> +}
> +
> +static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> + uint64_t off, NvmeRequest *req)
> +{
> +uint32_t trans_len;
> +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +NvmeFwSlotInfoLog fw_log = {
> +.afi = 0x1,
> +};
> +
> +strpadcpy((char *)_log.frs1, sizeof(fw_log.frs1), "1.0", ' ');
> +
> +if (off > sizeof(fw_log)) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +trans_len = MIN(sizeof(fw_log) - off, buf_len);
> +
> +return nvme_dma_read_prp(n, (uint8_t *) _log + off, trans_len, prp1,
> + prp2);
> +}
> +
> +static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> +uint64_t off, NvmeRequest *req)
> +{
> +uint32_t trans_len;
> +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +NvmeErrorLog errlog;
> +
> +if (off > sizeof(errlog)) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +memset(, 0x0, sizeof(errlog));
> +
> +trans_len = MIN(sizeof(errlog) - off, buf_len);
> +
> +return nvme_dma_read_prp(n, (uint8_t *), trans_len, prp1, prp2);
> +}
> +
> +static uint16_t nvme_get_log(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> +{
> +uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> +uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> +uint32_t dw12 = le32_to_cpu(cmd->cdw12);
> +

Re: [PATCH 08/17] hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> The NvmeFeatureVal does not belong with the spec-related data structures
> in include/block/nvme.h that is shared between the block-level nvme
> driver and the emulated nvme device.
> 
> Move it into the nvme device specific header file as it is the only
> user of the structure. Also, remove the unused members.
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.h  | 11 +++
>  include/block/nvme.h | 20 
>  2 files changed, 11 insertions(+), 20 deletions(-)
> 
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 1f64a0e94035..16a254d30b4e 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -79,6 +79,17 @@ static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
>  #define NVME(obj) \
>  OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
>  
> +typedef struct NvmeFeatureVal {
> +union {
> +struct {
> +uint16_t temp_thresh_hi;
> +uint16_t temp_thresh_low;
> +};
> +uint32_t temp_thresh;
> +};
> +uint32_tasync_config;
> +} NvmeFeatureVal;
> +
>  typedef struct NvmeCtrl {
>  PCIDeviceparent_obj;
>  MemoryRegion iomem;
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index e98584e38134..c9f232a70e98 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -865,26 +865,6 @@ enum NvmeIdCtrlLpa {
>  #define NVME_CTRL_SGLS_MPTR_SGL  (0x1 << 19)
>  #define NVME_CTRL_SGLS_ADDR_OFFSET   (0x1 << 20)
>  
> -typedef struct NvmeFeatureVal {
> -uint32_tarbitration;
> -uint32_tpower_mgmt;
> -union {
> -struct {
> -uint16_t temp_thresh_hi;
> -uint16_t temp_thresh_low;
> -};
> -uint32_t temp_thresh;
> -};
> -uint32_terr_rec;
> -uint32_tvolatile_wc;
> -uint32_tnum_queues;
> -uint32_tint_coalescing;
> -uint32_t*int_vector_config;
> -uint32_twrite_atomicity;
> -uint32_tasync_config;
> -uint32_tsw_prog_marker;
> -} NvmeFeatureVal;
> -
>  #define NVME_ARB_AB(arb)(arb & 0x7)
>  #define NVME_ARB_LPW(arb)   ((arb >> 8) & 0xff)
>  #define NVME_ARB_MPW(arb)   ((arb >> 16) & 0xff)


Re: [PATCH 04/17] hw/block/nvme: add temperature threshold feature

2020-07-02 Thread Dmitry Fomichev
On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> It might seem weird to implement this feature for an emulated device,
> but it is mandatory to support and the feature is useful for testing
> asynchronous event request support, which will be added in a later
> patch.
> 
> Signed-off-by: Klaus Jensen 
> Acked-by: Keith Busch 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c  | 48 
>  hw/block/nvme.h  |  1 +
>  include/block/nvme.h |  8 +++-
>  3 files changed, 56 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index b7037a7d3504..5ca50646369e 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -59,6 +59,9 @@
>  #define NVME_DB_SIZE  4
>  #define NVME_CMB_BIR 2
>  #define NVME_PMR_BIR 2
> +#define NVME_TEMPERATURE 0x143
> +#define NVME_TEMPERATURE_WARNING 0x157
> +#define NVME_TEMPERATURE_CRITICAL 0x175
>  
>  #define NVME_GUEST_ERR(trace, fmt, ...) \
>  do { \
> @@ -827,9 +830,31 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, 
> NvmeCmd *cmd)
>  static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>  {
>  uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> +uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>  uint32_t result;
>  
>  switch (dw10) {
> +case NVME_TEMPERATURE_THRESHOLD:
> +result = 0;
> +
> +/*
> + * The controller only implements the Composite Temperature sensor, 
> so
> + * return 0 for all other sensors.
> + */
> +if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> +break;
> +}
> +
> +switch (NVME_TEMP_THSEL(dw11)) {
> +case NVME_TEMP_THSEL_OVER:
> +result = cpu_to_le16(n->features.temp_thresh_hi);
> +break;
> +case NVME_TEMP_THSEL_UNDER:
> +result = cpu_to_le16(n->features.temp_thresh_low);
> +break;
> +}
> +
> +break;
> 
> >  case NVME_VOLATILE_WRITE_CACHE:
>  result = blk_enable_write_cache(n->conf.blk);
>  trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> @@ -874,6 +899,23 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>  
>  switch (dw10) {
> +case NVME_TEMPERATURE_THRESHOLD:
> +if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> +break;
> +}
> +
> +switch (NVME_TEMP_THSEL(dw11)) {
> +case NVME_TEMP_THSEL_OVER:
> +n->features.temp_thresh_hi = NVME_TEMP_TMPTH(dw11);
> +break;
> +case NVME_TEMP_THSEL_UNDER:
> +n->features.temp_thresh_low = NVME_TEMP_TMPTH(dw11);
> +break;
> +default:
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +break;
>  case NVME_VOLATILE_WRITE_CACHE:
>  blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
>  break;
> @@ -1454,6 +1496,7 @@ static void nvme_init_state(NvmeCtrl *n)
>  n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
>  n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
>  n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
> +n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
>  }
>  
>  static void nvme_init_blk(NvmeCtrl *n, Error **errp)
> @@ -1611,6 +1654,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  id->acl = 3;
>  id->frmw = 7 << 1;
>  id->lpa = 1 << 0;
> +
> +/* recommended default value (~70 C) */
> +id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> +id->cctemp = cpu_to_le16(NVME_TEMPERATURE_CRITICAL);
> +
>  id->sqes = (0x6 << 4) | 0x6;
>  id->cqes = (0x4 << 4) | 0x4;
>  id->nn = cpu_to_le32(n->num_namespaces);
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 1bf5c80ed843..3acde10e1d2a 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -107,6 +107,7 @@ typedef struct NvmeCtrl {
>  NvmeSQueue  admin_sq;
>  NvmeCQueue  admin_cq;
>  NvmeIdCtrl  id_ctrl;
> +NvmeFeatureVal  features;
>  } NvmeCtrl;
>  
>  /* calculate the number of LBAs that the namespace can accomodate */
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index 6d1fa6ff2228..bb651d0cbf5a 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -860,7 +860,13 @@ enum NvmeIdCtrlOncs {
>  typedef struct NvmeFeatureVal {
>  uint32_tarbitration;
>  uint32_tpower_mgmt;
> -uint32_ttemp_thresh;
> +union {
> +struct {
> +uint16_t temp_thresh_hi;
> +uint16_t temp_thresh_low;
> +};
> +uint32_t temp_thresh;

temp_thresh seems unused, is this union really needed?

> +};
>  uint32_terr_rec;
>  uint32_tvolatile_wc;
>  uint32_tnum_queues;


Re: [PATCH 02/17] hw/block/nvme: additional tracing

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Add various additional tracing and streamline nvme_identify_ns and
> nvme_identify_nslist (they do not need to repeat the command, it is
> already in the trace name).
> 
> Signed-off-by: Klaus Jensen 
> ---
>  hw/block/nvme.c   | 19 +++
>  hw/block/nvme.h   | 14 ++
>  hw/block/trace-events | 13 +++--
>  3 files changed, 44 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 71b388aa0e20..f5d9148f0936 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -331,6 +331,8 @@ static void nvme_post_cqes(void *opaque)
>  static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
>  {
>  assert(cq->cqid == req->sq->cqid);
> +trace_pci_nvme_enqueue_req_completion(nvme_cid(req), cq->cqid,
> +  req->status);
>  QTAILQ_REMOVE(>sq->out_req_list, req, entry);
>  QTAILQ_INSERT_TAIL(>req_list, req, entry);
>  timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
> @@ -343,6 +345,8 @@ static void nvme_rw_cb(void *opaque, int ret)
>  NvmeCtrl *n = sq->ctrl;
>  NvmeCQueue *cq = n->cq[sq->cqid];
>  
> +trace_pci_nvme_rw_cb(nvme_cid(req));
> +
>  if (!ret) {
>  block_acct_done(blk_get_stats(n->conf.blk), >acct);
>  req->status = NVME_SUCCESS;
> @@ -378,6 +382,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, 
> NvmeNamespace *ns, NvmeCmd *cmd,
>  uint64_t offset = slba << data_shift;
>  uint32_t count = nlb << data_shift;
>  
> +trace_pci_nvme_write_zeroes(nvme_cid(req), slba, nlb);
> +
>  if (unlikely(slba + nlb > ns->id_ns.nsze)) {
>  trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
>  return NVME_LBA_RANGE | NVME_DNR;
> @@ -445,6 +451,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, 
> NvmeRequest *req)
>  NvmeNamespace *ns;
>  uint32_t nsid = le32_to_cpu(cmd->nsid);
>  
> +trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), cmd->opcode);
> +
>  if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
>  trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
>  return NVME_INVALID_NSID | NVME_DNR;
> @@ -876,6 +884,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd 
> *cmd, NvmeRequest *req)
>  
>  static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>  {
> +trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), cmd->opcode);
> +
>  switch (cmd->opcode) {
>  case NVME_ADM_CMD_DELETE_SQ:
>  return nvme_del_sq(n, cmd);
> @@ -1204,6 +1214,8 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr 
> addr, unsigned size)
>  uint8_t *ptr = (uint8_t *)>bar;
>  uint64_t val = 0;
>  
> +trace_pci_nvme_mmio_read(addr);
> +
>  if (unlikely(addr & (sizeof(uint32_t) - 1))) {
>  NVME_GUEST_ERR(pci_nvme_ub_mmiord_misaligned32,
> "MMIO read not 32-bit aligned,"
> @@ -1273,6 +1285,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, 
> int val)
>  return;
>  }
>  
> +trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
> +
>  start_sqs = nvme_cq_full(cq) ? 1 : 0;
>  cq->head = new_head;
>  if (start_sqs) {
> @@ -1311,6 +1325,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, 
> int val)
>  return;
>  }
>  
> +trace_pci_nvme_mmio_doorbell_sq(sq->sqid, new_tail);
> +
>  sq->tail = new_tail;
>  timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
>  }
> @@ -1320,6 +1336,9 @@ static void nvme_mmio_write(void *opaque, hwaddr addr, 
> uint64_t data,
>  unsigned size)
>  {
>  NvmeCtrl *n = (NvmeCtrl *)opaque;
> +
> +trace_pci_nvme_mmio_write(addr, data);
> +
>  if (addr < sizeof(n->bar)) {
>  nvme_write_bar(n, addr, data, size);
>  } else if (addr >= 0x1000) {
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 1d30c0bca283..1bf5c80ed843 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -115,4 +115,18 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, 
> NvmeNamespace *ns)
>  return n->ns_size >> nvme_ns_lbads(ns);
>  }
>  
> +static inline uint16_t nvme_cid(NvmeRequest *req)
> +{
> +if (req) {
> +return le16_to_cpu(req->cqe.cid);
> +}
> +
> +return 0x;
> +}
> +
> +static inline uint16_t nvme_sqid(NvmeRequest *req)
> +{
> +return le16_to_cpu(req->sq->sqid);
> +}
> +
>  #endif /* HW_NVME_H */
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 958fcc5508d1..c40c0d2e4b28 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -33,19 +33,28 @@ pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ 
> vector %u"
>  pci_nvme_irq_pin(void) "pulsing IRQ pin"
>  pci_nvme_irq_masked(void) "IRQ is masked"

Re: [PATCH 01/17] hw/block/nvme: bump spec data structures to v1.3

2020-07-02 Thread Dmitry Fomichev
On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Add missing fields in the Identify Controller and Identify Namespace
> data structures to bring them in line with NVMe v1.3.
> 
> This also adds data structures and defines for SGL support which
> requires a couple of trivial changes to the nvme block driver as well.
> 
> Signed-off-by: Klaus Jensen 
> Acked-by: Fam Zheng 
> Reviewed-by: Maxim Levitsky 
> ---
>  block/nvme.c |  18 ++---
>  hw/block/nvme.c  |  12 ++--
>  include/block/nvme.h | 154 ++-
>  3 files changed, 152 insertions(+), 32 deletions(-)
> 
> diff --git a/block/nvme.c b/block/nvme.c
> index eb2f54dd9dc9..29e90557c428 100644
> --- a/block/nvme.c
> +++ b/block/nvme.c
> @@ -446,7 +446,7 @@ static void nvme_identify(BlockDriverState *bs, int 
> namespace, Error **errp)
>  error_setg(errp, "Cannot map buffer for DMA");
>  goto out;
>  }
> -cmd.prp1 = cpu_to_le64(iova);
> +cmd.dptr.prp1 = cpu_to_le64(iova);
>  
>  if (nvme_cmd_sync(bs, s->queues[0], )) {
>  error_setg(errp, "Failed to identify controller");
> @@ -545,7 +545,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error 
> **errp)
>  }
>  cmd = (NvmeCmd) {
>  .opcode = NVME_ADM_CMD_CREATE_CQ,
> -.prp1 = cpu_to_le64(q->cq.iova),
> +.dptr.prp1 = cpu_to_le64(q->cq.iova),
>  .cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0x)),
>  .cdw11 = cpu_to_le32(0x3),
>  };
> @@ -556,7 +556,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error 
> **errp)
>  }
>  cmd = (NvmeCmd) {
>  .opcode = NVME_ADM_CMD_CREATE_SQ,
> -.prp1 = cpu_to_le64(q->sq.iova),
> +.dptr.prp1 = cpu_to_le64(q->sq.iova),
>  .cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0x)),
>  .cdw11 = cpu_to_le32(0x1 | (n << 16)),
>  };
> @@ -904,16 +904,16 @@ try_map:
>  case 0:
>  abort();
>  case 1:
> -cmd->prp1 = pagelist[0];
> -cmd->prp2 = 0;
> +cmd->dptr.prp1 = pagelist[0];
> +cmd->dptr.prp2 = 0;
>  break;
>  case 2:
> -cmd->prp1 = pagelist[0];
> -cmd->prp2 = pagelist[1];
> +cmd->dptr.prp1 = pagelist[0];
> +cmd->dptr.prp2 = pagelist[1];
>  break;
>  default:
> -cmd->prp1 = pagelist[0];
> -cmd->prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
> +cmd->dptr.prp1 = pagelist[0];
> +cmd->dptr.prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
>  break;
>  }
>  trace_nvme_cmd_map_qiov(s, cmd, req, qiov, entries);
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 1aee042d4cb2..71b388aa0e20 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -397,8 +397,8 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, 
> NvmeCmd *cmd,
>  NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
>  uint32_t nlb  = le32_to_cpu(rw->nlb) + 1;
>  uint64_t slba = le64_to_cpu(rw->slba);
> -uint64_t prp1 = le64_to_cpu(rw->prp1);
> -uint64_t prp2 = le64_to_cpu(rw->prp2);
> +uint64_t prp1 = le64_to_cpu(rw->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(rw->dptr.prp2);
>  
>  uint8_t lba_index  = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
>  uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
> @@ -795,8 +795,8 @@ static inline uint64_t nvme_get_timestamp(const NvmeCtrl 
> *n)
>  
>  static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
>  {
> -uint64_t prp1 = le64_to_cpu(cmd->prp1);
> -uint64_t prp2 = le64_to_cpu(cmd->prp2);
> +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
>  
>  uint64_t timestamp = nvme_get_timestamp(n);
>  
> @@ -834,8 +834,8 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, 
> NvmeCmd *cmd)
>  {
>  uint16_t ret;
>  uint64_t timestamp;
> -uint64_t prp1 = le64_to_cpu(cmd->prp1);
> -uint64_t prp2 = le64_to_cpu(cmd->prp2);
> +uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
>  
>  ret = nvme_dma_write_prp(n, (uint8_t *),
>  sizeof(timestamp), prp1, prp2);
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index 1720ee1d5158..6d1fa6ff2228 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -377,15 +377,53 @@ enum NvmePmrmscMask {
>  #define NVME_PMRMSC_SET_CBA(pmrmsc, val)   \
>  (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
>  
> +enum NvmeSglDescriptorType {
> +NVME_SGL_DESCR_TYPE_DATA_BLOCK  = 0x0,
> +NVME_SGL_DESCR_TYPE_BIT_BUCKET  = 0x1,
> +NVME_SGL_DESCR_TYPE_SEGMENT = 0x2,
> +NVME_SGL_DESCR_TYPE_LAST_SEGMENT= 0x3,
> +NVME_SGL_DESCR_TYPE_KEYED_DATA_BLOCK= 0x4,
> +
> +NVME_SGL_DESCR_TYPE_VENDOR_SPECIFIC = 0xf,
> +};
> +
> +enum 

Re: [PATCH 03/17] hw/block/nvme: add support for the abort command

2020-07-02 Thread Dmitry Fomichev
Looks good,

Reviewed-by: Dmitry Fomichev 

On Mon, 2020-06-29 at 20:26 +0200, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d,
> Section 5.1 ("Abort command").
> 
> The Abort command is a best effort command; for now, the device always
> fails to abort the given command.
> 
> Signed-off-by: Klaus Jensen 
> Signed-off-by: Klaus Jensen 
> Acked-by: Keith Busch 
> Reviewed-by: Maxim Levitsky 
> ---
>  hw/block/nvme.c | 27 +++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index f5d9148f0936..b7037a7d3504 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -761,6 +761,18 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
>  }
>  }
>  
> +static uint16_t nvme_abort(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> +{
> +uint16_t sqid = le32_to_cpu(cmd->cdw10) & 0x;
> +
> +req->cqe.result = 1;
> +if (nvme_check_sqid(n, sqid)) {
> +return NVME_INVALID_FIELD | NVME_DNR;
> +}
> +
> +return NVME_SUCCESS;
> +}
> +
>  static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts)
>  {
>  trace_pci_nvme_setfeat_timestamp(ts);
> @@ -897,6 +909,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, 
> NvmeRequest *req)
>  return nvme_create_cq(n, cmd);
>  case NVME_ADM_CMD_IDENTIFY:
>  return nvme_identify(n, cmd);
> +case NVME_ADM_CMD_ABORT:
> +return nvme_abort(n, cmd, req);
>  case NVME_ADM_CMD_SET_FEATURES:
>  return nvme_set_feature(n, cmd, req);
>  case NVME_ADM_CMD_GET_FEATURES:
> @@ -1582,6 +1596,19 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  id->ieee[1] = 0x02;
>  id->ieee[2] = 0xb3;
>  id->oacs = cpu_to_le16(0);
> +
> +/*
> + * Because the controller always completes the Abort command immediately,
> + * there can never be more than one concurrently executing Abort command,
> + * so this value is never used for anything. Note that there can easily 
> be
> + * many Abort commands in the queues, but they are not considered
> + * "executing" until processed by nvme_abort.
> + *
> + * The specification recommends a value of 3 for Abort Command Limit 
> (four
> + * concurrently outstanding Abort commands), so lets use that though it 
> is
> + * inconsequential.
> + */
> +id->acl = 3;
>  id->frmw = 7 << 1;
>  id->lpa = 1 << 0;
>  id->sqes = (0x6 << 4) | 0x6;


Re: [PATCH v4 2/2] nvme: allow cmb and pmr to be enabled on same device

2020-07-02 Thread Andrzej Jakowski
On 7/2/20 10:51 AM, Klaus Jensen wrote:
> On Jul  2 08:07, Andrzej Jakowski wrote:
>> On 7/2/20 3:31 AM, Klaus Jensen wrote:
>>> Aight, an update here. This only happens when QEMU is run with a virtual
>>> IOMMU. Otherwise, the kernel is happy.
>>>
>>> With the vIOMMU, qemu also craps out a bit:
>>>
>>> qemu-system-x86_64: vtd_iova_to_slpte: detected slpte permission error 
>>> (iova=0xfd20, level=0x2, slpte=0x0, write=0)
>>> qemu-system-x86_64: vtd_iommu_translate: detected translation failure 
>>> (dev=03:00:00, iova=0xfd20)
>>>
>>> So I think we are back in QEMU land for the bug.
>>
>> Can you share command line for that?
>>
>>
> 
> qemu-system-x86_64 \
>   -nodefaults \
>   -display none \
>   -device intel-iommu,pt,intremap=on,device-iotlb=on \
>   -machine type=q35,accel=kvm,kernel_irqchip=split \
>   -cpu host \
>   -smp 4 \
>   -m 8G \
>   -nic user,model=virtio-net-pci,hostfwd=tcp::-:22 \
>   -device virtio-rng-pci \
>   -drive 
> id=boot,file=/home/kbj/work/src/vmctl/state/pmr/boot.qcow2,format=qcow2,if=virtio,discard=on,detect-zeroes=unmap
>  \
>   -device pcie-root-port,id=pcie_root_port1,chassis=1,slot=0 \
>   -device x3130-upstream,id=pcie_upstream1,bus=pcie_root_port1 \
>   -device 
> xio3130-downstream,id=pcie_downstream1,bus=pcie_upstream1,chassis=1,slot=1 \
>   -drive 
> id=nvme0n1,file=/home/kbj/work/src/vmctl/state/pmr/nvme0n1.img,format=raw,if=none,discard=on,detect-zeroes=unmap
>  \
>   -object memory-backend-file,id=pmr,share=on,mem-path=pmr.bin,size=1M \
>   -device 
> nvme,id=nvme0,serial=deadbeef,bus=pcie_downstream1,drive=nvme0n1,msix_qsize=1,pmrdev=pmr,cmb_size_mb=2
>  \
>   -pidfile /home/kbj/work/src/vmctl/run/pmr/pidfile \
>   -kernel /home/kbj/work/src/kernel/linux/arch/x86_64/boot/bzImage \
>   -append root=/dev/vda1 console=ttyS0,115200 audit=0 nokaslr \
>   -virtfs 
> local,path=/home/kbj/work/src/kernel/linux,security_model=none,readonly,mount_tag=modules
>  \
>   -serial mon:stdio \
>   -trace pci_nvme*
> 
> 

I focused on reproduction and it looks to me that my patch doesn't 
necessarily introduce regression. I run it w/ and w/o patch in both cases
getting error while registering. Here is kernel guest log:

[   87.606482] nvme nvme0: pci function :00:04.0
[   87.635577] dev=95b0a83b bar=2 size=134217728 offset=0
[   87.636593] nvme nvme0: failed to register the CMB ret=-95
[   87.643262] nvme nvme0: 12/0/0 default/read/poll queues

Any thoughts?



Re: [PATCH v9 30/34] qcow2: Add prealloc field to QCowL2Meta

2020-07-02 Thread Alberto Garcia
On Thu 02 Jul 2020 05:09:47 PM CEST, Max Reitz wrote:
>> Without a backing file, there is no read required - writing to an
>> unallocated subcluster within a preallocated cluster merely has to
>> provide zeros to the rest of the write.  And depending on whether we
>> can intelligently guarantee that the underlying protocol already
>> reads as zeroes when preallocated, we even have an optimization where
>> even that is not necessary.  We can still lump it in the "COW"
>> terminology, in that our write is more complex than merely writing in
>> place, but it isn't a true copy-on-write operation as there is
>> nothing to be copied.
>
> The term “COW” specifically in the qcow2 driver also refers to having
> to write zeroes to an area that isn’t written to by the guest as part
> of the process of having to allocate a (sub)cluster.

The question is valid: if the space for the clusters is allocated but
the subclusters are not marked as such then any partial write request
will need to fill the rest with zeroes (in practice handle_alloc_space()
can do that efficiently but that's another question).

If there is a backing file then there's no other alternative because we
do need to copy the data from the backing file.

If there is no backing file perhaps we could allocate all subclusters as
well. I suppose we can detect that scenario at that point in the code (I
haven't checked) and I don't know what would happen if one later
attaches a backing file on runtime using the command-line options.

But what I would argue is that I don't see the benefit of using extended
L2 entries on an preallocated image with no backing file: other than
having twice as much L2 metadata what would be the use? The point of
subclusters is that they make allocation more efficient, but if the
image is already fully allocated then they give you nothing.

Berto



Re: [PATCH v9 28/34] qcow2: Add subcluster support to qcow2_co_pwrite_zeroes()

2020-07-02 Thread Alberto Garcia
On Thu 02 Jul 2020 04:28:57 PM CEST, Max Reitz wrote:
>> +/* For full clusters use zero_in_l2_slice() instead */
>> +assert(nb_subclusters > 0 && nb_subclusters < 
>> s->subclusters_per_cluster);
>> +assert(sc + nb_subclusters <= s->subclusters_per_cluster);
>
> Maybe we should also assert that @offset is aligned to the subcluster
> size.

It doesn't hurt but the only caller already guarantees that already ...

>> @@ -4367,12 +4367,13 @@ static int coroutine_fn 
>> qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
>>  uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
>
> Can we instead align this to just subclusters?

I think so, good catch.

Berto



Re: [PATCH v9 21/34] qcow2: Add subcluster support to qcow2_get_host_offset()

2020-07-02 Thread Alberto Garcia
On Thu 02 Jul 2020 02:46:27 PM CEST, Max Reitz wrote:
>> -/* must be allocated */
>> -assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||
>> -   first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
>> +assert(*l2_index + nb_clusters <= s->l2_size);
>
> Not l2_slice_size?

Oh, indeed!

>> +} else if (check_offset) {
>
> My gcc (v10.1.1) appears to be a bit daft, and so doesn’t recognize
> that check_offset must always be initialized before this line is hit.

Yeah I noticed that patchew complained, I'll fix that.

Berto



Re: [PATCH v9 14/34] qcow2: Add QCow2SubclusterType and qcow2_get_subcluster_type()

2020-07-02 Thread Alberto Garcia
On Thu 02 Jul 2020 11:57:46 AM CEST, Max Reitz wrote:
>> The reason why we would want to check it is, of course, because that
>> bit does have a meaning in regular L2 entries.
>> 
>> But that bit is ignored in images with subclusters so the only reason
>> why we would check it is to report corruption, not because we need to
>> know its value.
>
> Sure.  But isn’t that the whole point of having
> QCOW2_SUBCLUSTER_INVALID in the first place?

At the moment we're only returning QCOW2_SUBCLUSTER_INVALID in cases
where there is no way to interpret the entry correctly: a) the
allocation and zero bits are set for the same subcluster, and b) the
allocation bit is set but the entry has no valid offset.

It doesn't mean that we cannot use _SUBCLUSTER_INVALID for cases like
the one we're discussing, but this one is different from the other two.

Berto



Re: nvme emulation merge process

2020-07-02 Thread Keith Busch
On Thu, Jul 02, 2020 at 01:29:26PM -0700, Andrzej Jakowski wrote:
> 
> Thx! Of course I am interested in helping and I think it is actually great 
> idea to have couple of designated maintainers/reviewers as it would be easier
> for folks to receive feedback vs requesting it in polling manner :)
> And please don't get me wrong -- I'm not complaining about anything -- I
> think it is just reality that everybody is stretched out into multiple 
> directions
> struggling to allocate time for multiple things. Having many people will
> actually increase likelihood of introducing high quality improvements.
> 
> Also, +1 on separate tree for nvme emulation.

Thanks for your help.

Klaus and I will be setting up an external tree for qemu-nvme
development (tentatively on git.infradead.org) and pull-request. I'm
just waiting for the server admin to upload our public keys. If I don't
hear back by Monday, I will use an alternate server in the interim.



Re: nvme emulation merge process

2020-07-02 Thread Andrzej Jakowski
On 7/1/20 6:57 AM, Philippe Mathieu-Daudé wrote:
> On 7/1/20 3:18 PM, Klaus Jensen wrote:
>> On Jul  1 12:34, Kevin Wolf wrote:
>>> Am 30.06.2020 um 22:36 hat Klaus Jensen geschrieben:
 On Jun 30 08:42, Keith Busch wrote:
> On Tue, Jun 30, 2020 at 04:09:46PM +0200, Philippe Mathieu-Daudé wrote:
>> What I see doable for the following days is:
>> - hw/block/nvme: Fix I/O BAR structure [3]
>> - hw/block/nvme: handle transient dma errors
>> - hw/block/nvme: bump to v1.3
>
>
> These look like sensible patches to rebase future work on, IMO. The 1.3
> updates had been prepared a while ago, at least.

 I think Philippe's "hw/block/nvme: Fix I/O BAR structure" series is a
 no-brainer. It just needs to get in asap.
>>>
>>> I think we need to talk about how nvme patches are supposed to get
>>> merged. I'm not familiar with the hardware nor the code, so the model
>>> was that I just blindly merge patches that Keith has reviewed/acked,
>>> just to spare him the work to prepare a pull request. But obviously, we
>>> started doing things this way when there was a lot less activity around
>>> the nvme emulation.
>>>
>>> If we find that this doesn't scale any more, maybe we need to change
>>> something.
>>
>> Honestly, I do not think the current model has worked very well for some
>> time; especially for larger series where I, for one, has felt that my
>> work was largely ignored due to a lack of designated reviewers. Things
>> only picked up when Beata, Maxim and Philippe started reviewing my
>> series - maybe out of pity or because I was bombing the list, I don't
>> know ;)
> 
> I have no interest in the NVMe device emulation, but one of the first
> thing I notice when I look at the wiki the time I wanted to send my
> first patch, is the "Return the favor" paragraph:
> https://wiki.qemu.org/Contribute/SubmitAPatch#Return_the_favor
> 
>  "Peer review only works if everyone chips in a bit of review time.
>   If everyone submitted more patches than they reviewed, we would
>   have a patch backlog. A good goal is to try to review at least as
>   many patches from others as what you submit. Don't worry if you
>   don't know the code base as well as a maintainer; it's perfectly
>   fine to admit when your review is weak because you are unfamiliar
>   with the code."
> 
> So as some reviewed my patches, I try to return the favor to the
> community, in particular when I see someone is stuck waiting for
> review, and the patch topic is some area I can understand.
> 
> I don't see that as an "out of pity" reaction.
> 
> Note, it is true bomb series scares reviewers. You learned it the
> bad way. But you can see, after resending the first part of your
> "bomb", even if it took 10 versions, the result is a great
> improvement!
> 
>> We've also seen good patches from Andrzej linger on the list for quite a
>> while, prompting a number of RESENDs. I only recently allocated more
>> time and upped my review game, but I hope that contributors feel that
>> stuff gets reviewed in a timely fashion by now.
>>
>> Please understand that this is in NO WAY a criticism of Keith who
>> already made it very clear to me that he did not have a lot time to
>> review, but only ack the odd patch.
>>
>>> Depending on how much time Keith can spend on review in the
>>> near future and how much control he wants to keep over the development,
>>> I could imagine adding Klaus to MAINTAINERS, either as a co-maintainer
>>> or as a reviewer. Then I could rely on reviews/acks from either of you
>>> for merging series.
>>>
>>
>> I would be happy to step up (officially) to help maintain the device
>> with Keith and review on a daily basis, and my position can support
>> this.
> 
> Sounds good to me, but it is up to Keith Busch to accept.
> 
> It would be nice to have at least one developer from WDC listed as
> designated reviewer too.
> 
> Maxim is candidate for designated reviewer but I think he doesn't
> have the time.
> 
> It would also nice to have Andrzej Jakowski listed, if he is interested.

Thx! Of course I am interested in helping and I think it is actually great 
idea to have couple of designated maintainers/reviewers as it would be easier
for folks to receive feedback vs requesting it in polling manner :)
And please don't get me wrong -- I'm not complaining about anything -- I
think it is just reality that everybody is stretched out into multiple 
directions
struggling to allocate time for multiple things. Having many people will
actually increase likelihood of introducing high quality improvements.

Also, +1 on separate tree for nvme emulation.

> 
>>
>>> Of course, the patches don't necessarily have to go through my tree
>>> either if this only serves to complicate things these days. If sending
>>> separate pull requests directly to Peter would make things easier, I
>>> certainly wouldn't object.
>>>
>>
>> I don't think there is any reason to by-pass your tree. I think the
>> volume would need to 

Re: [PATCH v2 11/44] qemu-option: Replace opt_set() by cleaner opt_validate()

2020-07-02 Thread Vladimir Sementsov-Ogievskiy

02.07.2020 18:49, Markus Armbruster wrote:

opt_set() frees its argument @value on failure.  Slightly unclean;
functions ideally do nothing on failure.

To tidy this up, move opt_create() from opt_set() into its callers,
along with the cleanup.  Rename opt_set() to opt_validate(), noting
its similarity to qemu_opts_validate().  Drop redundant parameter
@opts; use opt->opts instead.

Signed-off-by: Markus Armbruster
Reviewed-by: Eric Blake


Reviewed-by: Vladimir Sementsov-Ogievskiy 

--
Best regards,
Vladimir



Re: [PATCH 1/6] migration: improve error reporting of block driver state name

2020-07-02 Thread Dr. David Alan Gilbert
* Eric Blake (ebl...@redhat.com) wrote:
> On 7/2/20 12:57 PM, Daniel P. Berrangé wrote:
> > With blockdev, a BlockDriverState may not have an device name,
> 
> s/an/a/
> 
> > so using a node name is required as an alternative.
> > 
> > Signed-off-by: Daniel P. Berrangé 
> > ---
> >   migration/savevm.c | 12 ++--
> >   1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> 
> Reviewed-by: Eric Blake 

Why don't you send this one to trivial.

Dave

> 
> -- 
> Eric Blake, Principal Software Engineer
> Red Hat, Inc.   +1-919-301-3226
> Virtualization:  qemu.org | libvirt.org
--
Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK




Re: [PATCH 0/6] migration: bring savevm/loadvm/delvm over to QMP

2020-07-02 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20200702175754.2211821-1-berra...@redhat.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing 
commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===

 (qemu) info snapshots
 No available block device supports snapshots
 (qemu) loadvm snap0
-Error: No block device supports snapshots
+Error: No block device can accept snapshots
 (qemu) quit
 
 
---
 Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
-Error: Device '' is writable but does not support snapshots
+Error: Device 'file' is writable but does not support snapshots
 (qemu) info snapshots
 No available block device supports snapshots
 (qemu) loadvm snap0
-Error: Device '' is writable but does not support snapshots
+Error: Device 'file' is writable but does not support snapshots
 (qemu) quit
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
---
Not run: 259
Failures: 267
Failed 1 of 119 iotests
make: *** [check-tests/check-block.sh] Error 1
make: *** Waiting for unfinished jobs
  TESTcheck-qtest-aarch64: tests/qtest/test-hmp
  TESTcheck-qtest-aarch64: tests/qtest/qos-test
---
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', 
'--label', 'com.qemu.instance.uuid=80ecabfdc3b44cdabd915b427d791afe', '-u', 
'1003', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', 
'-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 
'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', 
'/home/patchew2/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', 
'/var/tmp/patchew-tester-tmp-vlubojb7/src/docker-src.2020-07-02-14.52.56.31106:/var/tmp/qemu:z,ro',
 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit 
status 2.
filter=--filter=label=com.qemu.instance.uuid=80ecabfdc3b44cdabd915b427d791afe
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-vlubojb7/src'
make: *** [docker-run-test-quick@centos7] Error 2

real14m49.668s
user0m8.931s


The full log is available at
http://patchew.org/logs/20200702175754.2211821-1-berra...@redhat.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

Re: [PATCH v2 03/44] qdev: Use returned bool to check for qdev_realize() etc. failure

2020-07-02 Thread Vladimir Sementsov-Ogievskiy

02.07.2020 18:49, Markus Armbruster wrote:

Convert

 foo(..., );
 if (err) {
 ...
 }

to

 if (!foo(..., )) {
 ...
 }

for qdev_realize(), qdev_realize_and_unref(), qbus_realize() and their
wrappers isa_realize_and_unref(), pci_realize_and_unref(),
sysbus_realize(), sysbus_realize_and_unref(), usb_realize_and_unref().
Coccinelle script:

 @@
 identifier fun = {isa_realize_and_unref, pci_realize_and_unref, 
qbus_realize, qdev_realize, qdev_realize_and_unref, sysbus_realize, 
sysbus_realize_and_unref, usb_realize_and_unref};
 expression list args, args2;
 typedef Error;
 Error *err;
 @@
 -fun(args, , args2);
 -if (err)
 +if (!fun(args, , args2))
  {
  ...
  }

Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information".  Nothing to convert there; skipped.

Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Converted manually.

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster



Sorry me, reviewing this patch with help of script:
#!/usr/bin/env python3

import sys
import re

with open(sys.argv[1]) as f:
patch = f.read()

regex = re.compile(r'^- *(?P(?P\w+)\(.*, &(?P\w+)\));\n'
   r'^- *if \((?P=err)( != NULL)?\) \{\n'
   r'^\+ *if \(!(?P=func_call)\) \{$', flags=re.MULTILINE)

for chunk in re.split('^@', patch, flags=re.MULTILINE):
filtered = regex.sub('OK', chunk)

if re.search('^[+-][^+-]', filtered, flags=re.MULTILINE):
print(re.sub('^', '   ', '@' + chunk, flags=re.MULTILINE))


funcs = set()

for m in regex.finditer(patch):
funcs.add(m.group('func'))

print()
for func in funcs:
print(func)



output:

   @@ -34,9 +34,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy 
*vpci_dev, Error **errp)
Error *local_error = NULL;

virtio_pci_force_virtio_1(vpci_dev);

   -qdev_realize(vdev, BUS(_dev->bus), _error);
   -
   -if (local_error) {
   +if (!qdev_realize(vdev, BUS(_dev->bus), _error)) {
error_propagate(errp, local_error);
return;
}
   diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
   index 67f409e106..0fc00fee1f 100644
   --- a/hw/display/virtio-vga.c
   +++ b/hw/display/virtio-vga.c
   
   @@ -444,15 +444,13 @@ static void realize_event_facility(DeviceState *dev, Error **errp)

SCLPEventFacility *event_facility = EVENT_FACILITY(dev);
Error *local_err = NULL;

   -qdev_realize(DEVICE(_facility->quiesce),

   - BUS(_facility->sbus), _err);
   -if (local_err) {
   +if (!qdev_realize(DEVICE(_facility->quiesce),
   +  BUS(_facility->sbus), _err)) {
error_propagate(errp, local_err);
return;
}
   -qdev_realize(DEVICE(_facility->cpu_hotplug),
   - BUS(_facility->sbus), _err);
   -if (local_err) {
   +if (!qdev_realize(DEVICE(_facility->cpu_hotplug),
   +  BUS(_facility->sbus), _err)) {
error_propagate(errp, local_err);
qdev_unrealize(DEVICE(_facility->quiesce));
return;
   diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
   index 142e52a8ff..0517901024 100644
   --- a/hw/s390x/s390-pci-bus.c
   +++ b/hw/s390x/s390-pci-bus.c
   


usb_realize_and_unref
sysbus_realize
sysbus_realize_and_unref
qdev_realize
qdev_realize_and_unref

===

So, the remaning non-matching seems correct, and all found functions seems to 
have corresponding semantics:

Reviewed-by: Vladimir Sementsov-Ogievskiy 

--
Best regards,
Vladimir



Re: [PATCH 0/6] migration: bring savevm/loadvm/delvm over to QMP

2020-07-02 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20200702175754.2211821-1-berra...@redhat.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing 
commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===

 (qemu) info snapshots
 No available block device supports snapshots
 (qemu) loadvm snap0
-Error: No block device supports snapshots
+Error: No block device can accept snapshots
 (qemu) quit
 
 
---
 Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
-Error: Device '' is writable but does not support snapshots
+Error: Device 'file' is writable but does not support snapshots
 (qemu) info snapshots
 No available block device supports snapshots
 (qemu) loadvm snap0
-Error: Device '' is writable but does not support snapshots
+Error: Device 'file' is writable but does not support snapshots
 (qemu) quit
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
---
Not run: 259
Failures: 267
Failed 1 of 119 iotests
make: *** [check-tests/check-block.sh] Error 1
make: *** Waiting for unfinished jobs
  TESTcheck-qtest-aarch64: tests/qtest/qos-test
Traceback (most recent call last):
---
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', 
'--label', 'com.qemu.instance.uuid=d415a115078246e4ab99c8a4d27787e7', '-u', 
'1001', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', 
'-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 
'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', 
'/home/patchew/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', 
'/var/tmp/patchew-tester-tmp-vi4bosi3/src/docker-src.2020-07-02-14.36.29.6528:/var/tmp/qemu:z,ro',
 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit 
status 2.
filter=--filter=label=com.qemu.instance.uuid=d415a115078246e4ab99c8a4d27787e7
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-vi4bosi3/src'
make: *** [docker-run-test-quick@centos7] Error 2

real16m29.279s
user0m8.998s


The full log is available at
http://patchew.org/logs/20200702175754.2211821-1-berra...@redhat.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

Re: [PATCH 1/6] migration: improve error reporting of block driver state name

2020-07-02 Thread Eric Blake

On 7/2/20 12:57 PM, Daniel P. Berrangé wrote:

With blockdev, a BlockDriverState may not have an device name,


s/an/a/


so using a node name is required as an alternative.

Signed-off-by: Daniel P. Berrangé 
---
  migration/savevm.c | 12 ++--
  1 file changed, 6 insertions(+), 6 deletions(-)



Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH 2/6] migration: introduce savevm, loadvm, delvm QMP commands

2020-07-02 Thread Daniel P . Berrangé
On Thu, Jul 02, 2020 at 01:12:52PM -0500, Eric Blake wrote:
> On 7/2/20 12:57 PM, Daniel P. Berrangé wrote:
> > savevm, loadvm and delvm are some of the few commands that have never
> > been converted to use QMP. The primary reason for this lack of
> > conversion is that they block execution of the thread for as long as
> > they run.
> > 
> > Despite this downside, however, libvirt and applications using libvirt
> > has used these commands for as long as QMP has existed, via the
> > "human-monitor-command" passthrough command. IOW, while it is clearly
> > desirable to be able to fix the blocking problem, this is not an
> > immediate obstacle to real world usage.
> > 
> > Meanwhile there is a need for other features which involve adding new
> > parameters to the commands. This is possible with HMP passthrough, but
> > it provides no reliable way for apps to introspect features, so using
> > QAPI modelling is highly desirable.
> > 
> > This patch thus introduces trival savevm, loadvm, delvm commands
> 
> trivial
> 
> > to QMP that are functionally identical to the HMP counterpart, including
> > the blocking problem.
> 
> Should we name them 'x-savevm', 'x-loadvm', 'x-delvm' to give ourselves room
> to change them when we DO solve the blocking issue?  Or will the solution of
> the blocking issue introduce new QMP commands, at which point we can add QMP
> deprecation markers on these commands to eventually retire them?

I was in two minds about this, so I'm open to arguments either way.

The primary goal is for libvirt to consume the APIs as soon as possible,
and generally libvirt doesn't want todo this is they are declared experimental
via a "x-" prefix. So that pushes me away from "x-".

If we don't have an "x-" prefix and want to make changes, we can add extra
parameters to trigger new behaviour in backwards compatible manner. Or we can
simply deprecate these commands, deleting them 2 releases later, while adding
completely new commands.

If we think the prposed design will definitely need incompatible changes in
a very short time frame though, that would push towards "x-".

So IMHO the right answer largely depends on whether there is a credible
strategy to implement the ideal non-blocking solution in a reasonable amount
of time. I can't justify spending much time on this myself, but I'm willing
to consider & try proposals for solving the blocking problem if they're not
too complex / invasive.

I just don't want to end up having a "x-savevm" command for another 10 years,
waiting for a perfect solution that never arrives because people always have
higher priority items, as apps are clearly able to accept the blocking problem
if the alternative is no snapshots at all.


> > +
> > +##
> > +# @savevm:
> > +#
> > +# Save a VM snapshot
> > +#
> > +# @tag: name of the snapshot to create. If it already
> > +# exists it will be replaced.
> > +#
> > +# Note that execution of the VM will be paused during the time
> > +# it takes to save the snapshot
> > +#
> > +# Returns: nothing
> > +#
> > +# Example:
> > +#
> > +# -> { "execute": "savevm",
> > +#  "data": {
> > +# "tag": "my-snap"
> > +#  }
> > +#}
> > +# <- { "return": { } }
> > +#
> > +# Since: 5.2
> 
> I guess you are NOT trying to make 5.1 soft freeze next week?

Correct. It is unrealistic to consider this for soft freeze.

I'd really love to have a solution in 5.2 though, even if it doesn't
solve all our problems. Something that can at least unblock apps that
want to use OVMF with internal snapshots today.

Regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [PATCH v2 37/44] error: Reduce unnecessary error propagation

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away, even when we need to keep error_propagate() for other
error paths.

Signed-off-by: Markus Armbruster 
---



+++ b/block/replication.c
@@ -85,7 +85,6 @@ static int replication_open(BlockDriverState *bs, QDict 
*options,
  {
  int ret;
  BDRVReplicationState *s = bs->opaque;
-Error *local_err = NULL;
  QemuOpts *opts = NULL;
  const char *mode;
  const char *top_id;
@@ -99,7 +98,7 @@ static int replication_open(BlockDriverState *bs, QDict 
*options,
  
  ret = -EINVAL;

  opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
  goto fail;
  }


Does this one belong in 36/44, given that removal of 'local_err' is 
evidence that no other error path needed it?


Either way, it belongs in the series, and the result of the two patches 
together is fine.


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 36/44] error: Eliminate error_propagate() manually

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away.  The previous two commits did that for sufficiently simple
cases with Coccinelle.  Do it for several more manually.

Signed-off-by: Markus Armbruster 
---



+++ b/qdev-monitor.c
@@ -597,7 +597,6 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
  const char *driver, *path;
  DeviceState *dev = NULL;
  BusState *bus = NULL;
-Error *err = NULL;
  bool hide;
  
  driver = qemu_opt_get(opts, "driver");

@@ -652,15 +651,14 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
  dev = qdev_new(driver);
  
  /* Check whether the hotplug is allowed by the machine */

-if (qdev_hotplug && !qdev_hotplug_allowed(dev, )) {
+if (qdev_hotplug && !qdev_hotplug_allowed(dev, errp)) {
  /* Error must be set in the machine hook */
-assert(err);


That comment could be deleted now.

Either way,
Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH 6/6] migration: support picking vmstate disk in QMP snapshot commands

2020-07-02 Thread Eric Blake

On 7/2/20 12:57 PM, Daniel P. Berrangé wrote:

This wires up support for a new "vmstate" parameter to the QMP commands
for snapshots (savevm, loadvm). This parameter accepts block driver
state node name.

One use case for this would be a VM using OVMF firmware where the
variables store is the first snapshottable disk image. The vmstate
snapshot usually wants to be stored in the primary root disk of the
VM, not the firmeware varstore. Thus there needs to be a mechanism


firmware


to override the default choice of disk.

Signed-off-by: Daniel P. Berrangé 
---



+++ b/qapi/migration.json
@@ -1630,6 +1630,7 @@
  # @tag: name of the snapshot to create. If it already
  # exists it will be replaced.
  # @exclude: list of block device node names to exclude
+# @vmstate: block device node name to save vmstate to
  #
  # Note that execution of the VM will be paused during the time
  # it takes to save the snapshot
@@ -1641,6 +1642,7 @@
  # -> { "execute": "savevm",
  #  "data": {
  # "tag": "my-snap",
+# "vmstate": "disk0",
  # "exclude": ["pflash0-vars"]
  #  }
  #}
@@ -1650,6 +1652,7 @@
  ##
  { 'command': 'savevm',
'data': { 'tag': 'str',
+'*vmstate': 'str',
  '*exclude': ['str'] } }


During save, the list of block devices is obvious: everything that is 
not excluded.  But,


  
  ##

@@ -1659,6 +1662,7 @@
  #
  # @tag: name of the snapshot to load.
  # @exclude: list of block device node names to exclude
+# @vmstate: block device node name to load vmstate from
  #
  # Returns: nothing
  #
@@ -1667,6 +1671,7 @@
  # -> { "execute": "loadvm",
  #  "data": {
  # "tag": "my-snap",
+# "vmstate": "disk0",
  # "exclude": ["pflash0-vars"]
  #  }
  #}
@@ -1676,6 +1681,7 @@
  ##
  { 'command': 'loadvm',
'data': { 'tag': 'str',
+'*vmstate': 'str',
  '*exclude': ['str'] } }


...now that we support exclusion during saving, or even without 
exclusion but when the user has performed hotplug/unplug operations in 
the meantime from when the snapshot was created, isn't load better off 
listing all devices which SHOULD be restored, rather than excluding 
devices that should NOT be restored?  (After all, libvirt knows which 
disks existed at the time of the snapshot, which may be different than 
the set of disks that exist now even though we are throwing out the 
state now to go back to the state at the time of the snapshot)


Then there's the question of symmetry: if load needs an explicit list of 
blocks to load from (rather than the set of blocks that are currently 
associated with the machine), should save also take its list by positive 
inclusion rather than negative exclusion?


And why does delvm not need to specify which block is the vmstate? 
delvm is in the same boat as loadvm - the set of blocks involved at the 
time of the snapshot creation may be different than the set of blocks 
currently associated with the guest at the time you run load/delvm.


--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH 2/6] migration: introduce savevm, loadvm, delvm QMP commands

2020-07-02 Thread Eric Blake

On 7/2/20 12:57 PM, Daniel P. Berrangé wrote:

savevm, loadvm and delvm are some of the few commands that have never
been converted to use QMP. The primary reason for this lack of
conversion is that they block execution of the thread for as long as
they run.

Despite this downside, however, libvirt and applications using libvirt
has used these commands for as long as QMP has existed, via the
"human-monitor-command" passthrough command. IOW, while it is clearly
desirable to be able to fix the blocking problem, this is not an
immediate obstacle to real world usage.

Meanwhile there is a need for other features which involve adding new
parameters to the commands. This is possible with HMP passthrough, but
it provides no reliable way for apps to introspect features, so using
QAPI modelling is highly desirable.

This patch thus introduces trival savevm, loadvm, delvm commands


trivial


to QMP that are functionally identical to the HMP counterpart, including
the blocking problem.


Should we name them 'x-savevm', 'x-loadvm', 'x-delvm' to give ourselves 
room to change them when we DO solve the blocking issue?  Or will the 
solution of the blocking issue introduce new QMP commands, at which 
point we can add QMP deprecation markers on these commands to eventually 
retire them?




Signed-off-by: Daniel P. Berrangé 
---



+++ b/qapi/migration.json
@@ -1621,3 +1621,79 @@
  ##
  { 'event': 'UNPLUG_PRIMARY',
'data': { 'device-id': 'str' } }
+
+##
+# @savevm:
+#
+# Save a VM snapshot
+#
+# @tag: name of the snapshot to create. If it already
+# exists it will be replaced.
+#
+# Note that execution of the VM will be paused during the time
+# it takes to save the snapshot
+#
+# Returns: nothing
+#
+# Example:
+#
+# -> { "execute": "savevm",
+#  "data": {
+# "tag": "my-snap"
+#  }
+#}
+# <- { "return": { } }
+#
+# Since: 5.2


I guess you are NOT trying to make 5.1 soft freeze next week?


--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 35/44] error: Eliminate error_propagate() with Coccinelle, part 2

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away.  The previous commit did that with a Coccinelle script I
consider fairly trustworthy.  This commit uses the same script with
the matching of return taken out, i.e. we convert

 if (!foo(..., )) {
...
error_propagate(errp, err);
...
 }

to

 if (!foo(..., errp)) {
...
...
 }

This is unsound: @err could still be read between afterwards.  I don't
know how to express "no read of @err without an intervening write" in
Coccinelle.  Instead, I manually double-checked for uses of @err.

Suboptimal line breaks tweaked manually.  qdev_realize() simplified
further to placate scripts/checkpatch.pl.

Signed-off-by: Markus Armbruster 
---
  block.c  |  6 ++
  block/blkdebug.c |  7 ++-
  block/blklogwrites.c |  3 +--
  block/blkverify.c|  3 +--
  block/crypto.c   |  4 +---
  block/file-posix.c   |  6 ++
  block/file-win32.c   |  6 ++
  block/gluster.c  |  4 +---
  block/iscsi.c|  3 +--
  block/nbd.c  |  8 ++--
  block/qcow2.c| 13 -
  block/raw-format.c   |  4 +---
  block/sheepdog.c |  8 ++--
  block/ssh.c  |  4 +---
  block/throttle.c |  4 +---
  block/vmdk.c |  4 +---
  block/vpc.c  |  3 +--
  block/vvfat.c|  3 +--
  blockdev.c   |  3 +--
  hw/intc/xics.c   |  4 +---
  hw/vfio/pci.c|  3 +--
  net/tap.c|  3 +--
  qom/object.c |  4 +---
  23 files changed, 32 insertions(+), 78 deletions(-)


Small enough to review each instance.

Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




[PATCH 4/6] block: allow specifying name of block device for vmstate storage

2020-07-02 Thread Daniel P . Berrangé
Currently the vmstate will be stored in the first block device that
supports snapshots. Historically this would have usually been the
root device, but with UEFI it might be the variable store. There
needs to be a way to override the choice of block device to store
the state in.

Signed-off-by: Daniel P. Berrangé 
---
 block/monitor/block-hmp-cmds.c |  2 +-
 block/snapshot.c   | 33 +
 include/block/snapshot.h   |  4 +++-
 migration/savevm.c |  6 ++
 4 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 0ee6e7a4be..a698fac027 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -899,7 +899,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
 ImageEntry *image_entry, *next_ie;
 SnapshotEntry *snapshot_entry;
 
-bs = bdrv_all_find_vmstate_bs(NULL);
+bs = bdrv_all_find_vmstate_bs(NULL, NULL, NULL);
 if (!bs) {
 monitor_printf(mon, "No available block device supports snapshots\n");
 return;
diff --git a/block/snapshot.c b/block/snapshot.c
index c8950b0b86..4774a1890d 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -552,7 +552,9 @@ fail:
 return err;
 }
 
-BlockDriverState *bdrv_all_find_vmstate_bs(strList *exclude_bs)
+BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
+   strList *exclude_bs,
+   Error **errp)
 {
 BlockDriverState *bs;
 BdrvNextIterator it;
@@ -560,16 +562,39 @@ BlockDriverState *bdrv_all_find_vmstate_bs(strList 
*exclude_bs)
 for (bs = bdrv_first(); bs; bs = bdrv_next()) {
 AioContext *ctx = bdrv_get_aio_context(bs);
 bool found;
+Error *err = NULL;
 
 aio_context_acquire(ctx);
-found = bdrv_all_snapshots_includes_bs(bs, exclude_bs) &&
-bdrv_can_snapshot(bs);
+if (vmstate_bs == NULL) {
+found = bdrv_all_snapshots_includes_bs(bs, exclude_bs) &&
+bdrv_can_snapshot(bs);
+} else {
+if (g_str_equal(vmstate_bs, bdrv_get_node_name(bs))) {
+found = bdrv_all_snapshots_includes_bs(bs, exclude_bs) &&
+bdrv_can_snapshot(bs);
+if (!found) {
+error_setg(,
+   "block device '%s' cannot accept snapshots",
+   vmstate_bs);
+}
+} else {
+found = false;
+}
+}
 aio_context_release(ctx);
 
-if (found) {
+if (found || err) {
 bdrv_next_cleanup();
+if (err) {
+error_propagate(errp, err);
+return NULL;
+}
 break;
 }
 }
+
+if (!bs) {
+error_setg(errp, "No block device can accept snapshots");
+}
 return bs;
 }
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
index f20986ca37..ff627df5cb 100644
--- a/include/block/snapshot.h
+++ b/include/block/snapshot.h
@@ -90,6 +90,8 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
  strList *exclude_bs,
  BlockDriverState **first_bad_bs);
 
-BlockDriverState *bdrv_all_find_vmstate_bs(strList *exclude_bs);
+BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
+   strList *exclude_bs,
+   Error **errp);
 
 #endif
diff --git a/migration/savevm.c b/migration/savevm.c
index 4251aa0dde..b11c6a882d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2662,9 +2662,8 @@ int save_snapshot(const char *name, Error **errp)
 }
 }
 
-bs = bdrv_all_find_vmstate_bs(NULL);
+bs = bdrv_all_find_vmstate_bs(NULL, NULL, errp);
 if (bs == NULL) {
-error_setg(errp, "No block device can accept snapshots");
 return ret;
 }
 aio_context = bdrv_get_aio_context(bs);
@@ -2857,9 +2856,8 @@ int load_snapshot(const char *name, Error **errp)
 return ret;
 }
 
-bs_vm_state = bdrv_all_find_vmstate_bs(NULL);
+bs_vm_state = bdrv_all_find_vmstate_bs(NULL, NULL, errp);
 if (!bs_vm_state) {
-error_setg(errp, "No block device supports snapshots");
 return -ENOTSUP;
 }
 aio_context = bdrv_get_aio_context(bs_vm_state);
-- 
2.26.2




[PATCH 3/6] block: add ability to filter out blockdevs during snapshot

2020-07-02 Thread Daniel P . Berrangé
When executing snapshot logic, currently blockdevs are filtered out if
they are read-only or if there is no media present. In order to support
snapshotting when UEFI firmware is in use, we need the ability to filter
out the blockdev used for the firmware vars store. This can be achieved
by having a list of node names that should be excluded from
consideration for snapshots.

Signed-off-by: Daniel P. Berrangé 
---
 block/monitor/block-hmp-cmds.c |  4 ++--
 block/snapshot.c   | 41 ++
 include/block/snapshot.h   | 19 +---
 migration/savevm.c | 18 +++
 4 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 4c8c375172..0ee6e7a4be 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -899,7 +899,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
 ImageEntry *image_entry, *next_ie;
 SnapshotEntry *snapshot_entry;
 
-bs = bdrv_all_find_vmstate_bs();
+bs = bdrv_all_find_vmstate_bs(NULL);
 if (!bs) {
 monitor_printf(mon, "No available block device supports snapshots\n");
 return;
@@ -951,7 +951,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
 total = 0;
 for (i = 0; i < nb_sns; i++) {
 SnapshotEntry *next_sn;
-if (bdrv_all_find_snapshot(sn_tab[i].name, ) == 0) {
+if (bdrv_all_find_snapshot(sn_tab[i].name, NULL, ) == 0) {
 global_snapshots[total] = i;
 total++;
 QTAILQ_FOREACH(image_entry, _list, next) {
diff --git a/block/snapshot.c b/block/snapshot.c
index bd9fb01817..c8950b0b86 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -385,12 +385,22 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState 
*bs,
 return ret;
 }
 
-static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
+static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs,
+   strList *exclude_bs)
 {
+const char *node_name = bdrv_get_node_name(bs);
+
 if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
 return false;
 }
 
+while (exclude_bs) {
+if (g_str_equal(node_name, exclude_bs->value)) {
+return false;
+}
+exclude_bs = exclude_bs->next;
+}
+
 /* Include all nodes that are either in use by a BlockBackend, or that
  * aren't attached to any node, but owned by the monitor. */
 return bdrv_has_blk(bs) || QLIST_EMPTY(>parents);
@@ -400,7 +410,7 @@ static bool bdrv_all_snapshots_includes_bs(BlockDriverState 
*bs)
  * These functions will properly handle dataplane (take aio_context_acquire
  * when appropriate for appropriate block drivers) */
 
-bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
+bool bdrv_all_can_snapshot(strList *exclude_bs, BlockDriverState 
**first_bad_bs)
 {
 bool ok = true;
 BlockDriverState *bs;
@@ -410,7 +420,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
 AioContext *ctx = bdrv_get_aio_context(bs);
 
 aio_context_acquire(ctx);
-if (bdrv_all_snapshots_includes_bs(bs)) {
+if (bdrv_all_snapshots_includes_bs(bs, exclude_bs)) {
 ok = bdrv_can_snapshot(bs);
 }
 aio_context_release(ctx);
@@ -425,8 +435,8 @@ fail:
 return ok;
 }
 
-int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
- Error **errp)
+int bdrv_all_delete_snapshot(const char *name, strList *exclude_bs,
+ BlockDriverState **first_bad_bs, Error **errp)
 {
 int ret = 0;
 BlockDriverState *bs;
@@ -437,7 +447,7 @@ int bdrv_all_delete_snapshot(const char *name, 
BlockDriverState **first_bad_bs,
 AioContext *ctx = bdrv_get_aio_context(bs);
 
 aio_context_acquire(ctx);
-if (bdrv_all_snapshots_includes_bs(bs) &&
+if (bdrv_all_snapshots_includes_bs(bs, exclude_bs) &&
 bdrv_snapshot_find(bs, snapshot, name) >= 0)
 {
 ret = bdrv_snapshot_delete(bs, snapshot->id_str,
@@ -456,8 +466,8 @@ fail:
 }
 
 
-int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs,
-   Error **errp)
+int bdrv_all_goto_snapshot(const char *name, strList *exclude_bs,
+   BlockDriverState **first_bad_bs, Error **errp)
 {
 int ret = 0;
 BlockDriverState *bs;
@@ -467,7 +477,7 @@ int bdrv_all_goto_snapshot(const char *name, 
BlockDriverState **first_bad_bs,
 AioContext *ctx = bdrv_get_aio_context(bs);
 
 aio_context_acquire(ctx);
-if (bdrv_all_snapshots_includes_bs(bs)) {
+if (bdrv_all_snapshots_includes_bs(bs, exclude_bs)) {
 ret = bdrv_snapshot_goto(bs, name, errp);
 }
 aio_context_release(ctx);
@@ -482,7 +492,8 @@ fail:
 return ret;
 }
 
-int 

Re: [PATCH v2 34/44] error: Eliminate error_propagate() with Coccinelle, part 1

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away.  Convert

 if (!foo(..., )) {
 ...
 error_propagate(errp, err);
 ...
 return ...
 }

to

 if (!foo(..., errp)) {
 ...
 ...
 return ...
 }





Not exactly elegant, I'm afraid.


True, but it is still reasonable enough to use.



The "when != goto lbl;" is necessary to avoid transforming


spelled "when != lbl:" above in rule1 and rule2



  if (fun(args, )) {
  goto out
  }
  ...
  out:
  error_propagate(errp, err);

even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().

Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly.  I don't know what exactly "when strict" does, only that
it helps here.

The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err".  For
an example where it's too narrow, see vfio_intx_enable().

Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there.  Converted manually.

Line breaks tidied up manually.  One nested declaration of @local_err
deleted manually.  Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.

Signed-off-by: Markus Armbruster 
---



  114 files changed, 376 insertions(+), 884 deletions(-)


Big, but sane.  Picks up the spots I noticed in 33/44, and then some ;)

Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




[PATCH 5/6] migration: support excluding block devs in QMP snapshot commands

2020-07-02 Thread Daniel P . Berrangé
This wires up support for a new "exclude" parameter to the QMP commands
for snapshots (savevm, loadvm, delvm). This parameter accepts a list of
block driver state node names.

One use case for this would be a VM using OVMF firmware where the
variables store is a raw disk image. Ideally the variable store would be
qcow2, allowing its contents to be included in the snapshot, but
typically today the variable store is raw. It is still useful to be able
to snapshot VMs using OVMF, even if the varstore is excluded, as the
main OS disk content is usually the stuff the user cares about.

Signed-off-by: Daniel P. Berrangé 
---
 include/migration/snapshot.h |  6 --
 migration/savevm.c   | 38 +---
 monitor/hmp-cmds.c   |  6 +++---
 qapi/migration.json  | 21 ++--
 replay/replay-snapshot.c |  4 ++--
 softmmu/vl.c |  2 +-
 6 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/include/migration/snapshot.h b/include/migration/snapshot.h
index c85b6ec75b..dffb84dbe5 100644
--- a/include/migration/snapshot.h
+++ b/include/migration/snapshot.h
@@ -15,7 +15,9 @@
 #ifndef QEMU_MIGRATION_SNAPSHOT_H
 #define QEMU_MIGRATION_SNAPSHOT_H
 
-int save_snapshot(const char *name, Error **errp);
-int load_snapshot(const char *name, Error **errp);
+#include "qapi/qapi-builtin-types.h"
+
+int save_snapshot(const char *name, strList *exclude, Error **errp);
+int load_snapshot(const char *name, strList *exclude, Error **errp);
 
 #endif
diff --git a/migration/savevm.c b/migration/savevm.c
index b11c6a882d..4b040676f7 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2624,7 +2624,7 @@ int qemu_load_device_state(QEMUFile *f)
 return 0;
 }
 
-int save_snapshot(const char *name, Error **errp)
+int save_snapshot(const char *name, strList *exclude, Error **errp)
 {
 BlockDriverState *bs, *bs1;
 QEMUSnapshotInfo sn1, *sn = , old_sn1, *old_sn = _sn1;
@@ -2646,7 +2646,7 @@ int save_snapshot(const char *name, Error **errp)
 return ret;
 }
 
-if (!bdrv_all_can_snapshot(NULL, )) {
+if (!bdrv_all_can_snapshot(exclude, )) {
 error_setg(errp, "Device '%s' is writable but does not support "
"snapshots", bdrv_get_device_or_node_name(bs));
 return ret;
@@ -2654,7 +2654,7 @@ int save_snapshot(const char *name, Error **errp)
 
 /* Delete old snapshots of the same name */
 if (name) {
-ret = bdrv_all_delete_snapshot(name, NULL, , errp);
+ret = bdrv_all_delete_snapshot(name, exclude, , errp);
 if (ret < 0) {
 error_prepend(errp, "Error while deleting snapshot on device "
   "'%s': ", bdrv_get_device_or_node_name(bs1));
@@ -2662,7 +2662,7 @@ int save_snapshot(const char *name, Error **errp)
 }
 }
 
-bs = bdrv_all_find_vmstate_bs(NULL, NULL, errp);
+bs = bdrv_all_find_vmstate_bs(NULL, exclude, errp);
 if (bs == NULL) {
 return ret;
 }
@@ -2724,7 +2724,7 @@ int save_snapshot(const char *name, Error **errp)
 aio_context_release(aio_context);
 aio_context = NULL;
 
-ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, NULL, );
+ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, exclude, );
 if (ret < 0) {
 error_setg(errp, "Error while creating snapshot on '%s'",
bdrv_get_device_or_node_name(bs));
@@ -2827,7 +2827,7 @@ void qmp_xen_load_devices_state(const char *filename, 
Error **errp)
 migration_incoming_state_destroy();
 }
 
-int load_snapshot(const char *name, Error **errp)
+int load_snapshot(const char *name, strList *exclude, Error **errp)
 {
 BlockDriverState *bs, *bs_vm_state;
 QEMUSnapshotInfo sn;
@@ -2842,13 +2842,13 @@ int load_snapshot(const char *name, Error **errp)
 return -EINVAL;
 }
 
-if (!bdrv_all_can_snapshot(NULL, )) {
+if (!bdrv_all_can_snapshot(exclude, )) {
 error_setg(errp,
"Device '%s' is writable but does not support snapshots",
bdrv_get_device_or_node_name(bs));
 return -ENOTSUP;
 }
-ret = bdrv_all_find_snapshot(name, NULL, );
+ret = bdrv_all_find_snapshot(name, exclude, );
 if (ret < 0) {
 error_setg(errp,
"Device '%s' does not have the requested snapshot '%s'",
@@ -2856,7 +2856,7 @@ int load_snapshot(const char *name, Error **errp)
 return ret;
 }
 
-bs_vm_state = bdrv_all_find_vmstate_bs(NULL, NULL, errp);
+bs_vm_state = bdrv_all_find_vmstate_bs(NULL, exclude, errp);
 if (!bs_vm_state) {
 return -ENOTSUP;
 }
@@ -2877,7 +2877,7 @@ int load_snapshot(const char *name, Error **errp)
 /* Flush all IO requests so they don't interfere with the new state.  */
 bdrv_drain_all_begin();
 
-ret = bdrv_all_goto_snapshot(name, NULL, , errp);
+ret = bdrv_all_goto_snapshot(name, exclude, , errp);
 if (ret < 0) {
 

[PATCH 2/6] migration: introduce savevm, loadvm, delvm QMP commands

2020-07-02 Thread Daniel P . Berrangé
savevm, loadvm and delvm are some of the few commands that have never
been converted to use QMP. The primary reason for this lack of
conversion is that they block execution of the thread for as long as
they run.

Despite this downside, however, libvirt and applications using libvirt
has used these commands for as long as QMP has existed, via the
"human-monitor-command" passthrough command. IOW, while it is clearly
desirable to be able to fix the blocking problem, this is not an
immediate obstacle to real world usage.

Meanwhile there is a need for other features which involve adding new
parameters to the commands. This is possible with HMP passthrough, but
it provides no reliable way for apps to introspect features, so using
QAPI modelling is highly desirable.

This patch thus introduces trival savevm, loadvm, delvm commands
to QMP that are functionally identical to the HMP counterpart, including
the blocking problem.

Signed-off-by: Daniel P. Berrangé 
---
 migration/savevm.c  | 27 
 monitor/hmp-cmds.c  | 18 ++-
 qapi/migration.json | 76 +
 3 files changed, 106 insertions(+), 15 deletions(-)

diff --git a/migration/savevm.c b/migration/savevm.c
index 72dbad95ed..53586a6406 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2943,3 +2943,30 @@ bool vmstate_check_only_migratable(const 
VMStateDescription *vmsd)
 
 return !(vmsd && vmsd->unmigratable);
 }
+
+void qmp_savevm(const char *tag, Error **errp)
+{
+save_snapshot(tag, errp);
+}
+
+void qmp_loadvm(const char *tag, Error **errp)
+{
+int saved_vm_running  = runstate_is_running();
+
+vm_stop(RUN_STATE_RESTORE_VM);
+
+if (load_snapshot(tag, errp) == 0 && saved_vm_running) {
+vm_start();
+}
+}
+
+void qmp_delvm(const char *tag, Error **errp)
+{
+BlockDriverState *bs;
+
+if (bdrv_all_delete_snapshot(tag, , errp) < 0) {
+error_prepend(errp,
+  "deleting snapshot on device '%s': ",
+  bdrv_get_device_or_node_name(bs));
+}
+}
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 2b0b58a336..26a5a1a701 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1089,15 +1089,9 @@ void hmp_balloon(Monitor *mon, const QDict *qdict)
 
 void hmp_loadvm(Monitor *mon, const QDict *qdict)
 {
-int saved_vm_running  = runstate_is_running();
-const char *name = qdict_get_str(qdict, "name");
 Error *err = NULL;
 
-vm_stop(RUN_STATE_RESTORE_VM);
-
-if (load_snapshot(name, ) == 0 && saved_vm_running) {
-vm_start();
-}
+qmp_loadvm(qdict_get_str(qdict, "name"), );
 hmp_handle_error(mon, err);
 }
 
@@ -1105,21 +1099,15 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
 {
 Error *err = NULL;
 
-save_snapshot(qdict_get_try_str(qdict, "name"), );
+qmp_savevm(qdict_get_try_str(qdict, "name"), );
 hmp_handle_error(mon, err);
 }
 
 void hmp_delvm(Monitor *mon, const QDict *qdict)
 {
-BlockDriverState *bs;
 Error *err = NULL;
-const char *name = qdict_get_str(qdict, "name");
 
-if (bdrv_all_delete_snapshot(name, , ) < 0) {
-error_prepend(,
-  "deleting snapshot on device '%s': ",
-  bdrv_get_device_name(bs));
-}
+qmp_delvm(qdict_get_str(qdict, "name"), );
 hmp_handle_error(mon, err);
 }
 
diff --git a/qapi/migration.json b/qapi/migration.json
index d5000558c6..849de38fb0 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1621,3 +1621,79 @@
 ##
 { 'event': 'UNPLUG_PRIMARY',
   'data': { 'device-id': 'str' } }
+
+##
+# @savevm:
+#
+# Save a VM snapshot
+#
+# @tag: name of the snapshot to create. If it already
+# exists it will be replaced.
+#
+# Note that execution of the VM will be paused during the time
+# it takes to save the snapshot
+#
+# Returns: nothing
+#
+# Example:
+#
+# -> { "execute": "savevm",
+#  "data": {
+# "tag": "my-snap"
+#  }
+#}
+# <- { "return": { } }
+#
+# Since: 5.2
+##
+{ 'command': 'savevm',
+  'data': { 'tag': 'str' } }
+
+##
+# @loadvm:
+#
+# Load a VM snapshot
+#
+# @tag: name of the snapshot to load.
+#
+# Returns: nothing
+#
+# Example:
+#
+# -> { "execute": "loadvm",
+#  "data": {
+# "tag": "my-snap"
+#  }
+#}
+# <- { "return": { } }
+#
+# Since: 5.2
+##
+{ 'command': 'loadvm',
+  'data': { 'tag': 'str' } }
+
+##
+# @delvm:
+#
+# Delete a VM snapshot
+#
+# @tag: name of the snapshot to delete.
+#
+# Note that execution of the VM will be paused during the time
+# it takes to delete the snapshot
+#
+# Returns: nothing
+#
+# Example:
+#
+# -> { "execute": "delvm",
+#  "data": {
+# "tag": "my-snap"
+#  }
+#}
+# <- { "return": { } }
+#
+# Since: 5.2
+##
+{ 'command': 'delvm',
+  'data': { 'tag': 'str' } }
-- 
2.26.2




[PATCH 6/6] migration: support picking vmstate disk in QMP snapshot commands

2020-07-02 Thread Daniel P . Berrangé
This wires up support for a new "vmstate" parameter to the QMP commands
for snapshots (savevm, loadvm). This parameter accepts block driver
state node name.

One use case for this would be a VM using OVMF firmware where the
variables store is the first snapshottable disk image. The vmstate
snapshot usually wants to be stored in the primary root disk of the
VM, not the firmeware varstore. Thus there needs to be a mechanism
to override the default choice of disk.

Signed-off-by: Daniel P. Berrangé 
---
 include/migration/snapshot.h |  8 ++--
 migration/savevm.c   | 16 ++--
 monitor/hmp-cmds.c   |  6 --
 qapi/migration.json  |  6 ++
 replay/replay-snapshot.c |  4 ++--
 softmmu/vl.c |  2 +-
 6 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/include/migration/snapshot.h b/include/migration/snapshot.h
index dffb84dbe5..721147d3c1 100644
--- a/include/migration/snapshot.h
+++ b/include/migration/snapshot.h
@@ -17,7 +17,11 @@
 
 #include "qapi/qapi-builtin-types.h"
 
-int save_snapshot(const char *name, strList *exclude, Error **errp);
-int load_snapshot(const char *name, strList *exclude, Error **errp);
+int save_snapshot(const char *name,
+  const char *vmstate, strList *exclude,
+  Error **errp);
+int load_snapshot(const char *name,
+  const char *vmstate, strList *exclude,
+  Error **errp);
 
 #endif
diff --git a/migration/savevm.c b/migration/savevm.c
index 4b040676f7..5fd593e475 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2624,7 +2624,8 @@ int qemu_load_device_state(QEMUFile *f)
 return 0;
 }
 
-int save_snapshot(const char *name, strList *exclude, Error **errp)
+int save_snapshot(const char *name, const char *vmstate,
+  strList *exclude, Error **errp)
 {
 BlockDriverState *bs, *bs1;
 QEMUSnapshotInfo sn1, *sn = , old_sn1, *old_sn = _sn1;
@@ -2662,7 +2663,7 @@ int save_snapshot(const char *name, strList *exclude, 
Error **errp)
 }
 }
 
-bs = bdrv_all_find_vmstate_bs(NULL, exclude, errp);
+bs = bdrv_all_find_vmstate_bs(vmstate, exclude, errp);
 if (bs == NULL) {
 return ret;
 }
@@ -2827,7 +2828,8 @@ void qmp_xen_load_devices_state(const char *filename, 
Error **errp)
 migration_incoming_state_destroy();
 }
 
-int load_snapshot(const char *name, strList *exclude, Error **errp)
+int load_snapshot(const char *name, const char *vmstate,
+  strList *exclude, Error **errp)
 {
 BlockDriverState *bs, *bs_vm_state;
 QEMUSnapshotInfo sn;
@@ -2856,7 +2858,7 @@ int load_snapshot(const char *name, strList *exclude, 
Error **errp)
 return ret;
 }
 
-bs_vm_state = bdrv_all_find_vmstate_bs(NULL, exclude, errp);
+bs_vm_state = bdrv_all_find_vmstate_bs(vmstate, exclude, errp);
 if (!bs_vm_state) {
 return -ENOTSUP;
 }
@@ -2943,13 +2945,15 @@ bool vmstate_check_only_migratable(const 
VMStateDescription *vmsd)
 }
 
 void qmp_savevm(const char *tag,
+bool has_vmstate, const char *vmstate,
 bool has_exclude, strList *exclude,
 Error **errp)
 {
-save_snapshot(tag, exclude, errp);
+save_snapshot(tag, vmstate, exclude, errp);
 }
 
 void qmp_loadvm(const char *tag,
+bool has_vmstate, const char *vmstate,
 bool has_exclude, strList *exclude,
 Error **errp)
 {
@@ -2957,7 +2961,7 @@ void qmp_loadvm(const char *tag,
 
 vm_stop(RUN_STATE_RESTORE_VM);
 
-if (load_snapshot(tag, exclude, errp) == 0 && saved_vm_running) {
+if (load_snapshot(tag, vmstate, exclude, errp) == 0 && saved_vm_running) {
 vm_start();
 }
 }
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index fcde649100..586676e179 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1091,7 +1091,8 @@ void hmp_loadvm(Monitor *mon, const QDict *qdict)
 {
 Error *err = NULL;
 
-qmp_loadvm(qdict_get_str(qdict, "name"), false, NULL, );
+qmp_loadvm(qdict_get_str(qdict, "name"),
+   false, NULL, false, NULL, );
 hmp_handle_error(mon, err);
 }
 
@@ -1099,7 +1100,8 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
 {
 Error *err = NULL;
 
-qmp_savevm(qdict_get_try_str(qdict, "name"), false, NULL, );
+qmp_savevm(qdict_get_try_str(qdict, "name"),
+   false, NULL, false, NULL, );
 hmp_handle_error(mon, err);
 }
 
diff --git a/qapi/migration.json b/qapi/migration.json
index 2388664077..91173f5b06 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1630,6 +1630,7 @@
 # @tag: name of the snapshot to create. If it already
 # exists it will be replaced.
 # @exclude: list of block device node names to exclude
+# @vmstate: block device node name to save vmstate to
 #
 # Note that execution of the VM will be paused during the time
 # it takes to save the snapshot
@@ -1641,6 +1642,7 @@
 # -> { "execute": 

[PATCH 1/6] migration: improve error reporting of block driver state name

2020-07-02 Thread Daniel P . Berrangé
With blockdev, a BlockDriverState may not have an device name,
so using a node name is required as an alternative.

Signed-off-by: Daniel P. Berrangé 
---
 migration/savevm.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/migration/savevm.c b/migration/savevm.c
index b979ea6e7f..72dbad95ed 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2648,7 +2648,7 @@ int save_snapshot(const char *name, Error **errp)
 
 if (!bdrv_all_can_snapshot()) {
 error_setg(errp, "Device '%s' is writable but does not support "
-   "snapshots", bdrv_get_device_name(bs));
+   "snapshots", bdrv_get_device_or_node_name(bs));
 return ret;
 }
 
@@ -2657,7 +2657,7 @@ int save_snapshot(const char *name, Error **errp)
 ret = bdrv_all_delete_snapshot(name, , errp);
 if (ret < 0) {
 error_prepend(errp, "Error while deleting snapshot on device "
-  "'%s': ", bdrv_get_device_name(bs1));
+  "'%s': ", bdrv_get_device_or_node_name(bs1));
 return ret;
 }
 }
@@ -2728,7 +2728,7 @@ int save_snapshot(const char *name, Error **errp)
 ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, );
 if (ret < 0) {
 error_setg(errp, "Error while creating snapshot on '%s'",
-   bdrv_get_device_name(bs));
+   bdrv_get_device_or_node_name(bs));
 goto the_end;
 }
 
@@ -2846,14 +2846,14 @@ int load_snapshot(const char *name, Error **errp)
 if (!bdrv_all_can_snapshot()) {
 error_setg(errp,
"Device '%s' is writable but does not support snapshots",
-   bdrv_get_device_name(bs));
+   bdrv_get_device_or_node_name(bs));
 return -ENOTSUP;
 }
 ret = bdrv_all_find_snapshot(name, );
 if (ret < 0) {
 error_setg(errp,
"Device '%s' does not have the requested snapshot '%s'",
-   bdrv_get_device_name(bs), name);
+   bdrv_get_device_or_node_name(bs), name);
 return ret;
 }
 
@@ -2882,7 +2882,7 @@ int load_snapshot(const char *name, Error **errp)
 ret = bdrv_all_goto_snapshot(name, , errp);
 if (ret < 0) {
 error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
-  name, bdrv_get_device_name(bs));
+  name, bdrv_get_device_or_node_name(bs));
 goto err_drain;
 }
 
-- 
2.26.2




[PATCH 0/6] migration: bring savevm/loadvm/delvm over to QMP

2020-07-02 Thread Daniel P . Berrangé
When QMP was first introduced some 10+ years ago now, the snapshot
related commands (savevm/loadvm/delvm) were not converted. This was
primarily because their implementation causes blocking of the thread
running the monitor commands. This was (and still is) considered
undesirable behaviour both in HMP and QMP.

In theory someone was supposed to fix this flaw at some point in the
past 10 years and bring them into the QMP world. Sadly, thus far it
hasn't happened as people always had more important things to work
on. Enterprise apps were much more interested in external snapshots
than internal snapshots as they have many more features.

Meanwhile users still want to use internal snapshots as there is
a certainly simplicity in having everything self-contained in one
image, even though it has limitations. Thus the apps that end up
executing the savevm/loadvm/delvm via the "human-monitor-command"
QMP command.


IOW, the problematic blocking behaviour that was one of the reasons
for not having savevm/loadvm/delvm in QMP is experienced by applications
regardless. By not portting the commands to QMP due to one design flaw,
we've forced apps and users to suffer from other design flaws of HMP (
bad error reporting, strong type checking of args, no introspection) for
an additional 10 years. This feels rather sub-optimal :-(

In practice users don't appear to care strongly about the fact that these
commands block the VM while they run. I might have seen one bug report
about it, but it certainly isn't something that comes up as a frequent
topic except among us QEMU maintainers. Users do care about having
access to the snapshot feature.

Where I am seeing frequent complaints is wrt the use of OVMF combined
with snapshots which has some serious pain points. This is getting worse
as the push to ditch legacy BIOS in favour of UEFI gain momentum both
across OS vendors and mgmt apps. Solving it requires new parameters to
the commands, but doing this in HMP is super unappealing.



After 10 years, I think it is time for us to be a little pragmatic about
our handling of snapshots commands. My desire is that libvirt should never
use "human-monitor-command" under any circumstances, because of the
inherant flaws in HMP as a protocol for machine consumption. If there
are flaws in QMP commands that's fine. If we fix them in future, we can
deprecate the current QMP commands and remove them not too long after,
without being locked in forever.


Thus in this series I'm proposing a direct 1-1 mapping of the existing
HMP commands for savevm/loadvm/delvm into QMP as a first step. This does
not solve the blocking thread problem, but it does eliminate the error
reporting, type checking and introspection problems inherant to HMP.
We're winning on 3 out of the 4 long term problems.

If someone can suggest a easy way to fix the thread blocking problem
too, I'd be interested to hear it. If it involves a major refactoring
then I think user are better served by unlocking what look like easy
wins today.

With a QMP variant, we reasonably deal with the problems related to OVMF:

 - The logic to pick which disk to store the vmstate in is not
   satsifactory.

   The first block driver state cannot be assumed to be the root disk
   image, it might be OVMF varstore and we don't want to store vmstate
   in there.

 - The logic to decide which disks must be snapshotted is hardwired
   to all disks which are writable

   Again with OVMF there might be a writable varstore, but this can be
   raw rather than qcow2 format, and thus unable to be snapshotted.
   While users might wish to snapshot their varstore, in some/many/most
   cases it is entirely uneccessary. Users are blocked from snapshotting
   their VM though due to this varstore.

These are solved by adding two parameters to the commands. The first is
a block device node name that identifies the image to store vmstate in,
and the second is a list of node names to exclude from snapshots.

In the block code I've only dealt with node names for block devices, as
IIUC, this is all that libvirt should need in the -blockdev world it now
lives in. IOW, I've made not attempt to cope with people wanting to use
these QMP commands in combination with -drive args.

I've done some minimal work in libvirt to start to make use of the new
commands to validate their functionality, but this isn't finished yet.

My ultimate goal is to make the GNOME Boxes maintainer happy again by
having internal snapshots work with OVMF:

  https://gitlab.gnome.org/GNOME/gnome-boxes/-/commit/c486da262f6566326fbcb5e=
f45c5f64048f16a6e

Daniel P. Berrang=C3=A9 (6):
  migration: improve error reporting of block driver state name
  migration: introduce savevm, loadvm, delvm QMP commands
  block: add ability to filter out blockdevs during snapshot
  block: allow specifying name of block device for vmstate storage
  migration: support excluding block devs in QMP snapshot commands
  migration: support picking vmstate disk in QMP snapshot 

Re: [PATCH v4 2/2] nvme: allow cmb and pmr to be enabled on same device

2020-07-02 Thread Klaus Jensen
On Jul  2 08:07, Andrzej Jakowski wrote:
> On 7/2/20 3:31 AM, Klaus Jensen wrote:
> > Aight, an update here. This only happens when QEMU is run with a virtual
> > IOMMU. Otherwise, the kernel is happy.
> > 
> > With the vIOMMU, qemu also craps out a bit:
> > 
> > qemu-system-x86_64: vtd_iova_to_slpte: detected slpte permission error 
> > (iova=0xfd20, level=0x2, slpte=0x0, write=0)
> > qemu-system-x86_64: vtd_iommu_translate: detected translation failure 
> > (dev=03:00:00, iova=0xfd20)
> > 
> > So I think we are back in QEMU land for the bug.
> 
> Can you share command line for that?
> 
> 

qemu-system-x86_64 \
  -nodefaults \
  -display none \
  -device intel-iommu,pt,intremap=on,device-iotlb=on \
  -machine type=q35,accel=kvm,kernel_irqchip=split \
  -cpu host \
  -smp 4 \
  -m 8G \
  -nic user,model=virtio-net-pci,hostfwd=tcp::-:22 \
  -device virtio-rng-pci \
  -drive 
id=boot,file=/home/kbj/work/src/vmctl/state/pmr/boot.qcow2,format=qcow2,if=virtio,discard=on,detect-zeroes=unmap
 \
  -device pcie-root-port,id=pcie_root_port1,chassis=1,slot=0 \
  -device x3130-upstream,id=pcie_upstream1,bus=pcie_root_port1 \
  -device 
xio3130-downstream,id=pcie_downstream1,bus=pcie_upstream1,chassis=1,slot=1 \
  -drive 
id=nvme0n1,file=/home/kbj/work/src/vmctl/state/pmr/nvme0n1.img,format=raw,if=none,discard=on,detect-zeroes=unmap
 \
  -object memory-backend-file,id=pmr,share=on,mem-path=pmr.bin,size=1M \
  -device 
nvme,id=nvme0,serial=deadbeef,bus=pcie_downstream1,drive=nvme0n1,msix_qsize=1,pmrdev=pmr,cmb_size_mb=2
 \
  -pidfile /home/kbj/work/src/vmctl/run/pmr/pidfile \
  -kernel /home/kbj/work/src/kernel/linux/arch/x86_64/boot/bzImage \
  -append root=/dev/vda1 console=ttyS0,115200 audit=0 nokaslr \
  -virtfs 
local,path=/home/kbj/work/src/kernel/linux,security_model=none,readonly,mount_tag=modules
 \
  -serial mon:stdio \
  -trace pci_nvme*





Re: [PATCH v2 33/44] error: Avoid unnecessary error_propagate() after error_setg()

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

Replace

 error_setg(, ...);
 error_propagate(errp, err);

by

 error_setg(errp, ...);





Candidates for conversion tracked down with this Coccinelle script:

 @@
 identifier err, errp;
 expression list args;
 @@
 -error_setg(, args);
 +error_setg(errp, args);
 ... when != err
 error_propagate(errp, err);

Signed-off-by: Markus Armbruster 
---



+++ b/backends/cryptodev.c
@@ -158,16 +158,15 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, 
const char *name,
  uint32_t value;
  
  if (!visit_type_uint32(v, name, , _err)) {

-goto out;
+error_propagate(errp, local_err);
+return;
  }


Looks like this error_propgate is spurious if you just use
 if (!visit_type_uint32(..., errp)) {

Oh - that's not the pattern you flagged, and a later patch then 
addresses it.  It might help if the commit message for this patch 
mentions that further cleanups are still forthcoming.




+++ b/backends/hostmem-file.c
@@ -114,18 +114,16 @@ static void file_memory_backend_set_align(Object *o, 
Visitor *v,
  uint64_t val;
  
  if (host_memory_backend_mr_inited(backend)) {

-error_setg(_err, "cannot change property '%s' of %s",
-   name, object_get_typename(o));
-goto out;
+error_setg(errp, "cannot change property '%s' of %s", name,
+   object_get_typename(o));
+return;
  }
  
  if (!visit_type_size(v, name, , _err)) {

-goto out;
+error_propagate(errp, local_err);
+return;
  }


Another case where the first 'if' matches the subject of this patch, and 
the second 'if' can avoid local_err but that the change will be done in 
a later patch.  And several more later on, but this is how far it took 
me to realize that you intentionally saved them for later.


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 32/44] qdev: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

The previous commit enables conversion of

 qdev_prop_set_drive_err(..., );
 if (err) {
 ...
 }

to

 if (!qdev_prop_set_drive_err(..., errp)) {
 ...
 }

Coccinelle script:


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 29/44] qom: Use returned bool to check for failure, manual part

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

The previous commit used Coccinelle to convert from checking the Error
object to checking the return value.  Convert a few more manually.

Signed-off-by: Markus Armbruster 
---
  hw/core/bus.c  |  6 +-
  hw/core/qdev.c |  7 +--
  hw/s390x/s390-virtio-ccw.c | 13 +++--
  3 files changed, 9 insertions(+), 17 deletions(-)



Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 28/44] qom: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

The previous commit enables conversion of

 foo(..., );
 if (err) {
...
 }

to

 if (!foo(..., errp)) {
...
 }

for QOM functions that now return true / false on success / error.
Coccinelle script:

 @@
 identifier fun = {object_apply_global_props, 
object_initialize_child_with_props, object_initialize_child_with_propsv, 
object_property_get, object_property_get_bool, object_property_parse, 
object_property_set, object_property_set_bool, object_property_set_int, 
object_property_set_link, object_property_set_qobject, object_property_set_str, 
object_property_set_uint, object_set_props, object_set_propv, 
user_creatable_add_dict, user_creatable_complete, user_creatable_del};
 expression list args, args2;
 typedef Error;
 Error *err;
 @@
 -fun(args, , args2);
 -if (err)
 +if (!fun(args, , args2))
  {
  ...
  }

Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Convert manually.

Line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 23/44] qom: Crash more nicely on object_property_get_link() failure

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

Pass _abort instead of NULL where the returned value is
dereferenced or asserted to be non-null.  Drop a now redundant
assertion.

Signed-off-by: Markus Armbruster 
---
  hw/core/platform-bus.c | 6 +++---

Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 17/44] qapi: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

The previous commit enables conversion of

 visit_foo(..., );
 if (err) {
...
 }

to

 if (!visit_foo(..., errp)) {
...
 }

for visitor functions that now return true / false on success / error.
Coccinelle script:

 @@
 identifier fun =~ 
"check_list|input_type_enum|lv_start_struct|lv_type_bool|lv_type_int64|lv_type_str|lv_type_uint64|output_type_enum|parse_type_bool|parse_type_int64|parse_type_null|parse_type_number|parse_type_size|parse_type_str|parse_type_uint64|print_type_bool|print_type_int64|print_type_null|print_type_number|print_type_size|print_type_str|print_type_uint64|qapi_clone_start_alternate|qapi_clone_start_list|qapi_clone_start_struct|qapi_clone_type_bool|qapi_clone_type_int64|qapi_clone_type_null|qapi_clone_type_number|qapi_clone_type_str|qapi_clone_type_uint64|qapi_dealloc_start_list|qapi_dealloc_start_struct|qapi_dealloc_type_anything|qapi_dealloc_type_bool|qapi_dealloc_type_int64|qapi_dealloc_type_null|qapi_dealloc_type_number|qapi_dealloc_type_str|qapi_dealloc_type_uint64|qobject_input_check_list|qobject_input_check_struct|qobject_input_start_alternate|qobject_input_start_list|qobject_input_start_struct|qobject_input_type_any|qobject_input_type_bool|qobject_input_type_bool_keyval|qobject_input_type_int64|qobject_input_type_int64_keyval|qobject_input_type_null|qobject_input_type_number|qobject_input_type_number_keyval|qobject_input_type_size_keyval|qobject_input_type_str|qobject_input_type_str_keyval|qobject_input_type_uint64|qobject_input_type_uint64_keyval|qobject_output_start_list|qobject_output_start_struct|qobject_output_type_any|qobject_output_type_bool|qobject_output_type_int64|qobject_output_type_null|qobject_output_type_number|qobject_output_type_str|qobject_output_type_uint64|start_list|visit_check_list|visit_check_struct|visit_start_alternate|visit_start_list|visit_start_struct|visit_type_.*";


Long line, but tolerable


 expression list args;
 typedef Error;
 Error *err;
 @@
 -fun(args, );
 -if (err)
 +if (!fun(args, ))
  {
  ...
  }

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


Re: [PATCH v2 16/44] qapi: Make visitor functions taking Error ** return bool, not void

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

See recent commit "error: Document Error API usage rules" for
rationale.

Signed-off-by: Markus Armbruster 
---


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 00/44] Less clumsy error checking

2020-07-02 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20200702155000.3455325-1-arm...@redhat.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing 
commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===




The full log is available at
http://patchew.org/logs/20200702155000.3455325-1-arm...@redhat.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

Re: [PATCH v2 00/44] Less clumsy error checking

2020-07-02 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20200702155000.3455325-1-arm...@redhat.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [PATCH v2 00/44] Less clumsy error checking
Type: series
Message-id: 20200702155000.3455325-1-arm...@redhat.com

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
581316d hmp: Ignore Error objects where the return value suffices
382f9cc qdev: Ignore Error objects where the return value suffices
2d54031 qemu-img: Ignore Error objects where the return value suffices
c1da551 error: Avoid error_propagate() after migrate_add_blocker()
584033a qapi: Purge error_propagate() from QAPI core
d5c18e7 qapi: Smooth visitor error checking in generated code
a0b2eb7 qapi: Smooth another visitor error checking pattern
59fbe03 error: Reduce unnecessary error propagation
d5401ed error: Eliminate error_propagate() manually
28da452 error: Eliminate error_propagate() with Coccinelle, part 2
249518d error: Eliminate error_propagate() with Coccinelle, part 1
79d26b3 error: Avoid unnecessary error_propagate() after error_setg()
69f21ee qdev: Use returned bool to check for failure, Coccinelle part
cc10b4f qdev: Make functions taking Error ** return bool, not void
937e007 qom: Make functions taking Error ** return bool, not 0/-1
c13008d qom: Use returned bool to check for failure, manual part
a76e6b8a qom: Use returned bool to check for failure, Coccinelle part
5831b19 qom: Make functions taking Error ** return bool, not void
ee89136 qom: Put name parameter before value / visitor parameter
cca92e7 qom: Use return values to check for error where that's simpler
b3e4fbd qom: Don't handle impossible object_property_get_link() failure
64c3868 qom: Crash more nicely on object_property_get_link() failure
1045bbb qom: Rename qdev_get_type() to object_get_type()
a90aa52 qom: Use error_reportf_err() instead of g_printerr() in examples
042c119 s390x/pci: Fix harmless mistake in zpci's property fid's setter
7556520 block/parallels: Simplify parallels_open() after previous commit
67c3627 qapi: Use returned bool to check for failure, manual part
d461f88 qapi: Use returned bool to check for failure, Coccinelle part
61c3c84 qapi: Make visitor functions taking Error ** return bool, not void
e11841d hmp: Eliminate a variable in hmp_migrate_set_parameter()
b11147d block: Avoid error accumulation in bdrv_img_create()
5ddfdab qemu-option: Use returned bool to check for failure
132ed75 qemu-option: Make functions taking Error ** return bool, not void
48a09ea qemu-option: Replace opt_set() by cleaner opt_validate()
7ea945d qemu-option: Factor out helper opt_create()
378230d qemu-option: Simplify around find_default_by_name()
419b8e9 qemu-option: Factor out helper find_default_by_name()
066fe51 qemu-option: Make uses of find_desc_by_name() more similar
5ce56fe qemu-option: Check return value instead of @err where convenient
367ec25 virtio-crypto-pci: Tidy up virtio_crypto_pci_realize()
8df3b8f macio: Tidy up error handling in macio_newworld_realize()
0e00e46 qdev: Use returned bool to check for qdev_realize() etc. failure
15a41a5 error: Document Error API usage rules
6cc06a1 error: Improve examples in error.h's big comment

=== OUTPUT BEGIN ===
1/44 Checking commit 6cc06a1b48e4 (error: Improve examples in error.h's big 
comment)
ERROR: Error messages should not contain newlines
#37: FILE: include/qapi/error.h:27:
+ * error_setg(errp, "invalid quark\n" // WRONG!

total: 1 errors, 0 warnings, 42 lines checked

Patch 1/44 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

2/44 Checking commit 15a41a5ba273 (error: Document Error API usage rules)
3/44 Checking commit 0e00e463e690 (qdev: Use returned bool to check for 
qdev_realize() etc. failure)
4/44 Checking commit 8df3b8f872d3 (macio: Tidy up error handling in 
macio_newworld_realize())
5/44 Checking commit 367ec250efbc (virtio-crypto-pci: Tidy up 
virtio_crypto_pci_realize())
6/44 Checking commit 5ce56fec2a32 (qemu-option: Check return value instead of 
@err where convenient)
7/44 Checking commit 066fe5182eff (qemu-option: Make uses of 
find_desc_by_name() more similar)
8/44 Checking commit 419b8e946ee0 (qemu-option: Factor out helper 
find_default_by_name())
9/44 Checking commit 378230df0dc2 (qemu-option: Simplify around 
find_default_by_name())
10/44 Checking commit 7ea945df03f9 (qemu-option: Factor out helper opt_create())
11/44 Checking commit 48a09ea2ba72 (qemu-option: Replace opt_set() by cleaner 
opt_validate())
12/44 Checking commit 132ed750d145 (qemu-option: Make functions taking Error ** 
return bool, not void)
13/44 

Re: [PATCH v2 14/44] block: Avoid error accumulation in bdrv_img_create()

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

When creating an image fails because the format doesn't support option
"backing_file" or "backing_fmt", bdrv_img_create() first has
qemu_opt_set() put a generic error into @local_err, then puts the real
error into @errp with error_setg(), and then propagates the former to
the latter, which throws away the generic error.  A bit complicated,
but works.

Not that qemu_opt_set() returns a useful value, we can simply ignore


s/Not/Now/


the generic error instead.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
  block.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)



--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




Re: [PATCH v2 13/44] qemu-option: Use returned bool to check for failure

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

The previous commit enables conversion of

 foo(..., );
 if (err) {
 ...
 }

to

 if (!foo(..., )) {
 ...
 }

for QemuOpts functions that now return true / false on success /
error.  Coccinelle script:

 @@
 identifier fun = {opts_do_parse, parse_option_bool, parse_option_number, 
parse_option_size, qemu_opt_parse, qemu_opt_rename, qemu_opt_set, 
qemu_opt_set_bool, qemu_opt_set_number, qemu_opts_absorb_qdict, 
qemu_opts_do_parse, qemu_opts_from_qdict_entry, qemu_opts_set, 
qemu_opts_validate};
 expression list args, args2;
 typedef Error;
 Error *err;
 @@
 -fun(args, , args2);
 -if (err)
 +if (!fun(args, , args2))
  {
  ...
  }

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---


Similar results to the script in 3/44.

Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




[PATCH v2 40/44] qapi: Purge error_propagate() from QAPI core

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 qapi/qapi-visit-core.c | 40 +++-
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 5a9c47aabf..7e5f40e7f0 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -39,19 +39,18 @@ void visit_free(Visitor *v)
 bool visit_start_struct(Visitor *v, const char *name, void **obj,
 size_t size, Error **errp)
 {
-Error *err = NULL;
+bool ok;
 
 trace_visit_start_struct(v, name, obj, size);
 if (obj) {
 assert(size);
 assert(!(v->type & VISITOR_OUTPUT) || *obj);
 }
-v->start_struct(v, name, obj, size, );
+ok = v->start_struct(v, name, obj, size, errp);
 if (obj && (v->type & VISITOR_INPUT)) {
-assert(!err != !*obj);
+assert(ok != !*obj);
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 bool visit_check_struct(Visitor *v, Error **errp)
@@ -69,16 +68,15 @@ void visit_end_struct(Visitor *v, void **obj)
 bool visit_start_list(Visitor *v, const char *name, GenericList **list,
   size_t size, Error **errp)
 {
-Error *err = NULL;
+bool ok;
 
 assert(!list || size >= sizeof(GenericList));
 trace_visit_start_list(v, name, list, size);
-v->start_list(v, name, list, size, );
+ok = v->start_list(v, name, list, size, errp);
 if (list && (v->type & VISITOR_INPUT)) {
-assert(!(err && *list));
+assert(ok || !*list);
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
@@ -104,19 +102,20 @@ bool visit_start_alternate(Visitor *v, const char *name,
GenericAlternate **obj, size_t size,
Error **errp)
 {
-Error *err = NULL;
+bool ok;
 
 assert(obj && size >= sizeof(GenericAlternate));
 assert(!(v->type & VISITOR_OUTPUT) || *obj);
 trace_visit_start_alternate(v, name, obj, size);
-if (v->start_alternate) {
-v->start_alternate(v, name, obj, size, );
+if (!v->start_alternate) {
+assert(!(v->type & VISITOR_INPUT));
+return true;
 }
+ok = v->start_alternate(v, name, obj, size, errp);
 if (v->type & VISITOR_INPUT) {
-assert(v->start_alternate && !err != !*obj);
+assert(ok != !*obj);
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 void visit_end_alternate(Visitor *v, void **obj)
@@ -309,7 +308,7 @@ bool visit_type_bool(Visitor *v, const char *name, bool 
*obj, Error **errp)
 
 bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
 {
-Error *err = NULL;
+bool ok;
 
 assert(obj);
 /* TODO: Fix callers to not pass NULL when they mean "", so that we
@@ -317,12 +316,11 @@ bool visit_type_str(Visitor *v, const char *name, char 
**obj, Error **errp)
 assert(!(v->type & VISITOR_OUTPUT) || *obj);
  */
 trace_visit_type_str(v, name, obj);
-v->type_str(v, name, obj, );
+ok = v->type_str(v, name, obj, errp);
 if (v->type & VISITOR_INPUT) {
-assert(!err != !*obj);
+assert(ok != !*obj);
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 bool visit_type_number(Visitor *v, const char *name, double *obj,
-- 
2.26.2




Re: [PATCH v2 03/44] qdev: Use returned bool to check for qdev_realize() etc. failure

2020-07-02 Thread Eric Blake

On 7/2/20 10:49 AM, Markus Armbruster wrote:

Convert

 foo(..., );
 if (err) {
 ...
 }

to

 if (!foo(..., )) {
 ...
 }

for qdev_realize(), qdev_realize_and_unref(), qbus_realize() and their
wrappers isa_realize_and_unref(), pci_realize_and_unref(),
sysbus_realize(), sysbus_realize_and_unref(), usb_realize_and_unref().
Coccinelle script:

 @@
 identifier fun = {isa_realize_and_unref, pci_realize_and_unref, 
qbus_realize, qdev_realize, qdev_realize_and_unref, sysbus_realize, 
sysbus_realize_and_unref, usb_realize_and_unref};
 expression list args, args2;
 typedef Error;
 Error *err;
 @@
 -fun(args, , args2);
 -if (err)
 +if (!fun(args, , args2))
  {
  ...
  }

Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information".  Nothing to convert there; skipped.

Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Converted manually.

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---


The conversion is quite straight-forward.  The patch is big, but 
correct, and you documented where it is not mechanical.


Reviewed-by: Eric Blake 

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




[PATCH v2 38/44] qapi: Smooth another visitor error checking pattern

2020-07-02 Thread Markus Armbruster
Convert

visit_type_FOO(v, ..., , );
...
if (err) {
...
}

to

visit_type_FOO(v, ..., , errp);
...
if (!ptr) {
...
}

for functions that set @ptr to non-null / null on success / error.

Eliminate error_propagate() that are now unnecessary.  Delete @err
that are now unused.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 block/nfs.c  |  7 ++-
 block/parallels.c|  6 ++
 block/qcow.c |  6 ++
 block/qcow2.c|  7 ++-
 block/qed.c  |  6 ++
 block/rbd.c  |  7 ++-
 block/sheepdog.c |  6 ++
 block/ssh.c  |  6 ++
 block/vdi.c  |  7 ++-
 block/vhdx.c |  6 ++
 block/vpc.c  |  6 ++
 hw/acpi/core.c   |  4 ++--
 hw/block/xen-block.c |  6 ++
 hw/core/numa.c   |  7 +++
 monitor/monitor.c| 21 +++--
 15 files changed, 36 insertions(+), 72 deletions(-)

diff --git a/block/nfs.c b/block/nfs.c
index b1718d125a..61a249a9fc 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -563,18 +563,15 @@ static BlockdevOptionsNfs 
*nfs_options_qdict_to_qapi(QDict *options,
 BlockdevOptionsNfs *opts = NULL;
 Visitor *v;
 const QDictEntry *e;
-Error *local_err = NULL;
 
 v = qobject_input_visitor_new_flat_confused(options, errp);
 if (!v) {
 return NULL;
 }
 
-visit_type_BlockdevOptionsNfs(v, NULL, , _err);
+visit_type_BlockdevOptionsNfs(v, NULL, , errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!opts) {
 return NULL;
 }
 
diff --git a/block/parallels.c b/block/parallels.c
index c259799111..f489c0d4ba 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -667,11 +667,9 @@ static int coroutine_fn 
parallels_co_create_opts(BlockDriver *drv,
 goto done;
 }
 
-visit_type_BlockdevCreateOptions(v, NULL, _options, _err);
+visit_type_BlockdevCreateOptions(v, NULL, _options, errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!create_options) {
 ret = -EINVAL;
 goto done;
 }
diff --git a/block/qcow.c b/block/qcow.c
index 7913d12d50..c22d1bf6b8 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -994,11 +994,9 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver 
*drv,
 goto fail;
 }
 
-visit_type_BlockdevCreateOptions(v, NULL, _options, _err);
+visit_type_BlockdevCreateOptions(v, NULL, _options, errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!create_options) {
 ret = -EINVAL;
 goto fail;
 }
diff --git a/block/qcow2.c b/block/qcow2.c
index a9137a535b..9ed2396c88 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3683,7 +3683,6 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver 
*drv,
 Visitor *v;
 BlockDriverState *bs = NULL;
 BlockDriverState *data_bs = NULL;
-Error *local_err = NULL;
 const char *val;
 int ret;
 
@@ -3779,11 +3778,9 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver 
*drv,
 goto finish;
 }
 
-visit_type_BlockdevCreateOptions(v, NULL, _options, _err);
+visit_type_BlockdevCreateOptions(v, NULL, _options, errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!create_options) {
 ret = -EINVAL;
 goto finish;
 }
diff --git a/block/qed.c b/block/qed.c
index 3d5ddd86f2..7fa7f880f6 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -770,11 +770,9 @@ static int coroutine_fn 
bdrv_qed_co_create_opts(BlockDriver *drv,
 goto fail;
 }
 
-visit_type_BlockdevCreateOptions(v, NULL, _options, _err);
+visit_type_BlockdevCreateOptions(v, NULL, _options, errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!create_options) {
 ret = -EINVAL;
 goto fail;
 }
diff --git a/block/rbd.c b/block/rbd.c
index 617553b022..688074c64b 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -681,7 +681,6 @@ static int qemu_rbd_convert_options(QDict *options, 
BlockdevOptionsRbd **opts,
 Error **errp)
 {
 Visitor *v;
-Error *local_err = NULL;
 
 /* Convert the remaining options into a QAPI object */
 v = qobject_input_visitor_new_flat_confused(options, errp);
@@ -689,11 +688,9 @@ static int qemu_rbd_convert_options(QDict *options, 
BlockdevOptionsRbd **opts,
 return -EINVAL;
 }
 
-visit_type_BlockdevOptionsRbd(v, NULL, opts, _err);
+visit_type_BlockdevOptionsRbd(v, NULL, opts, errp);
 visit_free(v);
-
-if (local_err) {
-error_propagate(errp, local_err);
+if (!opts) {
 return -EINVAL;
 }
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index a6a91442c9..6c487c8322 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -2193,11 +2193,9 @@ static int 

[PATCH v2 39/44] qapi: Smooth visitor error checking in generated code

2020-07-02 Thread Markus Armbruster
Use visitor functions' return values to check for failure.  Eliminate
error_propagate() that are now unnecessary.  Delete @err that are now
unused.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 docs/devel/qapi-code-gen.txt | 60 ++--
 scripts/qapi/commands.py | 22 ++---
 scripts/qapi/visit.py| 57 ++
 3 files changed, 55 insertions(+), 84 deletions(-)

diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 9bfc57063c..69eede6c28 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -1420,8 +1420,6 @@ Example:
 
 bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error 
**errp)
 {
-Error *err = NULL;
-
 if (!visit_type_int(v, "integer", >integer, errp)) {
 return false;
 }
@@ -1430,13 +1428,12 @@ Example:
 return false;
 }
 }
-error_propagate(errp, err);
-return !err;
+return true;
 }
 
 bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, 
Error **errp)
 {
-Error *err = NULL;
+bool ok = false;
 
 if (!visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), 
errp)) {
 return false;
@@ -1446,24 +1443,22 @@ Example:
 assert(visit_is_dealloc(v));
 goto out_obj;
 }
-visit_type_UserDefOne_members(v, *obj, );
-if (err) {
+if (!visit_type_UserDefOne_members(v, *obj, errp)) {
 goto out_obj;
 }
-visit_check_struct(v, );
+ok = visit_check_struct(v, errp);
 out_obj:
 visit_end_struct(v, (void **)obj);
-if (err && visit_is_input(v)) {
+if (!ok && visit_is_input(v)) {
 qapi_free_UserDefOne(*obj);
 *obj = NULL;
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 bool visit_type_UserDefOneList(Visitor *v, const char *name, 
UserDefOneList **obj, Error **errp)
 {
-Error *err = NULL;
+bool ok = false;
 UserDefOneList *tail;
 size_t size = sizeof(**obj);
 
@@ -1473,33 +1468,27 @@ Example:
 
 for (tail = *obj; tail;
  tail = (UserDefOneList *)visit_next_list(v, (GenericList *)tail, 
size)) {
-visit_type_UserDefOne(v, NULL, >value, );
-if (err) {
-break;
+if (!visit_type_UserDefOne(v, NULL, >value, errp)) {
+goto out_obj;
 }
 }
 
-if (!err) {
-visit_check_list(v, );
-}
+ok = visit_check_list(v, errp);
+out_obj:
 visit_end_list(v, (void **)obj);
-if (err && visit_is_input(v)) {
+if (!ok && visit_is_input(v)) {
 qapi_free_UserDefOneList(*obj);
 *obj = NULL;
 }
-error_propagate(errp, err);
-return !err;
+return ok;
 }
 
 bool visit_type_q_obj_my_command_arg_members(Visitor *v, 
q_obj_my_command_arg *obj, Error **errp)
 {
-Error *err = NULL;
-
 if (!visit_type_UserDefOneList(v, "arg1", >arg1, errp)) {
 return false;
 }
-error_propagate(errp, err);
-return !err;
+return true;
 }
 
 [Uninteresting stuff omitted...]
@@ -1554,15 +1543,12 @@ Example:
 
 static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject 
**ret_out, Error **errp)
 {
-Error *err = NULL;
 Visitor *v;
 
 v = qobject_output_visitor_new(ret_out);
-visit_type_UserDefOne(v, "unused", _in, );
-if (!err) {
+if (visit_type_UserDefOne(v, "unused", _in, errp)) {
 visit_complete(v, ret_out);
 }
-error_propagate(errp, err);
 visit_free(v);
 v = qapi_dealloc_visitor_new();
 visit_type_UserDefOne(v, "unused", _in, NULL);
@@ -1572,33 +1558,32 @@ Example:
 void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
 {
 Error *err = NULL;
+bool ok = false;
 Visitor *v;
 UserDefOne *retval;
 q_obj_my_command_arg arg = {0};
 
 v = qobject_input_visitor_new(QOBJECT(args));
-visit_start_struct(v, NULL, NULL, 0, );
-if (err) {
+if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
 goto out;
 }
-visit_type_q_obj_my_command_arg_members(v, , );
-if (!err) {
-visit_check_struct(v, );
+if (visit_type_q_obj_my_command_arg_members(v, , errp)) {
+ok = visit_check_struct(v, errp);
 }
 visit_end_struct(v, NULL);
-if (err) {
+if (!ok) {
 goto out;
 }
 
 retval = qmp_my_command(arg.arg1, );
+error_propagate(errp, err);
 if (err) {
 goto out;
 }
 
-

[PATCH v2 30/44] qom: Make functions taking Error ** return bool, not 0/-1

2020-07-02 Thread Markus Armbruster
Just for consistency.  Also fix the example in object_set_props()'s
documentation.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 include/qom/object.h | 28 +++-
 qom/object.c | 14 +++---
 2 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/include/qom/object.h b/include/qom/object.h
index b2d2558245..d74ede4eac 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -729,15 +729,13 @@ void object_apply_compat_props(Object *obj);
  *   Error *err = NULL;
  *   Object *obj = ...get / create object...;
  *
- *   obj = object_set_props(obj,
- *  ,
- *  "share", "yes",
- *  "mem-path", "/dev/shm/somefile",
- *  "prealloc", "yes",
- *  "size", "1048576",
- *  NULL);
- *
- *   if (!obj) {
+ *   if (!object_set_props(obj,
+ * ,
+ * "share", "yes",
+ * "mem-path", "/dev/shm/somefile",
+ * "prealloc", "yes",
+ * "size", "1048576",
+ * NULL)) {
  * error_reportf_err(err, "Cannot set properties: ");
  *   }
  *   
@@ -746,11 +744,9 @@ void object_apply_compat_props(Object *obj);
  * The returned object will have one stable reference maintained
  * for as long as it is present in the object hierarchy.
  *
- * Returns: -1 on error, 0 on success
+ * Returns: %true on success, %false on error.
  */
-int object_set_props(Object *obj,
- Error **errp,
- ...) QEMU_SENTINEL;
+bool object_set_props(Object *obj, Error **errp, ...) QEMU_SENTINEL;
 
 /**
  * object_set_propv:
@@ -760,11 +756,9 @@ int object_set_props(Object *obj,
  *
  * See object_set_props() for documentation.
  *
- * Returns: -1 on error, 0 on success
+ * Returns: %true on success, %false on error.
  */
-int object_set_propv(Object *obj,
- Error **errp,
- va_list vargs);
+bool object_set_propv(Object *obj, Error **errp, va_list vargs);
 
 /**
  * object_initialize:
diff --git a/qom/object.c b/qom/object.c
index ebfe6e6c51..bd8c86ec6f 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -557,7 +557,7 @@ bool object_initialize_child_with_propsv(Object *parentobj,
 object_initialize(childobj, size, type);
 obj = OBJECT(childobj);
 
-if (object_set_propv(obj, errp, vargs) < 0) {
+if (!object_set_propv(obj, errp, vargs)) {
 goto out;
 }
 
@@ -752,7 +752,7 @@ Object *object_new_with_propv(const char *typename,
 }
 obj = object_new_with_type(klass->type);
 
-if (object_set_propv(obj, errp, vargs) < 0) {
+if (!object_set_propv(obj, errp, vargs)) {
 goto error;
 }
 
@@ -780,12 +780,12 @@ Object *object_new_with_propv(const char *typename,
 }
 
 
-int object_set_props(Object *obj,
+bool object_set_props(Object *obj,
  Error **errp,
  ...)
 {
 va_list vargs;
-int ret;
+bool ret;
 
 va_start(vargs, errp);
 ret = object_set_propv(obj, errp, vargs);
@@ -795,7 +795,7 @@ int object_set_props(Object *obj,
 }
 
 
-int object_set_propv(Object *obj,
+bool object_set_propv(Object *obj,
  Error **errp,
  va_list vargs)
 {
@@ -809,12 +809,12 @@ int object_set_propv(Object *obj,
 g_assert(value != NULL);
 if (!object_property_parse(obj, propname, value, _err)) {
 error_propagate(errp, local_err);
-return -1;
+return false;
 }
 propname = va_arg(vargs, char *);
 }
 
-return 0;
+return true;
 }
 
 
-- 
2.26.2




[PATCH v2 27/44] qom: Make functions taking Error ** return bool, not void

2020-07-02 Thread Markus Armbruster
See recent commit "error: Document Error API usage rules" for
rationale.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 include/qom/object.h| 42 ++
 include/qom/object_interfaces.h | 12 +++-
 include/qom/qom-qobject.h   |  4 +-
 qom/object.c| 98 -
 qom/object_interfaces.c | 21 ---
 qom/qom-qobject.c   |  6 +-
 6 files changed, 121 insertions(+), 62 deletions(-)

diff --git a/include/qom/object.h b/include/qom/object.h
index 7ef9c8d0cc..b2d2558245 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -703,7 +703,7 @@ Object *object_new_with_propv(const char *typename,
   Error **errp,
   va_list vargs);
 
-void object_apply_global_props(Object *obj, const GPtrArray *props,
+bool object_apply_global_props(Object *obj, const GPtrArray *props,
Error **errp);
 void object_set_machine_compat_props(GPtrArray *compat_props);
 void object_set_accelerator_compat_props(GPtrArray *compat_props);
@@ -798,8 +798,10 @@ void object_initialize(void *obj, size_t size, const char 
*typename);
  * strings. The propname of %NULL indicates the end of the property list.
  * If the object implements the user creatable interface, the object will
  * be marked complete once all the properties have been processed.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_initialize_child_with_props(Object *parentobj,
+bool object_initialize_child_with_props(Object *parentobj,
  const char *propname,
  void *childobj, size_t size, const char *type,
  Error **errp, ...) QEMU_SENTINEL;
@@ -815,8 +817,10 @@ void object_initialize_child_with_props(Object *parentobj,
  * @vargs: list of property names and values
  *
  * See object_initialize_child() for documentation.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_initialize_child_with_propsv(Object *parentobj,
+bool object_initialize_child_with_propsv(Object *parentobj,
   const char *propname,
   void *childobj, size_t size, const char *type,
   Error **errp, va_list vargs);
@@ -1197,8 +1201,10 @@ void object_unparent(Object *obj);
  * @errp: returns an error if this function fails
  *
  * Reads a property from a object.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_get(Object *obj, const char *name, Visitor *v,
+bool object_property_get(Object *obj, const char *name, Visitor *v,
  Error **errp);
 
 /**
@@ -1208,8 +1214,10 @@ void object_property_get(Object *obj, const char *name, 
Visitor *v,
  * @errp: returns an error if this function fails
  *
  * Writes a string value to a property.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_set_str(Object *obj,
+bool object_property_set_str(Object *obj,
  const char *name, const char *value,
  Error **errp);
 
@@ -1238,8 +1246,9 @@ char *object_property_get_str(Object *obj, const char 
*name,
  * OBJ_PROP_LINK_STRONG bit, the old target object is
  * unreferenced, and a reference is added to the new target object.
  *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_set_link(Object *obj, const char *name, Object *value,
+bool object_property_set_link(Object *obj, const char *name, Object *value,
   Error **errp);
 
 /**
@@ -1262,8 +1271,10 @@ Object *object_property_get_link(Object *obj, const char 
*name,
  * @errp: returns an error if this function fails
  *
  * Writes a bool value to a property.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_set_bool(Object *obj, const char *name, bool value,
+bool object_property_set_bool(Object *obj, const char *name, bool value,
   Error **errp);
 
 /**
@@ -1285,8 +1296,10 @@ bool object_property_get_bool(Object *obj, const char 
*name,
  * @errp: returns an error if this function fails
  *
  * Writes an integer value to a property.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_set_int(Object *obj, const char *name, int64_t value,
+bool object_property_set_int(Object *obj, const char *name, int64_t value,
  Error **errp);
 
 /**
@@ -1308,8 +1321,10 @@ int64_t object_property_get_int(Object *obj, const char 
*name,
  * @errp: returns an error if this function fails
  *
  * Writes an unsigned integer value to a property.
+ *
+ * Returns: %true on success, %false on failure.
  */
-void object_property_set_uint(Object *obj, const char *name, uint64_t value,
+bool object_property_set_uint(Object *obj, const char *name, uint64_t value,
   

[PATCH v2 37/44] error: Reduce unnecessary error propagation

2020-07-02 Thread Markus Armbruster
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away, even when we need to keep error_propagate() for other
error paths.

Signed-off-by: Markus Armbruster 
---
 block.c | 2 +-
 block/gluster.c | 8 
 block/parallels.c   | 2 +-
 block/quorum.c  | 2 +-
 block/replication.c | 3 +--
 block/vxhs.c| 4 ++--
 hw/core/qdev.c  | 2 +-
 hw/net/virtio-net.c | 4 ++--
 8 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/block.c b/block.c
index 60d2945c2c..2dcf9afd61 100644
--- a/block.c
+++ b/block.c
@@ -6073,7 +6073,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 
 /* Parse -o options */
 if (options) {
-if (!qemu_opts_do_parse(opts, options, NULL, _err)) {
+if (!qemu_opts_do_parse(opts, options, NULL, errp)) {
 goto out;
 }
 }
diff --git a/block/gluster.c b/block/gluster.c
index c620880f27..4f1448e2bc 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -523,7 +523,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster 
*gconf,
 
 /* create opts info from runtime_json_opts list */
 opts = qemu_opts_create(_json_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 goto out;
 }
 
@@ -554,7 +554,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster 
*gconf,
 
 /* create opts info from runtime_type_opts list */
 opts = qemu_opts_create(_type_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, backing_options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
 goto out;
 }
 
@@ -584,7 +584,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster 
*gconf,
 if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
 /* create opts info from runtime_inet_opts list */
 opts = qemu_opts_create(_inet_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, backing_options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
 goto out;
 }
 
@@ -632,7 +632,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster 
*gconf,
 } else {
 /* create opts info from runtime_unix_opts list */
 opts = qemu_opts_create(_unix_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, backing_options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
 goto out;
 }
 
diff --git a/block/parallels.c b/block/parallels.c
index 324085ccea..c259799111 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -827,7 +827,7 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
 goto fail_options;
 }
 
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 goto fail_options;
 }
 
diff --git a/block/quorum.c b/block/quorum.c
index 5d52e605db..6df9449fc2 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -921,7 +921,7 @@ static int quorum_open(BlockDriverState *bs, QDict 
*options, int flags,
 }
 
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
 goto exit;
 }
diff --git a/block/replication.c b/block/replication.c
index dcd430624e..0c70215784 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -85,7 +85,6 @@ static int replication_open(BlockDriverState *bs, QDict 
*options,
 {
 int ret;
 BDRVReplicationState *s = bs->opaque;
-Error *local_err = NULL;
 QemuOpts *opts = NULL;
 const char *mode;
 const char *top_id;
@@ -99,7 +98,7 @@ static int replication_open(BlockDriverState *bs, QDict 
*options,
 
 ret = -EINVAL;
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 goto fail;
 }
 
diff --git a/block/vxhs.c b/block/vxhs.c
index fecaeb82c9..dc0e254730 100644
--- a/block/vxhs.c
+++ b/block/vxhs.c
@@ -318,7 +318,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options,
 opts = qemu_opts_create(_opts, NULL, 0, _abort);
 tcp_opts = qemu_opts_create(_tcp_opts, NULL, 0, _abort);
 
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
 goto out;
 }
@@ -345,7 +345,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options,
 /* get the 'server.' arguments */
 qdict_extract_subqdict(options, _options, VXHS_OPT_SERVER".");
 
-if (!qemu_opts_absorb_qdict(tcp_opts, backing_options, _err)) {
+

[PATCH v2 18/44] qapi: Use returned bool to check for failure, manual part

2020-07-02 Thread Markus Armbruster
The previous commit used Coccinelle to convert from checking the Error
object to checking the return value.  Convert a few more manually.
Also tweak control flow in places to conform to the conventional "if
error bail out" pattern.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 accel/kvm/kvm-all.c   | 50 ++-
 block/throttle-groups.c   |  5 ++--
 bootdevice.c  |  4 ++--
 hw/core/qdev-properties.c | 12 +-
 hw/ide/qdev.c |  4 ++--
 hw/mem/nvdimm.c   |  9 +++
 hw/net/ne2000-isa.c   |  4 ++--
 hw/usb/dev-storage.c  |  4 ++--
 net/net.c |  8 ++-
 9 files changed, 44 insertions(+), 56 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 397669231d..83f03b2018 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3128,37 +3128,33 @@ static void kvm_set_kernel_irqchip(Object *obj, Visitor 
*v,
const char *name, void *opaque,
Error **errp)
 {
-Error *err = NULL;
 KVMState *s = KVM_STATE(obj);
 OnOffSplit mode;
 
-visit_type_OnOffSplit(v, name, , );
-if (err) {
-error_propagate(errp, err);
+if (!visit_type_OnOffSplit(v, name, , errp)) {
 return;
-} else {
-switch (mode) {
-case ON_OFF_SPLIT_ON:
-s->kernel_irqchip_allowed = true;
-s->kernel_irqchip_required = true;
-s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
-break;
-case ON_OFF_SPLIT_OFF:
-s->kernel_irqchip_allowed = false;
-s->kernel_irqchip_required = false;
-s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
-break;
-case ON_OFF_SPLIT_SPLIT:
-s->kernel_irqchip_allowed = true;
-s->kernel_irqchip_required = true;
-s->kernel_irqchip_split = ON_OFF_AUTO_ON;
-break;
-default:
-/* The value was checked in visit_type_OnOffSplit() above. If
- * we get here, then something is wrong in QEMU.
- */
-abort();
-}
+}
+switch (mode) {
+case ON_OFF_SPLIT_ON:
+s->kernel_irqchip_allowed = true;
+s->kernel_irqchip_required = true;
+s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
+break;
+case ON_OFF_SPLIT_OFF:
+s->kernel_irqchip_allowed = false;
+s->kernel_irqchip_required = false;
+s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
+break;
+case ON_OFF_SPLIT_SPLIT:
+s->kernel_irqchip_allowed = true;
+s->kernel_irqchip_required = true;
+s->kernel_irqchip_split = ON_OFF_AUTO_ON;
+break;
+default:
+/* The value was checked in visit_type_OnOffSplit() above. If
+ * we get here, then something is wrong in QEMU.
+ */
+abort();
 }
 }
 
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index bb242fde1a..e411051160 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -895,8 +895,8 @@ static void throttle_group_set_limits(Object *obj, Visitor 
*v,
 ThrottleLimits *argp;
 Error *local_err = NULL;
 
-if (!visit_type_ThrottleLimits(v, name, , _err)) {
-goto ret;
+if (!visit_type_ThrottleLimits(v, name, , errp)) {
+return;
 }
 qemu_mutex_lock(>lock);
 throttle_get_config(>ts, );
@@ -908,7 +908,6 @@ static void throttle_group_set_limits(Object *obj, Visitor 
*v,
 
 unlock:
 qemu_mutex_unlock(>lock);
-ret:
 qapi_free_ThrottleLimits(argp);
 error_propagate(errp, local_err);
 return;
diff --git a/bootdevice.c b/bootdevice.c
index fb09d3c668..769f40c77d 100644
--- a/bootdevice.c
+++ b/bootdevice.c
@@ -297,8 +297,8 @@ static void device_set_bootindex(Object *obj, Visitor *v, 
const char *name,
 int32_t boot_index;
 Error *local_err = NULL;
 
-if (!visit_type_int32(v, name, _index, _err)) {
-goto out;
+if (!visit_type_int32(v, name, _index, errp)) {
+return;
 }
 /* check whether bootindex is present in fw_boot_order list  */
 check_boot_index(boot_index, _err);
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index c1a0f910d8..e4dd9ff6b2 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -672,15 +672,15 @@ static void set_pci_devfn(Object *obj, Visitor *v, const 
char *name,
 if (!visit_type_str(v, name, , _err)) {
 error_free(local_err);
 local_err = NULL;
-visit_type_int32(v, name, , _err);
-if (local_err) {
-error_propagate(errp, local_err);
-} else if (value < -1 || value > 255) {
+if (!visit_type_int32(v, name, , errp)) {
+return;
+}
+if (value < -1 || value > 255) {
 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "pci_devfn");
-} 

[PATCH v2 07/44] qemu-option: Make uses of find_desc_by_name() more similar

2020-07-02 Thread Markus Armbruster
This is to make the next commit easier to review.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 util/qemu-option.c | 32 ++--
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/util/qemu-option.c b/util/qemu-option.c
index fd1fd23521..1df55bc881 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -270,6 +270,7 @@ static void qemu_opt_del_all(QemuOpts *opts, const char 
*name)
 const char *qemu_opt_get(QemuOpts *opts, const char *name)
 {
 QemuOpt *opt;
+const QemuOptDesc *desc;
 
 if (opts == NULL) {
 return NULL;
@@ -277,7 +278,7 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
 
 opt = qemu_opt_find(opts, name);
 if (!opt) {
-const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
+desc = find_desc_by_name(opts->list->desc, name);
 if (desc && desc->def_value_str) {
 return desc->def_value_str;
 }
@@ -348,6 +349,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const 
char *name,
  bool defval, bool del)
 {
 QemuOpt *opt;
+const QemuOptDesc *desc;
 bool ret = defval;
 
 if (opts == NULL) {
@@ -356,7 +358,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const 
char *name,
 
 opt = qemu_opt_find(opts, name);
 if (opt == NULL) {
-const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
+desc = find_desc_by_name(opts->list->desc, name);
 if (desc && desc->def_value_str) {
 parse_option_bool(name, desc->def_value_str, , _abort);
 }
@@ -384,6 +386,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, 
const char *name,
uint64_t defval, bool del)
 {
 QemuOpt *opt;
+const QemuOptDesc *desc;
 uint64_t ret = defval;
 
 if (opts == NULL) {
@@ -392,7 +395,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, 
const char *name,
 
 opt = qemu_opt_find(opts, name);
 if (opt == NULL) {
-const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
+desc = find_desc_by_name(opts->list->desc, name);
 if (desc && desc->def_value_str) {
 parse_option_number(name, desc->def_value_str, , _abort);
 }
@@ -421,6 +424,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, 
const char *name,
  uint64_t defval, bool del)
 {
 QemuOpt *opt;
+const QemuOptDesc *desc;
 uint64_t ret = defval;
 
 if (opts == NULL) {
@@ -429,7 +433,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, 
const char *name,
 
 opt = qemu_opt_find(opts, name);
 if (opt == NULL) {
-const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
+desc = find_desc_by_name(opts->list->desc, name);
 if (desc && desc->def_value_str) {
 parse_option_size(name, desc->def_value_str, , _abort);
 }
@@ -540,18 +544,18 @@ void qemu_opt_set_bool(QemuOpts *opts, const char *name, 
bool val,
Error **errp)
 {
 QemuOpt *opt;
-const QemuOptDesc *desc = opts->list->desc;
+const QemuOptDesc *desc;
 
-opt = g_malloc0(sizeof(*opt));
-opt->desc = find_desc_by_name(desc, name);
-if (!opt->desc && !opts_accepts_any(opts)) {
+desc = find_desc_by_name(opts->list->desc, name);
+if (!desc && !opts_accepts_any(opts)) {
 error_setg(errp, QERR_INVALID_PARAMETER, name);
-g_free(opt);
 return;
 }
 
+opt = g_malloc0(sizeof(*opt));
 opt->name = g_strdup(name);
 opt->opts = opts;
+opt->desc = desc;
 opt->value.boolean = !!val;
 opt->str = g_strdup(val ? "on" : "off");
 QTAILQ_INSERT_TAIL(>head, opt, next);
@@ -561,18 +565,18 @@ void qemu_opt_set_number(QemuOpts *opts, const char 
*name, int64_t val,
  Error **errp)
 {
 QemuOpt *opt;
-const QemuOptDesc *desc = opts->list->desc;
+const QemuOptDesc *desc;
 
-opt = g_malloc0(sizeof(*opt));
-opt->desc = find_desc_by_name(desc, name);
-if (!opt->desc && !opts_accepts_any(opts)) {
+desc = find_desc_by_name(opts->list->desc, name);
+if (!desc && !opts_accepts_any(opts)) {
 error_setg(errp, QERR_INVALID_PARAMETER, name);
-g_free(opt);
 return;
 }
 
+opt = g_malloc0(sizeof(*opt));
 opt->name = g_strdup(name);
 opt->opts = opts;
+opt->desc = desc;
 opt->value.uint = val;
 opt->str = g_strdup_printf("%" PRId64, val);
 QTAILQ_INSERT_TAIL(>head, opt, next);
-- 
2.26.2




Re: [PATCH v2 00/44] Less clumsy error checking

2020-07-02 Thread Markus Armbruster
diff -w between v1 rebased and v2, with:

diff --git a/include/qapi/error.h b/include/qapi/error.h
index c3d84d610a..5ceb3ace06 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -145,10 +145,10 @@
  * Likewise, do *not*
  * Error *err = NULL;
  * if (cond1) {
- * error_setg(err, ...);
+ * error_setg(, ...);
  * }
  * if (cond2) {
- * error_setg(err, ...); // WRONG!
+ * error_setg(, ...); // WRONG!
  * }
  * because this may pass a non-null err to error_setg().
  */
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 7d1b8d579c..ebc19ede7f 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -284,7 +284,7 @@ void visit_free(Visitor *v);
  * On failure, set *@obj to NULL and store an error through @errp.
  * Can happen only when @v is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * After visit_start_struct() succeeds, the caller may visit its
  * members one after the other, passing the member's name and address
@@ -304,7 +304,7 @@ bool visit_start_struct(Visitor *v, const char *name, void 
**obj,
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * Should be called prior to visit_end_struct() if all other
  * intermediate visit steps were successful, to allow the visitor one
@@ -343,7 +343,7 @@ void visit_end_struct(Visitor *v, void **obj);
  * On failure, set *@list to NULL and store an error through @errp.
  * Can happen only when @v is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * After visit_start_list() succeeds, the caller may visit its members
  * one after the other.  A real visit (where @list is non-NULL) uses
@@ -380,7 +380,7 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, 
size_t size);
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * Should be called prior to visit_end_list() if all other
  * intermediate visit steps were successful, to allow the visitor one
@@ -418,7 +418,7 @@ void visit_end_list(Visitor *v, void **list);
  * On failure, set *@obj to NULL and store an error through @errp.
  * Can happen only when @v is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * If successful, this must be paired with visit_end_alternate() with
  * the same @obj to clean up, even if visiting the contents of the
@@ -476,7 +476,7 @@ bool visit_optional(Visitor *v, const char *name, bool 
*present);
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * May call visit_type_str() under the hood, and the enum visit may
  * fail even if the corresponding string visit succeeded; this implies
@@ -510,7 +510,7 @@ bool visit_is_dealloc(Visitor *v);
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  */
 bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp);
 
@@ -591,7 +591,7 @@ bool visit_type_size(Visitor *v, const char *name, uint64_t 
*obj,
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  */
 bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp);
 
@@ -612,7 +612,7 @@ bool visit_type_bool(Visitor *v, const char *name, bool 
*obj, Error **errp);
  * On failure, set *@obj to NULL and store an error through @errp.
  * Can happen only when @v is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * FIXME: Callers that try to output NULL *obj should not be allowed.
  */
@@ -631,7 +631,7 @@ bool visit_type_str(Visitor *v, const char *name, char 
**obj, Error **errp);
  * On failure, store an error through @errp.  Can happen only when @v
  * is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  */
 bool visit_type_number(Visitor *v, const char *name, double *obj,
Error **errp);
@@ -649,7 +649,7 @@ bool visit_type_number(Visitor *v, const char *name, double 
*obj,
  * On failure, set *@obj to NULL and store an error through @errp.
  * Can happen only when @v is an input visitor.
  *
- * Return true on succes, false on failure.
+ * Return true on success, false on failure.
  *
  * Note 

[PATCH v2 33/44] error: Avoid unnecessary error_propagate() after error_setg()

2020-07-02 Thread Markus Armbruster
Replace

error_setg(, ...);
error_propagate(errp, err);

by

error_setg(errp, ...);

Related pattern:

if (...) {
error_setg(, ...);
goto out;
}
...
 out:
error_propagate(errp, err);
return;

When all paths to label out are that way, replace by

if (...) {
error_setg(errp, ...);
return;
}

and delete the label along with the error_propagate().

When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.

foo(..., );
if (err) {
goto out;
}
...
bar(..., );
 out:
error_propagate(errp, err);
return;

move the error_propagate() to where it's needed, like

if (...) {
foo(..., );
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;

and transform the error_setg() as above.

Bonus: the elimination of gotos will make later patches in this series
easier to review.

Candidates for conversion tracked down with this Coccinelle script:

@@
identifier err, errp;
expression list args;
@@
-error_setg(, args);
+error_setg(errp, args);
 ... when != err
 error_propagate(errp, err);

Signed-off-by: Markus Armbruster 
---
 backends/cryptodev.c| 11 +++---
 backends/hostmem-file.c | 19 +++---
 backends/hostmem-memfd.c| 15 
 backends/hostmem.c  | 27 ++
 block/quorum.c  | 16 
 block/replication.c | 11 +++---
 block/throttle-groups.c | 22 +--
 block/vxhs.c|  9 ++---
 hw/acpi/core.c  | 15 +++-
 hw/hyperv/vmbus.c   |  5 +--
 hw/i386/pc.c| 35 ++
 hw/mem/nvdimm.c | 17 -
 hw/mem/pc-dimm.c| 14 +++
 hw/misc/aspeed_sdmc.c   |  3 +-
 hw/ppc/rs6000_mc.c  |  9 ++---
 hw/ppc/spapr.c  | 73 -
 hw/ppc/spapr_pci.c  | 14 +++
 hw/s390x/ipl.c  | 23 +---
 hw/xen/xen_pt_config_init.c |  3 +-
 iothread.c  | 12 +++---
 net/colo-compare.c  | 20 --
 net/dump.c  | 10 ++---
 net/filter-buffer.c | 10 ++---
 qga/commands-win32.c| 19 +++---
 24 files changed, 169 insertions(+), 243 deletions(-)

diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 72b7077475..4de378532b 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -158,16 +158,15 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, 
const char *name,
 uint32_t value;
 
 if (!visit_type_uint32(v, name, , _err)) {
-goto out;
+error_propagate(errp, local_err);
+return;
 }
 if (!value) {
-error_setg(_err, "Property '%s.%s' doesn't take value '%"
-   PRIu32 "'", object_get_typename(obj), name, value);
-goto out;
+error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
+   object_get_typename(obj), name, value);
+return;
 }
 backend->conf.peers.queues = value;
-out:
-error_propagate(errp, local_err);
 }
 
 static void
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index 320dffbaa9..a44f5a61ac 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -114,18 +114,16 @@ static void file_memory_backend_set_align(Object *o, 
Visitor *v,
 uint64_t val;
 
 if (host_memory_backend_mr_inited(backend)) {
-error_setg(_err, "cannot change property '%s' of %s",
-   name, object_get_typename(o));
-goto out;
+error_setg(errp, "cannot change property '%s' of %s", name,
+   object_get_typename(o));
+return;
 }
 
 if (!visit_type_size(v, name, , _err)) {
-goto out;
+error_propagate(errp, local_err);
+return;
 }
 fb->align = val;
-
- out:
-error_propagate(errp, local_err);
 }
 
 static bool file_memory_backend_get_pmem(Object *o, Error **errp)
@@ -139,7 +137,6 @@ static void file_memory_backend_set_pmem(Object *o, bool 
value, Error **errp)
 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
 
 if (host_memory_backend_mr_inited(backend)) {
-
 error_setg(errp, "cannot change property 'pmem' of %s.",
object_get_typename(o));
 return;
@@ -147,13 +144,9 @@ static void file_memory_backend_set_pmem(Object *o, bool 
value, Error **errp)
 
 #ifndef CONFIG_LIBPMEM
 if (value) {
-Error *local_err = NULL;
-
-error_setg(_err,
-   "Lack of libpmem support while setting the 'pmem=on'"
+error_setg(errp, "Lack of libpmem support while setting the 'pmem=on'"
" of %s. We can't ensure data persistence.",
object_get_typename(o));
-error_propagate(errp, local_err);
 return;
   

[PATCH v2 16/44] qapi: Make visitor functions taking Error ** return bool, not void

2020-07-02 Thread Markus Armbruster
See recent commit "error: Document Error API usage rules" for
rationale.

Signed-off-by: Markus Armbruster 
---
 docs/devel/qapi-code-gen.txt  |  51 +--
 include/qapi/clone-visitor.h  |   8 +-
 include/qapi/visitor-impl.h   |  26 +++---
 include/qapi/visitor.h| 102 -
 audio/audio_legacy.c  |  15 ++--
 qapi/opts-visitor.c   |  58 +++-
 qapi/qapi-clone-visitor.c |  67 --
 qapi/qapi-dealloc-visitor.c   |  27 --
 qapi/qapi-visit-core.c| 165 ++
 qapi/qobject-input-visitor.c  | 109 +-
 qapi/qobject-output-visitor.c |  27 --
 qapi/string-input-visitor.c   |  62 +++--
 qapi/string-output-visitor.c  |  32 ---
 scripts/qapi/visit.py |  58 +---
 14 files changed, 452 insertions(+), 355 deletions(-)

diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index a7794ef658..9bfc57063c 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -1408,42 +1408,38 @@ Example:
 #include "example-qapi-types.h"
 
 
-void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error 
**errp);
-void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, 
Error **errp);
-void visit_type_UserDefOneList(Visitor *v, const char *name, 
UserDefOneList **obj, Error **errp);
+bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error 
**errp);
+bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, 
Error **errp);
+bool visit_type_UserDefOneList(Visitor *v, const char *name, 
UserDefOneList **obj, Error **errp);
 
-void visit_type_q_obj_my_command_arg_members(Visitor *v, 
q_obj_my_command_arg *obj, Error **errp);
+bool visit_type_q_obj_my_command_arg_members(Visitor *v, 
q_obj_my_command_arg *obj, Error **errp);
 
 #endif /* EXAMPLE_QAPI_VISIT_H */
 $ cat qapi-generated/example-qapi-visit.c
 [Uninteresting stuff omitted...]
 
-void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error 
**errp)
+bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error 
**errp)
 {
 Error *err = NULL;
 
-visit_type_int(v, "integer", >integer, );
-if (err) {
-goto out;
+if (!visit_type_int(v, "integer", >integer, errp)) {
+return false;
 }
 if (visit_optional(v, "string", >has_string)) {
-visit_type_str(v, "string", >string, );
-if (err) {
-goto out;
+if (!visit_type_str(v, "string", >string, errp)) {
+return false;
 }
 }
-
-out:
 error_propagate(errp, err);
+return !err;
 }
 
-void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, 
Error **errp)
+bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, 
Error **errp)
 {
 Error *err = NULL;
 
-visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), );
-if (err) {
-goto out;
+if (!visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), 
errp)) {
+return false;
 }
 if (!*obj) {
 /* incomplete */
@@ -1461,19 +1457,18 @@ Example:
 qapi_free_UserDefOne(*obj);
 *obj = NULL;
 }
-out:
 error_propagate(errp, err);
+return !err;
 }
 
-void visit_type_UserDefOneList(Visitor *v, const char *name, 
UserDefOneList **obj, Error **errp)
+bool visit_type_UserDefOneList(Visitor *v, const char *name, 
UserDefOneList **obj, Error **errp)
 {
 Error *err = NULL;
 UserDefOneList *tail;
 size_t size = sizeof(**obj);
 
-visit_start_list(v, name, (GenericList **)obj, size, );
-if (err) {
-goto out;
+if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
+return false;
 }
 
 for (tail = *obj; tail;
@@ -1492,21 +1487,19 @@ Example:
 qapi_free_UserDefOneList(*obj);
 *obj = NULL;
 }
-out:
 error_propagate(errp, err);
+return !err;
 }
 
-void visit_type_q_obj_my_command_arg_members(Visitor *v, 
q_obj_my_command_arg *obj, Error **errp)
+bool visit_type_q_obj_my_command_arg_members(Visitor *v, 
q_obj_my_command_arg *obj, Error **errp)
 {
 Error *err = NULL;
 
-visit_type_UserDefOneList(v, "arg1", >arg1, );
-if (err) {
-goto out;
+if (!visit_type_UserDefOneList(v, "arg1", >arg1, errp)) {
+return false;
 }
-
-out:
 error_propagate(errp, err);
+return !err;
 }
 
 [Uninteresting stuff omitted...]
diff --git a/include/qapi/clone-visitor.h b/include/qapi/clone-visitor.h
index 5b665ee38c..adf9a788e2 100644
--- a/include/qapi/clone-visitor.h
+++ 

[PATCH v2 10/44] qemu-option: Factor out helper opt_create()

2020-07-02 Thread Markus Armbruster
There is just one use so far.  The next commit will add more.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 util/qemu-option.c | 27 ++-
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/util/qemu-option.c b/util/qemu-option.c
index e7b540a21b..1023fe7527 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -499,6 +499,23 @@ int qemu_opt_unset(QemuOpts *opts, const char *name)
 }
 }
 
+static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value,
+   bool prepend)
+{
+QemuOpt *opt = g_malloc0(sizeof(*opt));
+
+opt->name = g_strdup(name);
+opt->str = value;
+opt->opts = opts;
+if (prepend) {
+QTAILQ_INSERT_HEAD(>head, opt, next);
+} else {
+QTAILQ_INSERT_TAIL(>head, opt, next);
+}
+
+return opt;
+}
+
 static void opt_set(QemuOpts *opts, const char *name, char *value,
 bool prepend, bool *help_wanted, Error **errp)
 {
@@ -516,16 +533,8 @@ static void opt_set(QemuOpts *opts, const char *name, char 
*value,
 return;
 }
 
-opt = g_malloc0(sizeof(*opt));
-opt->name = g_strdup(name);
-opt->opts = opts;
-if (prepend) {
-QTAILQ_INSERT_HEAD(>head, opt, next);
-} else {
-QTAILQ_INSERT_TAIL(>head, opt, next);
-}
+opt = opt_create(opts, name, value, prepend);
 opt->desc = desc;
-opt->str = value;
 qemu_opt_parse(opt, _err);
 if (local_err) {
 error_propagate(errp, local_err);
-- 
2.26.2




[PATCH v2 19/44] block/parallels: Simplify parallels_open() after previous commit

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 block/parallels.c | 7 ++-
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 32d0ecd398..e0ec819550 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -843,6 +843,7 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
_err);
 g_free(buf);
 if (local_err != NULL) {
+error_propagate(errp, local_err);
 goto fail_options;
 }
 
@@ -873,15 +874,11 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
 
 fail_format:
 error_setg(errp, "Image not in Parallels format");
+fail_options:
 ret = -EINVAL;
 fail:
 qemu_vfree(s->header);
 return ret;
-
-fail_options:
-error_propagate(errp, local_err);
-ret = -EINVAL;
-goto fail;
 }
 
 
-- 
2.26.2




[PATCH v2 06/44] qemu-option: Check return value instead of @err where convenient

2020-07-02 Thread Markus Armbruster
Convert uses like

opts = qemu_opts_create(..., );
if (err) {
...
}

to

opts = qemu_opts_create(..., );
if (!opts) {
...
}

Eliminate error_propagate() that are now unnecessary.  Delete @err
that are now unused.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 block/parallels.c  |  4 ++--
 blockdev.c |  5 ++---
 qdev-monitor.c |  5 ++---
 util/qemu-config.c | 10 --
 util/qemu-option.c | 12 
 5 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 63a1cde8af..f26f03c926 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -824,8 +824,8 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
 }
 }
 
-opts = qemu_opts_create(_runtime_opts, NULL, 0, _err);
-if (local_err != NULL) {
+opts = qemu_opts_create(_runtime_opts, NULL, 0, errp);
+if (!opts) {
 goto fail_options;
 }
 
diff --git a/blockdev.c b/blockdev.c
index 31d5eaf6bf..b52ed9de86 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -504,9 +504,8 @@ static BlockBackend *blockdev_init(const char *file, QDict 
*bs_opts,
 /* Check common options by copying from bs_opts to opts, all other options
  * stay in bs_opts for processing by bdrv_open(). */
 id = qdict_get_try_str(bs_opts, "id");
-opts = qemu_opts_create(_common_drive_opts, id, 1, );
-if (error) {
-error_propagate(errp, error);
+opts = qemu_opts_create(_common_drive_opts, id, 1, errp);
+if (!opts) {
 goto err_no_opts;
 }
 
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 13a13a811a..079cb6001e 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -799,9 +799,8 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error 
**errp)
 QemuOpts *opts;
 DeviceState *dev;
 
-opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, errp);
+if (!opts) {
 return;
 }
 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 772f5a219e..c0d0e9b8ef 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -493,9 +493,8 @@ static void config_parse_qdict_section(QDict *options, 
QemuOptsList *opts,
 goto out;
 }
 
-subopts = qemu_opts_create(opts, NULL, 0, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+subopts = qemu_opts_create(opts, NULL, 0, errp);
+if (!subopts) {
 goto out;
 }
 
@@ -538,10 +537,9 @@ static void config_parse_qdict_section(QDict *options, 
QemuOptsList *opts,
 }
 
 opt_name = g_strdup_printf("%s.%u", opts->name, i++);
-subopts = qemu_opts_create(opts, opt_name, 1, _err);
+subopts = qemu_opts_create(opts, opt_name, 1, errp);
 g_free(opt_name);
-if (local_err) {
-error_propagate(errp, local_err);
+if (!subopts) {
 goto out;
 }
 
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 0ebfd97a98..fd1fd23521 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -670,11 +670,9 @@ void qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value, Error **errp)
 {
 QemuOpts *opts;
-Error *local_err = NULL;
 
-opts = qemu_opts_create(list, id, 1, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+opts = qemu_opts_create(list, id, 1, errp);
+if (!opts) {
 return;
 }
 qemu_opt_set(opts, name, value, errp);
@@ -1012,10 +1010,8 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const 
QDict *qdict,
 QemuOpts *opts;
 const QDictEntry *entry;
 
-opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
-_err);
-if (local_err) {
-error_propagate(errp, local_err);
+opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp);
+if (!opts) {
 return NULL;
 }
 
-- 
2.26.2




[PATCH v2 35/44] error: Eliminate error_propagate() with Coccinelle, part 2

2020-07-02 Thread Markus Armbruster
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away.  The previous commit did that with a Coccinelle script I
consider fairly trustworthy.  This commit uses the same script with
the matching of return taken out, i.e. we convert

if (!foo(..., )) {
...
error_propagate(errp, err);
...
}

to

if (!foo(..., errp)) {
...
...
}

This is unsound: @err could still be read between afterwards.  I don't
know how to express "no read of @err without an intervening write" in
Coccinelle.  Instead, I manually double-checked for uses of @err.

Suboptimal line breaks tweaked manually.  qdev_realize() simplified
further to placate scripts/checkpatch.pl.

Signed-off-by: Markus Armbruster 
---
 block.c  |  6 ++
 block/blkdebug.c |  7 ++-
 block/blklogwrites.c |  3 +--
 block/blkverify.c|  3 +--
 block/crypto.c   |  4 +---
 block/file-posix.c   |  6 ++
 block/file-win32.c   |  6 ++
 block/gluster.c  |  4 +---
 block/iscsi.c|  3 +--
 block/nbd.c  |  8 ++--
 block/qcow2.c| 13 -
 block/raw-format.c   |  4 +---
 block/sheepdog.c |  8 ++--
 block/ssh.c  |  4 +---
 block/throttle.c |  4 +---
 block/vmdk.c |  4 +---
 block/vpc.c  |  3 +--
 block/vvfat.c|  3 +--
 blockdev.c   |  3 +--
 hw/intc/xics.c   |  4 +---
 hw/vfio/pci.c|  3 +--
 net/tap.c|  3 +--
 qom/object.c |  4 +---
 23 files changed, 32 insertions(+), 78 deletions(-)

diff --git a/block.c b/block.c
index 7f3091da63..60d2945c2c 100644
--- a/block.c
+++ b/block.c
@@ -1629,8 +1629,7 @@ static int bdrv_open_common(BlockDriverState *bs, 
BlockBackend *file,
 assert(options != NULL && bs->options != options);
 
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
-error_propagate(errp, local_err);
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
 goto fail_opts;
 }
@@ -4090,8 +4089,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, 
BlockReopenQueue *queue,
 
 /* Process generic block layer options */
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, reopen_state->options, _err)) {
-error_propagate(errp, local_err);
+if (!qemu_opts_absorb_qdict(opts, reopen_state->options, errp)) {
 ret = -EINVAL;
 goto error;
 }
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 3c0a9d45cc..9c08d8a005 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -359,7 +359,6 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict 
*options,
 QObject *crumpled_subqdict = NULL;
 Visitor *v = NULL;
 BlockPermissionList *perm_list = NULL, *element;
-Error *local_err = NULL;
 
 *dest = 0;
 
@@ -375,8 +374,7 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict 
*options,
 }
 
 v = qobject_input_visitor_new(crumpled_subqdict);
-if (!visit_type_BlockPermissionList(v, NULL, _list, _err)) {
-error_propagate(errp, local_err);
+if (!visit_type_BlockPermissionList(v, NULL, _list, errp)) {
 ret = -EINVAL;
 goto out;
 }
@@ -471,8 +469,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
*options, int flags,
 uint64_t align;
 
 opts = qemu_opts_create(_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
-error_propagate(errp, local_err);
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
 goto out;
 }
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
index 0c93e926b1..57315f56b4 100644
--- a/block/blklogwrites.c
+++ b/block/blklogwrites.c
@@ -149,9 +149,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict 
*options, int flags,
 bool log_append;
 
 opts = qemu_opts_create(_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
-error_propagate(errp, local_err);
 goto fail;
 }
 
diff --git a/block/blkverify.c b/block/blkverify.c
index 666d626c57..4aed53ab59 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -116,8 +116,7 @@ static int blkverify_open(BlockDriverState *bs, QDict 
*options, int flags,
 int ret;
 
 opts = qemu_opts_create(_opts, NULL, 0, _abort);
-if (!qemu_opts_absorb_qdict(opts, options, _err)) {
-error_propagate(errp, local_err);
+if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 ret = -EINVAL;
 goto fail;
 }
diff --git a/block/crypto.c b/block/crypto.c
index 301fa4da8e..5b2b97ea2f 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -212,7 +212,6 @@ static int block_crypto_open_generic(QCryptoBlockFormat 

[PATCH v2 15/44] hmp: Eliminate a variable in hmp_migrate_set_parameter()

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 monitor/hmp-cmds.c | 8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 2b0b58a336..d7810cb564 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1247,7 +1247,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict 
*qdict)
 MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
 uint64_t valuebw = 0;
 uint64_t cache_size;
-MultiFDCompression compress_type;
 Error *err = NULL;
 int val, ret;
 
@@ -1343,11 +1342,8 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict 
*qdict)
 break;
 case MIGRATION_PARAMETER_MULTIFD_COMPRESSION:
 p->has_multifd_compression = true;
-visit_type_MultiFDCompression(v, param, _type, );
-if (err) {
-break;
-}
-p->multifd_compression = compress_type;
+visit_type_MultiFDCompression(v, param, >multifd_compression,
+  );
 break;
 case MIGRATION_PARAMETER_MULTIFD_ZLIB_LEVEL:
 p->has_multifd_zlib_level = true;
-- 
2.26.2




[PATCH v2 42/44] qemu-img: Ignore Error objects where the return value suffices

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 qemu-img.c | 8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 27bf94e7ae..c11bfe0268 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -464,22 +464,18 @@ static int add_old_style_options(const char *fmt, 
QemuOpts *opts,
  const char *base_filename,
  const char *base_fmt)
 {
-Error *err = NULL;
-
 if (base_filename) {
 if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename,
-  )) {
+  NULL)) {
 error_report("Backing file not supported for file format '%s'",
  fmt);
-error_free(err);
 return -1;
 }
 }
 if (base_fmt) {
-if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, )) {
+if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, NULL)) {
 error_report("Backing file format not supported for file "
  "format '%s'", fmt);
-error_free(err);
 return -1;
 }
 }
-- 
2.26.2




[PATCH v2 22/44] qom: Rename qdev_get_type() to object_get_type()

2020-07-02 Thread Markus Armbruster
Commit 2f262e06f0 lifted qdev_get_type() from qdev to object without
renaming it accordingly.  Do that now.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Philippe Mathieu-Daudé 
---
 qom/object.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qom/object.c b/qom/object.c
index 87ee0b5a81..0808da2767 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -2365,7 +2365,7 @@ object_class_property_add_tm(ObjectClass *klass, const 
char *name,
  NULL, NULL, prop);
 }
 
-static char *qdev_get_type(Object *obj, Error **errp)
+static char *object_get_type(Object *obj, Error **errp)
 {
 return g_strdup(object_get_typename(obj));
 }
@@ -2716,7 +2716,7 @@ void object_class_property_set_description(ObjectClass 
*klass,
 
 static void object_class_init(ObjectClass *klass, void *data)
 {
-object_class_property_add_str(klass, "type", qdev_get_type,
+object_class_property_add_str(klass, "type", object_get_type,
   NULL);
 }
 
-- 
2.26.2




[PATCH v2 44/44] hmp: Ignore Error objects where the return value suffices

2020-07-02 Thread Markus Armbruster
qdev_print_props() receives and throws away Error objects just to
check for object_property_get_str() and object_property_print()
failure.  Unnecessary, both return suitable values, so use those
instead.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 qdev-monitor.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/qdev-monitor.c b/qdev-monitor.c
index 2db38b18af..7ebb97cf0d 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -695,22 +695,22 @@ static void qdev_print_props(Monitor *mon, DeviceState 
*dev, Property *props,
 if (!props)
 return;
 for (; props->name; props++) {
-Error *err = NULL;
 char *value;
 char *legacy_name = g_strdup_printf("legacy-%s", props->name);
+
 if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
-value = object_property_get_str(OBJECT(dev), legacy_name, );
+value = object_property_get_str(OBJECT(dev), legacy_name, NULL);
 } else {
-value = object_property_print(OBJECT(dev), props->name, true, 
);
+value = object_property_print(OBJECT(dev), props->name, true,
+  NULL);
 }
 g_free(legacy_name);
 
-if (err) {
-error_free(err);
+if (!value) {
 continue;
 }
 qdev_printf("%s = %s\n", props->name,
-value && *value ? value : "");
+*value ? value : "");
 g_free(value);
 }
 }
-- 
2.26.2




[PATCH v2 00/44] Less clumsy error checking

2020-07-02 Thread Markus Armbruster
When the Error API was created, we adopted the (unwritten) rule to
return void when the function returns no useful value on success,
unlike GError, which recommends to return true on success and false on
error then.

When a function returns a distinct error value, say false, a checked
call that passes the error up looks like

if (!frobnicate(..., errp)) {
handle the error...
}

When it returns void, we need

Error *err = NULL;

frobnicate(..., );
if (err) {
handle the error...
error_propagate(errp, err);
}

Not only is this more verbose, it also creates an Error object even
when @errp is null, _abort or _fatal.

People got tired of the additional boilerplate, and started to ignore
the unwritten rule.  The result is confusion among developers about
the preferred usage.

This series adopts the GError rule (in writing), and updates a
substantial amount of code to honor the rule.  Cuts the number of
error_propagate() calls nearly by half.  The diffstat speaks for
itself.

Based on my "[PULL 00/28] Error reporting patches patches for
2020-07-02".  Also available from my public repository
https://repo.or.cz/qemu/armbru.git on branch error-smooth.

Based-on: Message-Id: <20200702110931.2953148-1-arm...@redhat.com>

v2:
* Rebased
* Coccinelle scripts reworked, patches sliced and diced for
  reviewability:
  Old PATCH 03+17+23-24+35+38-39+42 split into "Use returned bool to
  check for failure" parts [PATCH 03+13+17-18+25+28-29+42], and
  "Eliminate error_propagate()" parts.  The latter combined with old
  PATCH 06-07+18-19+29+43 are now [PATCH 33-37].  The end result is
  almost identical.  Some R-bys dropped; sorry!
* Drop variables as they become unused [Vladimir]
* PATCH 01: Comment typos fixed [Greg]
* PATCH 09: Simplify further by cutting out variables [Eric]
* PATCH 11: opt_set() renamed to opt_validate(), redundant parameter
  dropped [Vladimir], R-by kept
* PATCH 16: Comment typos fixed, indentation tidied up [Eric]
* PATCH 23: Assertion dropped [Eric], incorrect hunk backed out
* PATCH 26: Regenerated after rebase; note additional Coccinelle
  hiccup in the commit message
* PATCH 27: Indentation tiedied up [Eric]
* Left for later: followup to fix nearby typos and such [Eric]

Markus Armbruster (44):
  error: Improve examples in error.h's big comment
  error: Document Error API usage rules
  qdev: Use returned bool to check for qdev_realize() etc. failure
  macio: Tidy up error handling in macio_newworld_realize()
  virtio-crypto-pci: Tidy up virtio_crypto_pci_realize()
  qemu-option: Check return value instead of @err where convenient
  qemu-option: Make uses of find_desc_by_name() more similar
  qemu-option: Factor out helper find_default_by_name()
  qemu-option: Simplify around find_default_by_name()
  qemu-option: Factor out helper opt_create()
  qemu-option: Replace opt_set() by cleaner opt_validate()
  qemu-option: Make functions taking Error ** return bool, not void
  qemu-option: Use returned bool to check for failure
  block: Avoid error accumulation in bdrv_img_create()
  hmp: Eliminate a variable in hmp_migrate_set_parameter()
  qapi: Make visitor functions taking Error ** return bool, not void
  qapi: Use returned bool to check for failure, Coccinelle part
  qapi: Use returned bool to check for failure, manual part
  block/parallels: Simplify parallels_open() after previous commit
  s390x/pci: Fix harmless mistake in zpci's property fid's setter
  qom: Use error_reportf_err() instead of g_printerr() in examples
  qom: Rename qdev_get_type() to object_get_type()
  qom: Crash more nicely on object_property_get_link() failure
  qom: Don't handle impossible object_property_get_link() failure
  qom: Use return values to check for error where that's simpler
  qom: Put name parameter before value / visitor parameter
  qom: Make functions taking Error ** return bool, not void
  qom: Use returned bool to check for failure, Coccinelle part
  qom: Use returned bool to check for failure, manual part
  qom: Make functions taking Error ** return bool, not 0/-1
  qdev: Make functions taking Error ** return bool, not void
  qdev: Use returned bool to check for failure, Coccinelle part
  error: Avoid unnecessary error_propagate() after error_setg()
  error: Eliminate error_propagate() with Coccinelle, part 1
  error: Eliminate error_propagate() with Coccinelle, part 2
  error: Eliminate error_propagate() manually
  error: Reduce unnecessary error propagation
  qapi: Smooth another visitor error checking pattern
  qapi: Smooth visitor error checking in generated code
  qapi: Purge error_propagate() from QAPI core
  error: Avoid error_propagate() after migrate_add_blocker()
  qemu-img: Ignore Error objects where the return value suffices
  qdev: Ignore Error objects where the return value suffices
  hmp: Ignore Error objects where the return value suffices

 docs/devel/qapi-code-gen.txt | 103 -
 include/hw/audio/pcspk.h |   2 +-
 

[PATCH v2 32/44] qdev: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Markus Armbruster
The previous commit enables conversion of

qdev_prop_set_drive_err(..., );
if (err) {
...
}

to

if (!qdev_prop_set_drive_err(..., errp)) {
...
}

Coccinelle script:

@@
identifier fun = qdev_prop_set_drive_err;
expression list args;
typedef Error;
Error *err;
@@
-fun(args, );
-if (err)
+if (!fun(args, ))
 {
 ...
 }

One line break tidied up manually.

Signed-off-by: Markus Armbruster 
---
 hw/scsi/scsi-bus.c | 3 +--
 hw/sd/sd.c | 3 +--
 hw/sd/ssi-sd.c | 5 ++---
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index a83939f7d0..38b66a2f45 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -277,8 +277,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, 
BlockBackend *blk,
 if (serial && object_property_find(OBJECT(dev), "serial", NULL)) {
 qdev_prop_set_string(dev, "serial", serial);
 }
-qdev_prop_set_drive_err(dev, "drive", blk, );
-if (err) {
+if (!qdev_prop_set_drive_err(dev, "drive", blk, )) {
 error_propagate(errp, err);
 object_unparent(OBJECT(dev));
 return NULL;
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 97a9d32964..5137168d66 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -706,8 +706,7 @@ SDState *sd_init(BlockBackend *blk, bool is_spi)
 
 obj = object_new(TYPE_SD_CARD);
 dev = DEVICE(obj);
-qdev_prop_set_drive_err(dev, "drive", blk, );
-if (err) {
+if (!qdev_prop_set_drive_err(dev, "drive", blk, )) {
 error_reportf_err(err, "sd_init failed: ");
 return NULL;
 }
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 4d91f603fa..e0fb9f3093 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -254,9 +254,8 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
 dinfo = drive_get_next(IF_SD);
 carddev = qdev_new(TYPE_SD_CARD);
 if (dinfo) {
-qdev_prop_set_drive_err(carddev, "drive", blk_by_legacy_dinfo(dinfo),
-);
-if (err) {
+if (!qdev_prop_set_drive_err(carddev, "drive",
+ blk_by_legacy_dinfo(dinfo), )) {
 goto fail;
 }
 }
-- 
2.26.2




[PATCH v2 31/44] qdev: Make functions taking Error ** return bool, not void

2020-07-02 Thread Markus Armbruster
See recent commit "error: Document Error API usage rules" for
rationale.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 include/hw/qdev-properties.h | 4 ++--
 hw/core/qdev-properties-system.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 49c6cd2460..f12ab9e6bc 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -236,8 +236,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
 /*
  * Set properties between creation and realization.
  */
-void qdev_prop_set_drive_err(DeviceState *dev, const char *name,
- BlockBackend *value, Error **errp);
+bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
+ BlockBackend *value, Error **errp);
 
 /*
  * Set properties between creation and realization.
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 810831b1df..7d2387f22c 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -421,7 +421,7 @@ const PropertyInfo qdev_prop_audiodev = {
 .set = set_audiodev,
 };
 
-void qdev_prop_set_drive_err(DeviceState *dev, const char *name,
+bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
  BlockBackend *value, Error **errp)
 {
 const char *ref = "";
@@ -436,7 +436,7 @@ void qdev_prop_set_drive_err(DeviceState *dev, const char 
*name,
 }
 }
 
-object_property_set_str(OBJECT(dev), name, ref, errp);
+return object_property_set_str(OBJECT(dev), name, ref, errp);
 }
 
 void qdev_prop_set_drive(DeviceState *dev, const char *name,
-- 
2.26.2




[PATCH v2 12/44] qemu-option: Make functions taking Error ** return bool, not void

2020-07-02 Thread Markus Armbruster
See recent commit "error: Document Error API usage rules" for
rationale.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 include/qemu/option.h | 16 
 blockdev.c|  5 ++-
 util/qemu-option.c| 92 +--
 3 files changed, 64 insertions(+), 49 deletions(-)

diff --git a/include/qemu/option.h b/include/qemu/option.h
index eb4097889d..2d77b10f90 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -30,7 +30,7 @@
 
 const char *get_opt_value(const char *p, char **value);
 
-void parse_option_size(const char *name, const char *value,
+bool parse_option_size(const char *name, const char *value,
uint64_t *ret, Error **errp);
 bool has_help_option(const char *param);
 
@@ -80,11 +80,11 @@ uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char 
*name,
 uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
uint64_t defval);
 int qemu_opt_unset(QemuOpts *opts, const char *name);
-void qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
+bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
   Error **errp);
-void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
+bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
Error **errp);
-void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
+bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
  Error **errp);
 typedef int (*qemu_opt_loopfunc)(void *opaque,
  const char *name, const char *value,
@@ -106,13 +106,13 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char 
*id,
int fail_if_exists, Error **errp);
 void qemu_opts_reset(QemuOptsList *list);
 void qemu_opts_loc_restore(QemuOpts *opts);
-void qemu_opts_set(QemuOptsList *list, const char *id,
+bool qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value, Error **errp);
 const char *qemu_opts_id(QemuOpts *opts);
 void qemu_opts_set_id(QemuOpts *opts, char *id);
 void qemu_opts_del(QemuOpts *opts);
-void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp);
-void qemu_opts_do_parse(QemuOpts *opts, const char *params,
+bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp);
+bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
 const char *firstname, Error **errp);
 QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
   bool permit_abbrev);
@@ -125,7 +125,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const 
QDict *qdict,
 QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
QemuOptsList *list, bool del);
 QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
-void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
+bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
 
 typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
 int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
diff --git a/blockdev.c b/blockdev.c
index b52ed9de86..39e12a62b3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -705,7 +705,7 @@ BlockDriverState *bdrv_next_monitor_owned(BlockDriverState 
*bs)
   : QTAILQ_FIRST(_bdrv_states);
 }
 
-static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
+static bool qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
 Error **errp)
 {
 const char *value;
@@ -715,7 +715,7 @@ static void qemu_opt_rename(QemuOpts *opts, const char 
*from, const char *to,
 if (qemu_opt_find(opts, to)) {
 error_setg(errp, "'%s' and its alias '%s' can't be used at the "
"same time", to, from);
-return;
+return false;
 }
 }
 
@@ -724,6 +724,7 @@ static void qemu_opt_rename(QemuOpts *opts, const char 
*from, const char *to,
 qemu_opt_set(opts, to, value, _abort);
 qemu_opt_unset(opts, from);
 }
+return true;
 }
 
 QemuOptsList qemu_legacy_drive_opts = {
diff --git a/util/qemu-option.c b/util/qemu-option.c
index d8233b3b35..2f4fb62120 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -96,7 +96,7 @@ const char *get_opt_value(const char *p, char **value)
 return offset;
 }
 
-static void parse_option_bool(const char *name, const char *value, bool *ret,
+static bool parse_option_bool(const char *name, const char *value, bool *ret,
   Error **errp)
 {
 if (!strcmp(value, "on")) {
@@ -106,10 +106,12 @@ static void parse_option_bool(const char *name, const 
char *value, bool *ret,
 } else 

[PATCH v2 20/44] s390x/pci: Fix harmless mistake in zpci's property fid's setter

2020-07-02 Thread Markus Armbruster
s390_pci_set_fid() sets zpci->fid_defined to true even when
visit_type_uint32() failed.  Reproducer: "-device zpci,fid=junk".
Harmless in practice, because qdev_device_add() then fails, throwing
away @zpci.  Fix it anyway.

Cc: Matthew Rosato 
Cc: Cornelia Huck 
Signed-off-by: Markus Armbruster 
Reviewed-by: Matthew Rosato 
Reviewed-by: Cornelia Huck 
---
 hw/s390x/s390-pci-bus.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 0517901024..07e1e4d7a3 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -1267,7 +1267,9 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, 
const char *name,
 return;
 }
 
-visit_type_uint32(v, name, ptr, errp);
+if (!visit_type_uint32(v, name, ptr, errp)) {
+return;
+}
 zpci->fid_defined = true;
 }
 
-- 
2.26.2




[PATCH v2 43/44] qdev: Ignore Error objects where the return value suffices

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 hw/core/qdev-properties.c | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index e1ad147339..8eb4283a56 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -653,7 +653,6 @@ static void set_pci_devfn(Object *obj, Visitor *v, const 
char *name,
 Property *prop = opaque;
 int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
 unsigned int slot, fn, n;
-Error *local_err = NULL;
 char *str;
 
 if (dev->realized) {
@@ -661,9 +660,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, const 
char *name,
 return;
 }
 
-if (!visit_type_str(v, name, , _err)) {
-error_free(local_err);
-local_err = NULL;
+if (!visit_type_str(v, name, , NULL)) {
 if (!visit_type_int32(v, name, , errp)) {
 return;
 }
-- 
2.26.2




[PATCH v2 36/44] error: Eliminate error_propagate() manually

2020-07-02 Thread Markus Armbruster
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away.  The previous two commits did that for sufficiently simple
cases with Coccinelle.  Do it for several more manually.

Signed-off-by: Markus Armbruster 
---
 block/replication.c|  4 +---
 blockdev.c | 16 --
 bootdevice.c   |  6 ++
 dump/dump.c|  7 ++
 hw/block/fdc.c |  8 +++
 hw/core/numa.c | 44 --
 hw/i386/x86.c  |  6 ++
 hw/intc/xive.c | 12 +++
 hw/ppc/spapr_cpu_core.c| 14 
 hw/s390x/s390-pci-bus.c|  4 +---
 hw/s390x/s390-virtio-ccw.c |  6 ++
 hw/s390x/sclp.c| 12 ---
 hw/usb/bus.c   |  4 +---
 qdev-monitor.c | 11 --
 qga/commands-posix.c   |  4 +---
 qom/object.c   |  9 ++--
 qom/qom-qobject.c  |  5 +
 target/i386/cpu.c  | 19 +---
 18 files changed, 56 insertions(+), 135 deletions(-)

diff --git a/block/replication.c b/block/replication.c
index b844a09eb1..dcd430624e 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -367,7 +367,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool 
writable,
 {
 BDRVReplicationState *s = bs->opaque;
 BlockReopenQueue *reopen_queue = NULL;
-Error *local_err = NULL;
 
 if (writable) {
 s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs);
@@ -392,8 +391,7 @@ static void reopen_backing_file(BlockDriverState *bs, bool 
writable,
 }
 
 if (reopen_queue) {
-bdrv_reopen_multiple(reopen_queue, _err);
-error_propagate(errp, local_err);
+bdrv_reopen_multiple(reopen_queue, errp);
 }
 
 bdrv_subtree_drained_end(s->hidden_disk->bs);
diff --git a/blockdev.c b/blockdev.c
index 1f254e7110..59b0b8ffaf 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -793,7 +793,6 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType 
block_default_type,
 bool read_only = false;
 bool copy_on_read;
 const char *filename;
-Error *local_err = NULL;
 int i;
 
 /* Change legacy command line options into QMP ones */
@@ -1003,13 +1002,10 @@ DriveInfo *drive_new(QemuOpts *all_opts, 
BlockInterfaceType block_default_type,
 }
 
 /* Actual block device init: Functionality shared with blockdev-add */
-blk = blockdev_init(filename, bs_opts, _err);
+blk = blockdev_init(filename, bs_opts, errp);
 bs_opts = NULL;
 if (!blk) {
-error_propagate(errp, local_err);
 goto fail;
-} else {
-assert(!local_err);
 }
 
 /* Create legacy DriveInfo */
@@ -3141,9 +3137,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
arg->has_copy_mode, arg->copy_mode,
arg->has_auto_finalize, arg->auto_finalize,
arg->has_auto_dismiss, arg->auto_dismiss,
-   _err);
+   errp);
 bdrv_unref(target_bs);
-error_propagate(errp, local_err);
 out:
 aio_context_release(aio_context);
 }
@@ -3171,7 +3166,6 @@ void qmp_blockdev_mirror(bool has_job_id, const char 
*job_id,
 AioContext *aio_context;
 AioContext *old_context;
 BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
-Error *local_err = NULL;
 bool zero_target;
 int ret;
 
@@ -3213,8 +3207,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char 
*job_id,
has_copy_mode, copy_mode,
has_auto_finalize, auto_finalize,
has_auto_dismiss, auto_dismiss,
-   _err);
-error_propagate(errp, local_err);
+   errp);
 out:
 aio_context_release(aio_context);
 }
@@ -3433,8 +3426,7 @@ void qmp_change_backing_file(const char *device,
 }
 
 if (ro) {
-bdrv_reopen_set_read_only(image_bs, true, _err);
-error_propagate(errp, local_err);
+bdrv_reopen_set_read_only(image_bs, true, errp);
 }
 
 out:
diff --git a/bootdevice.c b/bootdevice.c
index 8185402a5a..add4e3d2d1 100644
--- a/bootdevice.c
+++ b/bootdevice.c
@@ -303,15 +303,13 @@ static void device_set_bootindex(Object *obj, Visitor *v, 
const char *name,
 /* check whether bootindex is present in fw_boot_order list  */
 check_boot_index(boot_index, _err);
 if (local_err) {
-goto out;
+error_propagate(errp, local_err);
+return;
 }
 /* change bootindex to a new one */
 *prop->bootindex = boot_index;
 
 add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix);
-
-out:
-error_propagate(errp, local_err);
 }
 
 static void property_release_bootindex(Object *obj, const char *name,
diff --git a/dump/dump.c b/dump/dump.c
index 

[PATCH v2 23/44] qom: Crash more nicely on object_property_get_link() failure

2020-07-02 Thread Markus Armbruster
Pass _abort instead of NULL where the returned value is
dereferenced or asserted to be non-null.  Drop a now redundant
assertion.

Signed-off-by: Markus Armbruster 
---
 hw/core/platform-bus.c | 6 +++---
 hw/ppc/spapr_drc.c | 3 ++-
 hw/ppc/spapr_hcall.c   | 3 ++-
 hw/ppc/spapr_pci_nvlink2.c | 3 ++-
 ui/vnc.c   | 2 +-
 5 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
index d494e5cec1..5037ca265e 100644
--- a/hw/core/platform-bus.c
+++ b/hw/core/platform-bus.c
@@ -22,6 +22,7 @@
 #include "qemu/osdep.h"
 #include "hw/platform-bus.h"
 #include "hw/qdev-properties.h"
+#include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
 
@@ -63,9 +64,8 @@ hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, 
SysBusDevice *sbdev,
 return -1;
 }
 
-parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
-
-assert(parent_mr);
+parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container",
+ _abort);
 if (parent_mr != pbus_mr_obj) {
 /* MMIO region is not mapped on platform bus */
 return -1;
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index d10193f39e..1f18b79348 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -870,7 +870,8 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, 
uint32_t drc_type_mask)
 continue;
 }
 
-obj = object_property_get_link(root_container, prop->name, NULL);
+obj = object_property_get_link(root_container, prop->name,
+   _abort);
 drc = SPAPR_DR_CONNECTOR(obj);
 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 0f54988f2e..c1d01228c6 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1655,7 +1655,8 @@ static void 
spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
 continue;
 }
 drc = SPAPR_DR_CONNECTOR(object_property_get_link(drc_container,
-  prop->name, NULL));
+  prop->name,
+  _abort));
 
 if (spapr_drc_transient(drc)) {
 spapr_drc_reset(drc);
diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c
index 8332d5694e..dd8cd6db96 100644
--- a/hw/ppc/spapr_pci_nvlink2.c
+++ b/hw/ppc/spapr_pci_nvlink2.c
@@ -358,7 +358,8 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, 
void *fdt)
 for (i = 0; i < sphb->nvgpus->num; ++i) {
 SpaprPhbPciNvGpuSlot *nvslot = >nvgpus->slots[i];
 Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev),
-"nvlink2-mr[0]", NULL);
+"nvlink2-mr[0]",
+_abort);
 uint32_t associativity[] = {
 cpu_to_be32(0x4),
 SPAPR_GPU_NUMA_ID,
diff --git a/ui/vnc.c b/ui/vnc.c
index 527ad25124..f006aa1afd 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -568,7 +568,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
>vencrypt, >has_vencrypt);
 if (vd->dcl.con) {
 dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con),
-  "device", NULL));
+  "device", _abort));
 info->has_display = true;
 info->display = g_strdup(dev->id);
 }
-- 
2.26.2




[PATCH v2 17/44] qapi: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Markus Armbruster
The previous commit enables conversion of

visit_foo(..., );
if (err) {
...
}

to

if (!visit_foo(..., errp)) {
...
}

for visitor functions that now return true / false on success / error.
Coccinelle script:

@@
identifier fun =~ 
"check_list|input_type_enum|lv_start_struct|lv_type_bool|lv_type_int64|lv_type_str|lv_type_uint64|output_type_enum|parse_type_bool|parse_type_int64|parse_type_null|parse_type_number|parse_type_size|parse_type_str|parse_type_uint64|print_type_bool|print_type_int64|print_type_null|print_type_number|print_type_size|print_type_str|print_type_uint64|qapi_clone_start_alternate|qapi_clone_start_list|qapi_clone_start_struct|qapi_clone_type_bool|qapi_clone_type_int64|qapi_clone_type_null|qapi_clone_type_number|qapi_clone_type_str|qapi_clone_type_uint64|qapi_dealloc_start_list|qapi_dealloc_start_struct|qapi_dealloc_type_anything|qapi_dealloc_type_bool|qapi_dealloc_type_int64|qapi_dealloc_type_null|qapi_dealloc_type_number|qapi_dealloc_type_str|qapi_dealloc_type_uint64|qobject_input_check_list|qobject_input_check_struct|qobject_input_start_alternate|qobject_input_start_list|qobject_input_start_struct|qobject_input_type_any|qobject_input_type_bool|qobject_input_type_bool_keyval|qobject_input_type_int64|qobject_input_type_int64_keyval|qobject_input_type_null|qobject_input_type_number|qobject_input_type_number_keyval|qobject_input_type_size_keyval|qobject_input_type_str|qobject_input_type_str_keyval|qobject_input_type_uint64|qobject_input_type_uint64_keyval|qobject_output_start_list|qobject_output_start_struct|qobject_output_type_any|qobject_output_type_bool|qobject_output_type_int64|qobject_output_type_null|qobject_output_type_number|qobject_output_type_str|qobject_output_type_uint64|start_list|visit_check_list|visit_check_struct|visit_start_alternate|visit_start_list|visit_start_struct|visit_type_.*";
expression list args;
typedef Error;
Error *err;
@@
-fun(args, );
-if (err)
+if (!fun(args, ))
 {
 ...
 }

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---
 accel/kvm/kvm-all.c  |  3 +--
 accel/tcg/tcg-all.c  |  3 +--
 backends/cryptodev.c |  3 +--
 backends/hostmem-file.c  |  3 +--
 backends/hostmem-memfd.c |  3 +--
 backends/hostmem.c   |  6 ++---
 backends/tpm/tpm_util.c  |  3 +--
 block/blkdebug.c |  3 +--
 block/nbd.c  |  3 +--
 block/sheepdog.c |  3 +--
 block/throttle-groups.c  |  6 ++---
 bootdevice.c |  3 +--
 hw/block/xen-block.c |  3 +--
 hw/core/machine.c|  3 +--
 hw/core/qdev-properties-system.c | 12 +++--
 hw/core/qdev-properties.c| 38 +++--
 hw/cpu/core.c|  6 ++---
 hw/gpio/aspeed_gpio.c|  3 +--
 hw/i386/pc.c |  3 +--
 hw/ide/qdev.c|  3 +--
 hw/intc/apic_common.c|  3 +--
 hw/mem/nvdimm.c  |  6 ++---
 hw/misc/aspeed_sdmc.c|  3 +--
 hw/misc/pca9552.c|  3 +--
 hw/misc/tmp105.c |  3 +--
 hw/misc/tmp421.c |  3 +--
 hw/net/ne2000-isa.c  |  3 +--
 hw/ppc/spapr_caps.c  |  9 +++
 hw/ppc/spapr_drc.c   | 10 +++-
 hw/s390x/css.c   |  3 +--
 hw/usb/dev-storage.c |  3 +--
 hw/vfio/pci-quirks.c |  3 +--
 hw/virtio/virtio-balloon.c   | 15 
 iothread.c   |  3 +--
 monitor/hmp-cmds.c   |  3 +--
 net/colo-compare.c   |  6 ++---
 net/dump.c   |  3 +--
 net/filter-buffer.c  |  3 +--
 qom/object.c | 42 +++-
 qom/object_interfaces.c  |  3 +--
 target/arm/cpu64.c   |  9 +++
 target/arm/monitor.c |  3 +--
 target/i386/cpu.c| 15 
 target/ppc/compat.c  |  3 +--
 target/s390x/cpu_models.c|  9 +++
 target/sparc/cpu.c   |  3 +--
 46 files changed, 97 insertions(+), 188 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index d54a8701d8..397669231d 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3116,8 +3116,7 @@ static void kvm_set_kvm_shadow_mem(Object *obj, Visitor 
*v,
 Error *error = NULL;
 int64_t value;
 
-visit_type_int(v, name, , );
-if (error) {
+if (!visit_type_int(v, name, , )) {
 error_propagate(errp, error);
 return;
 }
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index 3b4fda5640..d6b3d7fc07 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -185,8 +185,7 @@ static void tcg_set_tb_size(Object *obj, Visitor *v,
 Error *error = NULL;
 uint32_t value;
 
-

[PATCH v2 29/44] qom: Use returned bool to check for failure, manual part

2020-07-02 Thread Markus Armbruster
The previous commit used Coccinelle to convert from checking the Error
object to checking the return value.  Convert a few more manually.

Signed-off-by: Markus Armbruster 
---
 hw/core/bus.c  |  6 +-
 hw/core/qdev.c |  7 +--
 hw/s390x/s390-virtio-ccw.c | 13 +++--
 3 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/hw/core/bus.c b/hw/core/bus.c
index 00d1d31762..6b987b6946 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -166,11 +166,7 @@ BusState *qbus_create(const char *typename, DeviceState 
*parent, const char *nam
 
 bool qbus_realize(BusState *bus, Error **errp)
 {
-Error *err = NULL;
-
-object_property_set_bool(OBJECT(bus), "realized", true, );
-error_propagate(errp, err);
-return !err;
+return object_property_set_bool(OBJECT(bus), "realized", true, errp);
 }
 
 void qbus_unrealize(BusState *bus)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index d6416fb894..17bd8fc2ec 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -386,8 +386,6 @@ void qdev_simple_device_unplug_cb(HotplugHandler 
*hotplug_dev,
  */
 bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
 {
-Error *err = NULL;
-
 assert(!dev->realized && !dev->parent_bus);
 
 if (bus) {
@@ -396,10 +394,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error 
**errp)
 assert(!DEVICE_GET_CLASS(dev)->bus_type);
 }
 
-if (!object_property_set_bool(OBJECT(dev), "realized", true, )) {
-error_propagate(errp, err);
-}
-return !err;
+return object_property_set_bool(OBJECT(dev), "realized", true, errp);
 }
 
 /*
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 62af349c31..f7a68343ef 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -70,19 +70,20 @@ static S390CPU *s390x_new_cpu(const char *typename, 
uint32_t core_id,
 {
 S390CPU *cpu = S390_CPU(object_new(typename));
 Error *err = NULL;
+S390CPU *ret = NULL;
 
 if (!object_property_set_int(OBJECT(cpu), "core-id", core_id, )) {
 goto out;
 }
-qdev_realize(DEVICE(cpu), NULL, );
+if (!qdev_realize(DEVICE(cpu), NULL, )) {
+goto out;
+}
+ret = cpu;
 
 out:
 object_unref(OBJECT(cpu));
-if (err) {
-error_propagate(errp, err);
-cpu = NULL;
-}
-return cpu;
+error_propagate(errp, err);
+return ret;
 }
 
 static void s390_init_cpus(MachineState *machine)
-- 
2.26.2




[PATCH v2 14/44] block: Avoid error accumulation in bdrv_img_create()

2020-07-02 Thread Markus Armbruster
When creating an image fails because the format doesn't support option
"backing_file" or "backing_fmt", bdrv_img_create() first has
qemu_opt_set() put a generic error into @local_err, then puts the real
error into @errp with error_setg(), and then propagates the former to
the latter, which throws away the generic error.  A bit complicated,
but works.

Not that qemu_opt_set() returns a useful value, we can simply ignore
the generic error instead.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 block.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index 8d478bdc51..b396f32a51 100644
--- a/block.c
+++ b/block.c
@@ -6090,7 +6090,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 
 if (base_filename) {
 if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename,
-  _err)) {
+  NULL)) {
 error_setg(errp, "Backing file not supported for file format '%s'",
fmt);
 goto out;
@@ -6098,7 +6098,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 }
 
 if (base_fmt) {
-if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, _err)) {
+if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, NULL)) {
 error_setg(errp, "Backing file format not supported for file "
  "format '%s'", fmt);
 goto out;
-- 
2.26.2




[PATCH v2 25/44] qom: Use return values to check for error where that's simpler

2020-07-02 Thread Markus Armbruster
When using the Error object to check for error, we need to receive it
into a local variable, then propagate() it to @errp.

Using the return value permits allows receiving it straight to @errp.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 qom/object.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/qom/object.c b/qom/object.c
index 0808da2767..56d858b6a5 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -549,8 +549,7 @@ void object_initialize_child_with_propsv(Object *parentobj,
 object_initialize(childobj, size, type);
 obj = OBJECT(childobj);
 
-object_set_propv(obj, _err, vargs);
-if (local_err) {
+if (object_set_propv(obj, errp, vargs) < 0) {
 goto out;
 }
 
@@ -743,7 +742,7 @@ Object *object_new_with_propv(const char *typename,
 }
 obj = object_new_with_type(klass->type);
 
-if (object_set_propv(obj, _err, vargs) < 0) {
+if (object_set_propv(obj, errp, vargs) < 0) {
 goto error;
 }
 
@@ -1767,14 +1766,17 @@ static void object_set_link_property(Object *obj, 
Visitor *v,
 char *path = NULL;
 
 visit_type_str(v, name, , _err);
+if (local_err) {
+error_propagate(errp, local_err);
+return;
+}
 
-if (!local_err && strcmp(path, "") != 0) {
-new_target = object_resolve_link(obj, name, path, _err);
+if (strcmp(path, "") != 0) {
+new_target = object_resolve_link(obj, name, path, errp);
 }
 
 g_free(path);
-if (local_err) {
-error_propagate(errp, local_err);
+if (!new_target) {
 return;
 }
 
-- 
2.26.2




[PATCH v2 41/44] error: Avoid error_propagate() after migrate_add_blocker()

2020-07-02 Thread Markus Armbruster
When migrate_add_blocker(blocker, ) is followed by
error_propagate(errp, err), we can often just as well do
migrate_add_blocker(..., errp).

Do that with this Coccinelle script:

@@
expression blocker, err, errp;
expression ret;
@@
-ret = migrate_add_blocker(blocker, );
-if (err) {
+ret = migrate_add_blocker(blocker, errp);
+if (ret < 0) {
 ... when != err;
-error_propagate(errp, err);
 ...
 }

@@
expression blocker, err, errp;
@@
-migrate_add_blocker(blocker, );
-if (err) {
+if (migrate_add_blocker(blocker, errp) < 0) {
 ... when != err;
-error_propagate(errp, err);
 ...
 }

Double-check @err is not used afterwards.  Dereferencing it would be
use after free, but checking whether it's null would be legitimate.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 block/parallels.c| 5 ++---
 block/qcow.c | 6 ++
 block/vdi.c  | 6 ++
 block/vhdx.c | 5 ++---
 block/vmdk.c | 6 ++
 block/vpc.c  | 5 ++---
 block/vvfat.c| 6 ++
 hw/display/virtio-gpu-base.c | 5 +
 hw/intc/arm_gic_kvm.c| 4 +---
 hw/intc/arm_gicv3_its_kvm.c  | 5 +
 hw/intc/arm_gicv3_kvm.c  | 4 +---
 hw/misc/ivshmem.c| 4 +---
 hw/scsi/vhost-scsi.c | 4 +---
 13 files changed, 20 insertions(+), 45 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index f489c0d4ba..3c22dfdc9d 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -859,9 +859,8 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
 error_setg(>migration_blocker, "The Parallels format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(s->migration_blocker, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = migrate_add_blocker(s->migration_blocker, errp);
+if (ret < 0) {
 error_free(s->migration_blocker);
 goto fail;
 }
diff --git a/block/qcow.c b/block/qcow.c
index c22d1bf6b8..1e134f3445 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -121,7 +121,6 @@ static int qcow_open(BlockDriverState *bs, QDict *options, 
int flags,
 unsigned int len, i, shift;
 int ret;
 QCowHeader header;
-Error *local_err = NULL;
 QCryptoBlockOpenOptions *crypto_opts = NULL;
 unsigned int cflags = 0;
 QDict *encryptopts = NULL;
@@ -314,9 +313,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, 
int flags,
 error_setg(>migration_blocker, "The qcow format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(s->migration_blocker, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = migrate_add_blocker(s->migration_blocker, errp);
+if (ret < 0) {
 error_free(s->migration_blocker);
 goto fail;
 }
diff --git a/block/vdi.c b/block/vdi.c
index 0a60be773e..3a3df45f84 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -375,7 +375,6 @@ static int vdi_open(BlockDriverState *bs, QDict *options, 
int flags,
 VdiHeader header;
 size_t bmap_size;
 int ret;
-Error *local_err = NULL;
 QemuUUID uuid_link, uuid_parent;
 
 bs->file = bdrv_open_child(NULL, options, "file", bs, _of_bds,
@@ -496,9 +495,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, 
int flags,
 error_setg(>migration_blocker, "The vdi format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(s->migration_blocker, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = migrate_add_blocker(s->migration_blocker, errp);
+if (ret < 0) {
 error_free(s->migration_blocker);
 goto fail_free_bmap;
 }
diff --git a/block/vhdx.c b/block/vhdx.c
index eed9c3b860..1f9fca837d 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1089,9 +1089,8 @@ static int vhdx_open(BlockDriverState *bs, QDict 
*options, int flags,
 error_setg(>migration_blocker, "The vhdx format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(s->migration_blocker, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = migrate_add_blocker(s->migration_blocker, errp);
+if (ret < 0) {
 error_free(s->migration_blocker);
 goto fail;
 }
diff --git a/block/vmdk.c b/block/vmdk.c
index 9a09193f3b..28cec50f38 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1263,7 +1263,6 @@ static int 

[PATCH v2 05/44] virtio-crypto-pci: Tidy up virtio_crypto_pci_realize()

2020-07-02 Thread Markus Armbruster
virtio_crypto_pci_realize() continues after realization of its
"virtio-crypto-device" fails.  Only an object_property_set_link()
follows; looks harmless to me.  Tidy up anyway: return after failure,
just like virtio_rng_pci_realize() does.

Cc: "Gonglei (Arei)" 
Cc: Michael S. Tsirkin 
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
Reviewed-by: Gonglei < arei.gong...@huawei.com>
---
 hw/virtio/virtio-crypto-pci.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index 72be531c95..0755722288 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -54,7 +54,9 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy 
*vpci_dev, Error **errp)
 }
 
 virtio_pci_force_virtio_1(vpci_dev);
-qdev_realize(vdev, BUS(_dev->bus), errp);
+if (!qdev_realize(vdev, BUS(_dev->bus), errp)) {
+return;
+}
 object_property_set_link(OBJECT(vcrypto),
  OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
  NULL);
-- 
2.26.2




[PATCH v2 13/44] qemu-option: Use returned bool to check for failure

2020-07-02 Thread Markus Armbruster
The previous commit enables conversion of

foo(..., );
if (err) {
...
}

to

if (!foo(..., )) {
...
}

for QemuOpts functions that now return true / false on success /
error.  Coccinelle script:

@@
identifier fun = {opts_do_parse, parse_option_bool, parse_option_number, 
parse_option_size, qemu_opt_parse, qemu_opt_rename, qemu_opt_set, 
qemu_opt_set_bool, qemu_opt_set_number, qemu_opts_absorb_qdict, 
qemu_opts_do_parse, qemu_opts_from_qdict_entry, qemu_opts_set, 
qemu_opts_validate};
expression list args, args2;
typedef Error;
Error *err;
@@
-fun(args, , args2);
-if (err)
+if (!fun(args, , args2))
 {
 ...
 }

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---
 block.c   | 16 ++--
 block/blkdebug.c  |  3 +--
 block/blklogwrites.c  |  3 +--
 block/blkverify.c |  3 +--
 block/crypto.c|  3 +--
 block/curl.c  |  3 +--
 block/file-posix.c|  6 ++
 block/file-win32.c|  6 ++
 block/gluster.c   | 15 +--
 block/iscsi.c |  3 +--
 block/nbd.c   |  3 +--
 block/parallels.c |  3 +--
 block/qcow2.c |  3 +--
 block/quorum.c|  3 +--
 block/raw-format.c|  3 +--
 block/replication.c   |  3 +--
 block/sheepdog.c  |  3 +--
 block/ssh.c   |  3 +--
 block/throttle.c  |  3 +--
 block/vpc.c   |  3 +--
 block/vvfat.c |  3 +--
 block/vxhs.c  |  6 ++
 blockdev.c| 11 ---
 chardev/char.c|  6 ++
 contrib/ivshmem-server/main.c |  4 ++--
 hw/net/virtio-net.c   |  5 ++---
 hw/smbios/smbios.c| 24 
 qapi/string-input-visitor.c   |  3 +--
 qemu-img.c| 19 +++
 tpm.c |  3 +--
 util/qemu-config.c| 12 
 util/qemu-option.c| 16 ++--
 32 files changed, 71 insertions(+), 132 deletions(-)

diff --git a/block.c b/block.c
index 6dbcb7e083..8d478bdc51 100644
--- a/block.c
+++ b/block.c
@@ -1629,8 +1629,7 @@ static int bdrv_open_common(BlockDriverState *bs, 
BlockBackend *file,
 assert(options != NULL && bs->options != options);
 
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-qemu_opts_absorb_qdict(opts, options, _err);
-if (local_err) {
+if (!qemu_opts_absorb_qdict(opts, options, _err)) {
 error_propagate(errp, local_err);
 ret = -EINVAL;
 goto fail_opts;
@@ -4091,8 +4090,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, 
BlockReopenQueue *queue,
 
 /* Process generic block layer options */
 opts = qemu_opts_create(_runtime_opts, NULL, 0, _abort);
-qemu_opts_absorb_qdict(opts, reopen_state->options, _err);
-if (local_err) {
+if (!qemu_opts_absorb_qdict(opts, reopen_state->options, _err)) {
 error_propagate(errp, local_err);
 ret = -EINVAL;
 goto error;
@@ -6078,8 +6076,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 
 /* Parse -o options */
 if (options) {
-qemu_opts_do_parse(opts, options, NULL, _err);
-if (local_err) {
+if (!qemu_opts_do_parse(opts, options, NULL, _err)) {
 goto out;
 }
 }
@@ -6092,8 +6089,8 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 }
 
 if (base_filename) {
-qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, _err);
-if (local_err) {
+if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename,
+  _err)) {
 error_setg(errp, "Backing file not supported for file format '%s'",
fmt);
 goto out;
@@ -6101,8 +6098,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 }
 
 if (base_fmt) {
-qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, _err);
-if (local_err) {
+if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, _err)) {
 error_setg(errp, "Backing file format not supported for file "
  "format '%s'", fmt);
 goto out;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 7194bc7f06..d473dcf8c7 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -472,8 +472,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
*options, int flags,
 uint64_t align;
 
 opts = qemu_opts_create(_opts, NULL, 0, _abort);
-qemu_opts_absorb_qdict(opts, options, _err);
-if (local_err) {
+if (!qemu_opts_absorb_qdict(opts, options, _err)) {
 error_propagate(errp, local_err);
 ret = -EINVAL;
 goto out;
diff --git 

[PATCH v2 03/44] qdev: Use returned bool to check for qdev_realize() etc. failure

2020-07-02 Thread Markus Armbruster
Convert

foo(..., );
if (err) {
...
}

to

if (!foo(..., )) {
...
}

for qdev_realize(), qdev_realize_and_unref(), qbus_realize() and their
wrappers isa_realize_and_unref(), pci_realize_and_unref(),
sysbus_realize(), sysbus_realize_and_unref(), usb_realize_and_unref().
Coccinelle script:

@@
identifier fun = {isa_realize_and_unref, pci_realize_and_unref, 
qbus_realize, qdev_realize, qdev_realize_and_unref, sysbus_realize, 
sysbus_realize_and_unref, usb_realize_and_unref};
expression list args, args2;
typedef Error;
Error *err;
@@
-fun(args, , args2);
-if (err)
+if (!fun(args, , args2))
 {
 ...
 }

Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information".  Nothing to convert there; skipped.

Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Converted manually.

A few line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---
 hw/arm/allwinner-a10.c  | 15 +++
 hw/arm/armsse.c | 78 +++--
 hw/arm/armv7m.c |  9 ++--
 hw/arm/aspeed_ast2600.c | 51 +++--
 hw/arm/aspeed_soc.c | 45 +++
 hw/arm/bcm2835_peripherals.c| 45 +++
 hw/arm/bcm2836.c|  9 ++--
 hw/arm/cubieboard.c |  3 +-
 hw/arm/digic.c  |  9 ++--
 hw/arm/digic_boards.c   |  3 +-
 hw/arm/fsl-imx25.c  | 33 +-
 hw/arm/fsl-imx31.c  | 24 --
 hw/arm/fsl-imx6.c   | 36 +--
 hw/arm/msf2-soc.c   | 15 +++
 hw/arm/nrf51_soc.c  | 18 +++-
 hw/arm/stm32f205_soc.c  | 21 +++--
 hw/arm/stm32f405_soc.c  | 24 --
 hw/arm/xlnx-zynqmp.c| 45 +++
 hw/block/fdc.c  |  3 +-
 hw/block/xen-block.c|  3 +-
 hw/char/serial-pci-multi.c  |  3 +-
 hw/char/serial-pci.c|  3 +-
 hw/char/serial.c|  6 +--
 hw/core/cpu.c   |  3 +-
 hw/cpu/a15mpcore.c  |  3 +-
 hw/cpu/a9mpcore.c   | 15 +++
 hw/cpu/arm11mpcore.c| 12 ++---
 hw/cpu/realview_mpcore.c|  6 +--
 hw/display/virtio-gpu-pci.c |  4 +-
 hw/display/virtio-vga.c |  3 +-
 hw/intc/armv7m_nvic.c   |  6 +--
 hw/intc/pnv_xive.c  |  6 +--
 hw/intc/realview_gic.c  |  3 +-
 hw/intc/spapr_xive.c|  6 +--
 hw/intc/xics.c  |  3 +-
 hw/intc/xive.c  |  3 +-
 hw/isa/piix4.c  |  3 +-
 hw/microblaze/xlnx-zynqmp-pmu.c |  6 +--
 hw/mips/cps.c   | 12 ++---
 hw/misc/macio/cuda.c|  3 +-
 hw/misc/macio/macio.c   | 18 +++-
 hw/misc/macio/pmu.c |  3 +-
 hw/pci-host/pnv_phb3.c  |  9 ++--
 hw/pci-host/pnv_phb4.c  |  3 +-
 hw/pci-host/pnv_phb4_pec.c  |  3 +-
 hw/ppc/e500.c   |  3 +-
 hw/ppc/pnv.c| 39 ++---
 hw/ppc/pnv_core.c   |  3 +-
 hw/ppc/pnv_psi.c|  6 +--
 hw/ppc/spapr_cpu_core.c |  3 +-
 hw/ppc/spapr_irq.c  |  3 +-
 hw/riscv/opentitan.c|  6 +--
 hw/riscv/sifive_e.c |  3 +-
 hw/riscv/sifive_u.c |  3 +-
 hw/s390x/event-facility.c   | 10 ++---
 hw/s390x/s390-pci-bus.c |  3 +-
 hw/s390x/sclp.c |  3 +-
 hw/s390x/virtio-ccw-crypto.c|  3 +-
 hw/s390x/virtio-ccw-rng.c   |  3 +-
 hw/scsi/scsi-bus.c  |  3 +-
 hw/sd/aspeed_sdhci.c|  3 +-
 hw/sd/ssi-sd.c  |  3 +-
 hw/usb/bus.c|  3 +-
 hw/virtio/virtio-rng-pci.c  |  3 +-
 qdev-monitor.c  |  3 +-
 65 files changed, 248 insertions(+), 495 deletions(-)

diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 52e0d83760..e1acffe5f6 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -74,14 +74,12 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
 SysBusDevice *sysbusdev;
 Error *err = NULL;
 
-qdev_realize(DEVICE(>cpu), NULL, );
-if (err != NULL) {
+if (!qdev_realize(DEVICE(>cpu), NULL, )) {
 error_propagate(errp, err);
 return;
 }
 
-sysbus_realize(SYS_BUS_DEVICE(>intc), );
-if (err != NULL) {
+if (!sysbus_realize(SYS_BUS_DEVICE(>intc), )) {
 error_propagate(errp, err);
 return;
 }
@@ -93,8 +91,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(>cpu), ARM_CPU_FIQ));
 qdev_pass_gpios(DEVICE(>intc), dev, NULL);
 
-sysbus_realize(SYS_BUS_DEVICE(>timer), );
-if (err != NULL) {
+if (!sysbus_realize(SYS_BUS_DEVICE(>timer), )) 

[PATCH v2 28/44] qom: Use returned bool to check for failure, Coccinelle part

2020-07-02 Thread Markus Armbruster
The previous commit enables conversion of

foo(..., );
if (err) {
...
}

to

if (!foo(..., errp)) {
...
}

for QOM functions that now return true / false on success / error.
Coccinelle script:

@@
identifier fun = {object_apply_global_props, 
object_initialize_child_with_props, object_initialize_child_with_propsv, 
object_property_get, object_property_get_bool, object_property_parse, 
object_property_set, object_property_set_bool, object_property_set_int, 
object_property_set_link, object_property_set_qobject, object_property_set_str, 
object_property_set_uint, object_set_props, object_set_propv, 
user_creatable_add_dict, user_creatable_complete, user_creatable_del};
expression list args, args2;
typedef Error;
Error *err;
@@
-fun(args, , args2);
-if (err)
+if (!fun(args, , args2))
 {
 ...
 }

Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Convert manually.

Line breaks tidied up manually.

Signed-off-by: Markus Armbruster 
---
 hw/arm/armsse.c  | 52 +++-
 hw/arm/armv7m.c  | 20 ++
 hw/arm/aspeed_ast2600.c  |  5 ++--
 hw/arm/aspeed_soc.c  |  5 ++--
 hw/arm/bcm2835_peripherals.c |  5 ++--
 hw/arm/bcm2836.c | 12 -
 hw/arm/cubieboard.c  | 11 
 hw/arm/digic.c   |  4 +--
 hw/arm/nrf51_soc.c   |  8 +++---
 hw/arm/stm32f405_soc.c   |  7 +++--
 hw/arm/xlnx-zynqmp.c | 14 +-
 hw/block/xen-block.c | 15 +--
 hw/core/qdev.c   |  3 +--
 hw/i386/x86.c|  3 +--
 hw/ppc/pnv_psi.c |  4 +--
 hw/s390x/s390-pci-bus.c  |  3 +--
 hw/s390x/s390-virtio-ccw.c   |  3 +--
 hw/scsi/scsi-bus.c   |  3 +--
 hw/sd/aspeed_sdhci.c |  8 +++---
 hw/sd/ssi-sd.c   |  3 +--
 hw/virtio/virtio-rng.c   |  5 ++--
 qdev-monitor.c   |  3 +--
 qom/object.c | 15 ---
 qom/object_interfaces.c  |  6 ++---
 softmmu/vl.c |  4 +--
 target/arm/monitor.c |  3 +--
 target/i386/cpu.c| 11 +++-
 target/s390x/cpu_models.c|  3 +--
 28 files changed, 96 insertions(+), 142 deletions(-)

diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index f8822f9cbd..e8d489a7e7 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -535,22 +535,20 @@ static void armsse_realize(DeviceState *dev, Error **errp)
  * later if necessary.
  */
 if (extract32(info->cpuwait_rst, i, 1)) {
-object_property_set_bool(cpuobj, "start-powered-off", true, );
-if (err) {
+if (!object_property_set_bool(cpuobj, "start-powered-off", true,
+  )) {
 error_propagate(errp, err);
 return;
 }
 }
 if (!s->cpu_fpu[i]) {
-object_property_set_bool(cpuobj, "vfp", false, );
-if (err) {
+if (!object_property_set_bool(cpuobj, "vfp", false, )) {
 error_propagate(errp, err);
 return;
 }
 }
 if (!s->cpu_dsp[i]) {
-object_property_set_bool(cpuobj, "dsp", false, );
-if (err) {
+if (!object_property_set_bool(cpuobj, "dsp", false, )) {
 error_propagate(errp, err);
 return;
 }
@@ -605,9 +603,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
 DeviceState *devs = DEVICE(splitter);
 int cpunum;
 
-object_property_set_int(splitter, "num-lines", info->num_cpus,
-);
-if (err) {
+if (!object_property_set_int(splitter, "num-lines",
+ info->num_cpus, )) {
 error_propagate(errp, err);
 return;
 }
@@ -659,9 +656,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
  * multiple lines, one for each of the PPCs within the ARMSSE and one
  * that will be an output from the ARMSSE to the system.
  */
-object_property_set_int(OBJECT(>sec_resp_splitter), "num-lines", 3,
-);
-if (err) {
+if (!object_property_set_int(OBJECT(>sec_resp_splitter),
+ "num-lines", 3, )) {
 error_propagate(errp, err);
 return;
 }
@@ -703,9 +699,9 @@ static void armsse_realize(DeviceState *dev, Error **errp)
 }
 
 /* We must OR together lines from the MPC splitters to go to the NVIC */
-object_property_set_int(OBJECT(>mpc_irq_orgate), "num-lines",
-IOTS_NUM_EXP_MPC + info->sram_banks, );
-if (err) {
+if 

[PATCH v2 09/44] qemu-option: Simplify around find_default_by_name()

2020-07-02 Thread Markus Armbruster
Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
---
 util/qemu-option.c | 18 +-
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/util/qemu-option.c b/util/qemu-option.c
index 14e211ddd8..e7b540a21b 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -277,7 +277,6 @@ static void qemu_opt_del_all(QemuOpts *opts, const char 
*name)
 const char *qemu_opt_get(QemuOpts *opts, const char *name)
 {
 QemuOpt *opt;
-const char *def_val;
 
 if (opts == NULL) {
 return NULL;
@@ -285,12 +284,10 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
 
 opt = qemu_opt_find(opts, name);
 if (!opt) {
-def_val = find_default_by_name(opts, name);
-if (def_val) {
-return def_val;
-}
+return find_default_by_name(opts, name);
 }
-return opt ? opt->str : NULL;
+
+return opt->str;
 }
 
 void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
@@ -319,8 +316,7 @@ const char *qemu_opt_iter_next(QemuOptsIter *iter)
 char *qemu_opt_get_del(QemuOpts *opts, const char *name)
 {
 QemuOpt *opt;
-const char *def_val;
-char *str = NULL;
+char *str;
 
 if (opts == NULL) {
 return NULL;
@@ -328,11 +324,7 @@ char *qemu_opt_get_del(QemuOpts *opts, const char *name)
 
 opt = qemu_opt_find(opts, name);
 if (!opt) {
-def_val = find_default_by_name(opts, name);
-if (def_val) {
-str = g_strdup(def_val);
-}
-return str;
+return g_strdup(find_default_by_name(opts, name));
 }
 str = opt->str;
 opt->str = NULL;
-- 
2.26.2




[PATCH v2 24/44] qom: Don't handle impossible object_property_get_link() failure

2020-07-02 Thread Markus Armbruster
Don't handle object_property_get_link() failure that can't happen
unless the programmer screwed up, pass _abort.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Philippe Mathieu-Daudé 
---
 hw/arm/bcm2835_peripherals.c |  7 +--
 hw/arm/bcm2836.c |  7 +--
 hw/display/bcm2835_fb.c  |  8 +---
 hw/dma/bcm2835_dma.c |  9 +
 hw/gpio/bcm2835_gpio.c   | 15 ++-
 hw/intc/nios2_iic.c  |  8 +---
 hw/misc/bcm2835_mbox.c   |  9 +
 hw/misc/bcm2835_property.c   | 17 ++---
 hw/usb/hcd-dwc2.c|  9 +
 9 files changed, 11 insertions(+), 78 deletions(-)

diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 2df81168e4..beade39e41 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -134,12 +134,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, 
Error **errp)
 uint64_t ram_size, vcram_size;
 int n;
 
-obj = object_property_get_link(OBJECT(dev), "ram", );
-if (obj == NULL) {
-error_setg(errp, "%s: required ram link not found: %s",
-   __func__, error_get_pretty(err));
-return;
-}
+obj = object_property_get_link(OBJECT(dev), "ram", _abort);
 
 ram = MEMORY_REGION(obj);
 ram_size = memory_region_size(ram);
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 1a7560ef30..70ca2f0d9a 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -77,12 +77,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
 
 /* common peripherals from bcm2835 */
 
-obj = object_property_get_link(OBJECT(dev), "ram", );
-if (obj == NULL) {
-error_setg(errp, "%s: required ram link not found: %s",
-   __func__, error_get_pretty(err));
-return;
-}
+obj = object_property_get_link(OBJECT(dev), "ram", _abort);
 
 object_property_add_const_link(OBJECT(>peripherals), "ram", obj);
 
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index c6263808a2..c4bfed2740 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -401,7 +401,6 @@ static void bcm2835_fb_reset(DeviceState *dev)
 static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
 {
 BCM2835FBState *s = BCM2835_FB(dev);
-Error *err = NULL;
 Object *obj;
 
 if (s->vcram_base == 0) {
@@ -409,12 +408,7 @@ static void bcm2835_fb_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 
-obj = object_property_get_link(OBJECT(dev), "dma-mr", );
-if (obj == NULL) {
-error_setg(errp, "%s: required dma-mr link not found: %s",
-   __func__, error_get_pretty(err));
-return;
-}
+obj = object_property_get_link(OBJECT(dev), "dma-mr", _abort);
 
 /* Fill in the parts of initial_config that are not set by QOM properties 
*/
 s->initial_config.xres_virtual = s->initial_config.xres;
diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c
index 4cd9dab745..eb0002a2b9 100644
--- a/hw/dma/bcm2835_dma.c
+++ b/hw/dma/bcm2835_dma.c
@@ -376,16 +376,9 @@ static void bcm2835_dma_reset(DeviceState *dev)
 static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
 {
 BCM2835DMAState *s = BCM2835_DMA(dev);
-Error *err = NULL;
 Object *obj;
 
-obj = object_property_get_link(OBJECT(dev), "dma-mr", );
-if (obj == NULL) {
-error_setg(errp, "%s: required dma-mr link not found: %s",
-   __func__, error_get_pretty(err));
-return;
-}
-
+obj = object_property_get_link(OBJECT(dev), "dma-mr", _abort);
 s->dma_mr = MEMORY_REGION(obj);
 address_space_init(>dma_as, s->dma_mr, TYPE_BCM2835_DMA "-memory");
 
diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c
index 91ce3d10cc..abdddbc67c 100644
--- a/hw/gpio/bcm2835_gpio.c
+++ b/hw/gpio/bcm2835_gpio.c
@@ -312,22 +312,11 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error 
**errp)
 {
 BCM2835GpioState *s = BCM2835_GPIO(dev);
 Object *obj;
-Error *err = NULL;
 
-obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", );
-if (obj == NULL) {
-error_setg(errp, "%s: required sdhci link not found: %s",
-__func__, error_get_pretty(err));
-return;
-}
+obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", _abort);
 s->sdbus_sdhci = SD_BUS(obj);
 
-obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", );
-if (obj == NULL) {
-error_setg(errp, "%s: required sdhost link not found: %s",
-__func__, error_get_pretty(err));
-return;
-}
+obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", _abort);
 s->sdbus_sdhost = SD_BUS(obj);
 }
 
diff --git a/hw/intc/nios2_iic.c b/hw/intc/nios2_iic.c
index 3a5d86c2a4..1a5df8c89a 100644
--- a/hw/intc/nios2_iic.c
+++ b/hw/intc/nios2_iic.c
@@ -66,14 +66,8 @@ static void altera_iic_init(Object *obj)
 static void 

[PATCH v2 01/44] error: Improve examples in error.h's big comment

2020-07-02 Thread Markus Armbruster
Show errp instead of  where  is actually unusual.  Add a
missing declaration.  Add a second error pileup example.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
Reviewed-by: Vladimir Sementsov-Ogievskiy 
Reviewed-by: Greg Kurz 
---
 include/qapi/error.h | 19 +++
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/include/qapi/error.h b/include/qapi/error.h
index ad5b6e896d..3e64324b7a 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -16,15 +16,15 @@
  * Error reporting system loosely patterned after Glib's GError.
  *
  * Create an error:
- * error_setg(, "situation normal, all fouled up");
+ * error_setg(errp, "situation normal, all fouled up");
  *
  * Create an error and add additional explanation:
- * error_setg(, "invalid quark");
- * error_append_hint(, "Valid quarks are up, down, strange, "
+ * error_setg(errp, "invalid quark");
+ * error_append_hint(errp, "Valid quarks are up, down, strange, "
  *   "charm, top, bottom.\n");
  *
  * Do *not* contract this to
- * error_setg(, "invalid quark\n"
+ * error_setg(errp, "invalid quark\n" // WRONG!
  *"Valid quarks are up, down, strange, charm, top, bottom.");
  *
  * Report an error to the current monitor if we have one, else stderr:
@@ -108,12 +108,23 @@
  * }
  *
  * Do *not* "optimize" this to
+ * Error *err = NULL;
  * foo(arg, );
  * bar(arg, ); // WRONG!
  * if (err) {
  * handle the error...
  * }
  * because this may pass a non-null err to bar().
+ *
+ * Likewise, do *not*
+ * Error *err = NULL;
+ * if (cond1) {
+ * error_setg(, ...);
+ * }
+ * if (cond2) {
+ * error_setg(, ...); // WRONG!
+ * }
+ * because this may pass a non-null err to error_setg().
  */
 
 #ifndef ERROR_H
-- 
2.26.2




  1   2   >