diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 4e28122dd1680492bc45df943334e195f45dba80..87660ee67404f6802a956f7ef3cf4d104875fc73 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -388,8 +388,7 @@ static const vshCmdInfo info_domblkinfo[] = { static const vshCmdOptDef opts_domblkinfo[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "device", - .type = VSH_OT_DATA, - .flags = VSH_OFLAG_REQ, + .type = VSH_OT_STRING, .completer = virshDomainDiskTargetCompleter, .help = N_("block device") }, @@ -397,30 +396,66 @@ static const vshCmdOptDef opts_domblkinfo[] = { .type = VSH_OT_BOOL, .help = N_("Human readable output") }, + {.name = "all", + .type = VSH_OT_BOOL, + .help = N_("display all block devices info") + }, {.name = NULL} }; static void cmdDomblkinfoPrint(vshControl *ctl, const virDomainBlockInfo *info, - bool human) + const char *device, + bool human, bool title) { - if (!human) { - vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info->capacity); - vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info->allocation); - vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info->physical); + char *cap = NULL; + char *alloc = NULL; + char *phy = NULL; + + if (title) { + vshPrintExtra(ctl, "%-10s %-15s %-15s %-15s\n", _("Target"), + _("Capacity"), _("Allocation"), _("Physical")); + vshPrintExtra(ctl, "-----------------------------" + "------------------------\n"); + return; + } + + if (info->capacity == 0 && info->allocation == 0 && info->physical == 0) { + cap = vshStrdup(ctl, "-"); + alloc = vshStrdup(ctl, "-"); + phy = vshStrdup(ctl, "-"); + } else if (!human) { + if (virAsprintf(&cap, "%llu", info->capacity) < 0 || + virAsprintf(&alloc, "%llu", info->allocation) < 0 || + virAsprintf(&phy, "%llu", info->physical) < 0) + goto cleanup; + } else { + double val_cap, val_alloc, val_phy; + const char *unit_cap, *unit_alloc, *unit_phy; + + val_cap = vshPrettyCapacity(info->capacity, &unit_cap); + val_alloc = vshPrettyCapacity(info->allocation, &unit_alloc); + val_phy = vshPrettyCapacity(info->physical, &unit_phy); + + if (virAsprintf(&cap, "%.3lf %s", val_cap, unit_cap) < 0 || + virAsprintf(&alloc, "%.3lf %s", val_alloc, unit_alloc) < 0 || + virAsprintf(&phy, "%.3lf %s", val_phy, unit_phy) < 0) + goto cleanup; + } + + if (device) { + vshPrint(ctl, "%-10s %-15s %-15s %-15s\n", device, cap, alloc, phy); } else { - double val; - const char *unit; - - val = vshPrettyCapacity(info->capacity, &unit); - vshPrint(ctl, "%-15s %-.3lf %s\n", _("Capacity:"), val, unit); - val = vshPrettyCapacity(info->allocation, &unit); - vshPrint(ctl, "%-15s %-.3lf %s\n", _("Allocation:"), val, unit); - val = vshPrettyCapacity(info->physical, &unit); - vshPrint(ctl, "%-15s %-.3lf %s\n", _("Physical:"), val, unit); + vshPrint(ctl, "%-15s %s\n", _("Capacity:"), cap); + vshPrint(ctl, "%-15s %s\n", _("Allocation:"), alloc); + vshPrint(ctl, "%-15s %s\n", _("Physical:"), phy); } + cleanup: + VIR_FREE(cap); + VIR_FREE(alloc); + VIR_FREE(phy); } @@ -431,25 +466,83 @@ cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd) virDomainPtr dom; bool ret = false; bool human = false; + bool all = false; const char *device = NULL; + xmlDocPtr xmldoc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ndisks; + size_t i; + xmlNodePtr *disks = NULL; + char *target = NULL; + char *protocol = NULL; if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; - if (vshCommandOptStringReq(ctl, cmd, "device", &device) < 0) - goto cleanup; - - if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) + all = vshCommandOptBool(cmd, "all"); + if (!all && vshCommandOptStringQuiet(ctl, cmd, "device", &device) <= 0) { + vshError(ctl, "command 'domblkinfo' requires option"); goto cleanup; + } human = vshCommandOptBool(cmd, "human"); - cmdDomblkinfoPrint(ctl, &info, human); + if (all) { + bool active = virDomainIsActive(dom) == 1; + int rc; + + if (virshDomainGetXML(ctl, cmd, 0, &xmldoc, &ctxt) < 0) + goto cleanup; + + ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks); + if (ndisks < 0) + goto cleanup; + + /* print the title */ + cmdDomblkinfoPrint(ctl, NULL, NULL, false, true); + + for (i = 0; i < ndisks; i++) { + ctxt->node = disks[i]; + protocol = virXPathString("string(./source/@protocol)", ctxt); + target = virXPathString("string(./target/@dev)", ctxt); + + rc = virDomainGetBlockInfo(dom, target, &info, 0); + + if (rc < 0) { + /* If protocol is present that's an indication of a networked + * storage device which cannot provide statistics, so generate + * 0 based data and get the next disk. */ + if (protocol && !active && + virGetLastErrorCode() == VIR_ERR_INTERNAL_ERROR && + virGetLastErrorDomain() == VIR_FROM_STORAGE) { + memset(&info, 0, sizeof(info)); + vshResetLibvirtError(); + } else { + goto cleanup; + } + } + + cmdDomblkinfoPrint(ctl, &info, target, human, false); + + VIR_FREE(target); + VIR_FREE(protocol); + } + } else { + if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) + goto cleanup; + + cmdDomblkinfoPrint(ctl, &info, NULL, human, false); + } ret = true; cleanup: virshDomainFree(dom); + VIR_FREE(target); + VIR_FREE(protocol); + VIR_FREE(disks); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xmldoc); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 7cb8c8a6e43caa9b9522e459ecf77fdfe17e041c..c9ef4f137c3e9293c1de8d7cbd6561c003f3ea79 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -949,13 +949,16 @@ B command says that a domain was paused due to I/O error. The B command lists all block devices in error state and the error seen on each of them. -=item B I I [I<--human>] +=item B I [I I<--all>] [I<--human>] Get block device size info for a domain. A I corresponds to a unique target name () or source file () for one of the disk devices attached to I (see also B for listing these names). If I<--human> is set, the output will have a human readable output. +If I<--all> is set, the output will be a table showing all block devices +size info associated with I. +The I<--all> option takes precedence of the others. =item B I [I<--inactive>] [I<--details>]