[libvirt] [PATCH v4] libxl: implement virDomainBlockStats

Joao Martins joao.m.martins at oracle.com
Mon Jul 25 23:47:38 UTC 2016



On 07/25/2016 09:35 PM, Jim Fehlig wrote:
> On 07/23/2016 05:34 AM, Joao Martins wrote:
>> On 07/22/2016 10:50 PM, Jim Fehlig wrote:
>>> On 07/20/2016 04:48 PM, Joao Martins wrote:
>>>> Introduce initial support for domainBlockStats API call that
>>>> allow us to query block device statistics. openstack nova
>>>> uses this API call to query block statistics, alongside
>>>> virDomainMemoryStats and virDomainInterfaceStats.  Note that
>>>> this patch only introduces it for VBD for starters. QDisk
>>>> would come in a separate patch series.
>>>>
>>>> A new statistics data structure is introduced to fit common
>>>> statistics among others specific to the underlying block
>>>> backends. For the VBD statistics on linux these are exported
>>>> via sysfs on the path:
>>>>
>>>> "/sys/bus/xen-backend/devices/vbd-<domid>-<devid>/statistics"
>>>>
>>>> To calculate the block devno libxlDiskPathToID is introduced.
>>> Too bad libxl or libxlutil doesn't provide such a function.
>> Yeah :( Unfortunately the function is private to libxl.
>>
>> But we could get devno indirectly through
>> libxl_device_disk_getinfo provided by libxl_diskinfo->devid field.
>> But at the same time that function does much more than that i.e.
>> 5 other xenstore reads being the reason why I didn't pursued this way
>> initially. On the other hand while it's incurs more overhead for just
>> calculating an ID, it's better towards unlikely adjustments on this
>> area. I say unlikely because this hasn't changed for the past 6 years
>> (Xen 4.0?), see xen commit e9703a9 ("libxl: Properly parse vbd name").
>> What do you think?
> 
> I think copying the pertinent code to libxlDiskPathToID is the best approach in
> this case.
OK.

> xend, whose functionality was replaced by the libvirt libxl driver,
> had a similar function
> 
> http://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=tools/python/xen/util/blkif.py;h=4bbae308af51dee946a5cd498e93807e05ab9ef3;hb=refs/heads/stable-4.4#l13
>
Yep.

[snip]

>>>>  static int
>>>> +libxlDiskPathToID(const char *virtpath)
>>>> +{
>>>> +    static char const* drive_prefix[] = {"xvd", "hd", "sd"};
>>>> +    int disk, partition, chrused;
>>>> +    int fmt, id;
>>>> +    char *r;[snip
>>>> +    size_t i;
>>>> +
>>>> +    fmt = id = -1;
>>>> +
>>>> +    /* Find any disk prefixes we know about */
>>>> +    for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
>>>> +        if (STRPREFIX(virtpath, drive_prefix[i]) &&
>>>> +            !virDiskNameParse(virtpath, &disk, &partition)) {
>>>> +            fmt = i;
>>>> +            break;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* Handle it same way as xvd */
>>>> +    if (fmt < 0 &&
>>>> +        (sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
>>>> +         && chrused == strlen(virtpath)))
>>>> +        fmt = 0;
>>>> +
>>>> +    /* Test indexes ranges and calculate the device id */
>>>> +    switch (fmt) {
>>>> +    case 0: /* xvd */
>>>> +        if (disk <= 15 && partition <= 15)
>>>> +            id = (202 << 8) | (disk << 4) | partition;
>>>> +        else if ((disk <= ((1<<20)-1)) || partition <= 255)
>>>> +            id = (1 << 28) | (disk << 8) | partition;
>>>> +        break;
>>>> +    case 1: /* hd */
>>>> +        if (disk <= 3 && partition <= 63)
>>>> +            id = ((disk < 2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
>>>> +        break;
>>>> +    case 2: /* sd */
>>>> +        if (disk <= 15 && (partition <= 15))
>>>> +            id = (8 << 8) | (disk << 4) | partition;
>>>> +        break;
>>>> +    default:
>>>> +        errno = virStrToLong_i(virtpath, &r, 0, &id);
>>>> +        if (errno || *r || id > INT_MAX)
>>>> +            id = -1;
>>>> +        break;
>>> The purpose of the default case is not clear to me. Can you explain that a bit? 
>>> IIUC, virtpath would contain values such as xvda, sdc, or /path/to/image.
>> virtpath would only contain device names (no image paths). This falltrough case is to
>> have device number directly from unsigned long instead of parsing device name. See
>> (xen) libxl commit 8ca0ed2cd ("libxl: fail to parse disk vpath if a disk+part number
>> needed but unavailable") as docs/misc/vbd-interface.txt isn't exactly clear on this.
>> Regardless probably doesn't make a lot of sense for libvirt since we can only have
>> device names. I will probably just set "id = -1" or depending on your preference rely
>> on libxl_device_disk_getinfo(..) returned devid.
> 
> Yeah, I don't think it makes much sense for libvirt. virtpath is the 'disk'
> parameter in virDomainBlockStats*, which is documented as
> 
/nods

> "The @disk parameter is either the device target shorthand (the <target
> dev='...'/> sub-element, such as "vda"), or (since 0.9.8) an unambiguous source
> name of the block device (the <source file='...'/> sub-element, such as
> "/path/to/image"). Valid names can be found by calling virDomainGetXMLDesc() and
> inspecting elements within //domain/devices/disk. Some drivers might also accept
> the empty string for the @disk parameter, and then yield summary stats for the
> entire domain."
> 
My apologies, I was misinformed that the path could actually be a file and wasn't
handling that case in this patch. I've fixed that in v5 - and since I fetch anyways
the DiskDef by path I can just use disk->dst (aka disk/target/@dev). Note that I
don't validate disk->dst existence which AFAICT disk definition will always have this
dst field not NULL.

> Setting 'id = -1' is the right thing to do IMO.
OK.

> 
>>
>>>> +    }
>>>> +    return id;
>>>> +}
>>>> +
>>>> +#define LIBXL_VBD_SECTOR_SIZE 512
>>>> +
>>>> +static int
>>>> +libxlDiskSectorSize(int domid, int devno)
>>>> +{
>>>> +    char *path, *val;
>>>> +    struct xs_handle *handle;
>>>> +    int ret = LIBXL_VBD_SECTOR_SIZE;
>>>> +    unsigned int len;
>>>> +
>>>> +    handle = xs_daemon_open_readonly();
>>>> +    if (!handle) {
>>>> +        VIR_WARN("cannot read sector size");
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    path = val = NULL;
>>>> +    if (virAsprintf(&path, "/local/domain/%d/device/vbd/%d/backend",
>>>> +                    domid, devno) < 0)
>>>> +        goto cleanup;
>>>> +
>>>> +    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
>>>> +        goto cleanup;
>>>> +
>>>> +    VIR_FREE(path);
>>>> +    if (virAsprintf(&path, "%s/physical-sector-size", val) < 0)
>>>> +        goto cleanup;
>>>> +
>>>> +    VIR_FREE(val);
>>>> +    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
>>>> +        goto cleanup;
>>>> +
>>>> +    if (sscanf(val, "%d", &ret) != 1)
>>>> +        ret = LIBXL_VBD_SECTOR_SIZE;
>>>> +
>>>> + cleanup:
>>>> +    VIR_FREE(val);
>>>> +    VIR_FREE(path);
>>>> +    xs_daemon_close(handle);
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +static int
>>>> +libxlDomainBlockStatsVBD(virDomainObjPtr vm,
>>>> +                         const char *dev,
>>>> +                         libxlBlockStatsPtr stats)
>>> The stats parameter is unused when __linux__ is not defined. Otherwise, the
>>> patch looks fine.
>> Ah yes, and size will get declared but not used too.
>> Would you prefer resorting to this syntax instead:
>>
>> #ifdef __linux__
>> static int
>> libxlDomainBlockStatsVBD(virDomainObjPtr vm,
>>                          const char *dev,
>>                          libxlBlockStatsPtr stats)
>> {
>>    ...
>> }
>> #else
>> static int
>> libxlDomainBlockStatsVBD(virDomainObjPtr vm,
>>                          const char *dev ATTRIBUTE_UNUSED,
>>                          libxlBlockStatsPtr stats ATTRIBUTE_UNUSED)
>> {
>>     virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>>                    "%s", _("platform unsupported"));
>>     return -1;
>> }
>> #endif
>>
>> Or in alternative moving __linux__ conditional above devno declaration and always set
>> ATTRIBUTE_UNUSED on dev and stats params?
> 
> grepping through the sources shows both patterns are used. I find the first one
> more readable and future-proof. And having ATTRIBUTE_UNUSED on a used param
> feels odd to me :-).
> 
Hehe - I also lean towards option 1, much more readable.

Just sent v5 here:

https://www.redhat.com/archives/libvir-list/2016-July/msg01029.html

Regards,
Joao




More information about the libvir-list mailing list