[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 04/11] tools/xenstored: add GLOBAL_QUOTA_DATA record for live update



On Thu, Mar 05, 2026 at 02:52:01PM +0100, Juergen Gross wrote:
> diff --git a/tools/xenstored/domain.c b/tools/xenstored/domain.c
> index acdcaa769e..694ae58973 100644
> --- a/tools/xenstored/domain.c
> +++ b/tools/xenstored/domain.c
> @@ -1332,6 +1332,27 @@ int do_set_feature(const void *ctx, struct connection 
> *conn,
>       return 0;
>  }
>  
> +static bool parse_quota_name(const char *name, unsigned int *qidx,
> +                          unsigned int *idx)
> +{
> +     unsigned int q;

What do you think of using something like:
    const char soft_prefix[] = "soft-";
    const size_t soft_prefix_len = sizeof(soft_prefix) - 1;
to explain the `5`, here and in e.g. the function build_quota_data() ?
We used this in libxl in one place:
    
https://elixir.bootlin.com/xen/v4.21.0/source/tools/libs/light/libxl_qmp.c#L1288

But it's fine to leave it like that, as the '5's are close enought to
the prefix that we can guess easly enough.

> +
> +     if (strncmp(name, "soft-", 5)) {
> +             *idx = Q_IDX_HARD;
> +     } else {
> +             *idx = Q_IDX_SOFT;
> +             name += 5;
> +     }
> +     for (q = 0; q < ACC_N; q++) {
> +             if (quota_adm[q].name && !strcmp(quota_adm[q].name, name)) {
> +                     *qidx = q;
> +                     return false;
> +             }
> +     }
> +
> +     return true;
> +}
> +
>  static int close_xgt_handle(void *_handle)
>  {
>       xengnttab_close(*(xengnttab_handle **)_handle);
> @@ -2001,6 +2022,61 @@ void read_state_connection(const void *ctx, const void 
> *state)
>       }
>  }
>  
> +static unsigned int get_quota_size(struct quota *quota, unsigned int *len)
> +{
> +     unsigned int q;
> +     unsigned int n = 0;
> +
> +     for (q = 0; q < ACC_N; q++) {
> +             if (!quota_adm[q].name)
> +                     continue;
> +             if (quota[q].val[Q_IDX_HARD] != Q_VAL_DISABLED) {
> +                     n++;
> +                     *len += strlen(quota_adm[q].name) + 1;
> +             }
> +             if (quota[q].val[Q_IDX_SOFT] != Q_VAL_DISABLED) {
> +                     n++;
> +                     *len += strlen(quota_adm[q].name) + 5 + 1;

The value 5 here isn't explained. A comment would be nice.

> +             }
> +     }
> +
> +     return n;
> +}
> +
> +static void build_quota_data(struct quota *quota, uint32_t *val, char *name)

I guess we will need a leap of faith to trust that `val` is big enough,
after finding out that it's actually an output of multiple values, and
not an input of a single value.

And `name` seems to also be an output, and this is actually impossible
to guess from the prototype.

> +{
> +     unsigned int q;
> +     unsigned int n = 0;
> +
> +     for (q = 0; q < ACC_N; q++) {
> +             if (!quota_adm[q].name)
> +                     continue;
> +             if (quota[q].val[Q_IDX_HARD] != Q_VAL_DISABLED) {
> +                     val[n++] = quota[q].val[Q_IDX_HARD];
> +                     strcpy(name, quota_adm[q].name);
> +                     name += strlen(name) + 1;
> +             }
> +             if (quota[q].val[Q_IDX_SOFT] != Q_VAL_DISABLED) {
> +                     val[n++] = quota[q].val[Q_IDX_SOFT];
> +                     strcpy(name, "soft-");
> +                     strcpy(name + 5, quota_adm[q].name);
> +                     name += strlen(name) + 1;
> +             }
> +     }
> +}
> +
> +static void parse_quota_data(const uint32_t *val, const char *name,
> +                          unsigned int n, struct quota *quota)
> +{
> +     unsigned int i, q, idx;
> +
> +     for (i = 0; i < n; i++) {
> +             if (!parse_quota_name(name, &q, &idx))
> +                     quota[q].val[idx] = val[i];
> +             name += strlen(name) + 1;

So for `val`, we have a size. But, we don't have a size for `name`, are
we sure that it's safe to keep reading past `NUL` characters ? Is the
size of name available somewhere?

> +     }
> +}
> +
>  static int dump_state_domain(const void *k, void *v, void *arg)
>  {
>       struct domain *domain = v;
> @@ -2049,6 +2125,53 @@ void read_state_domain(const void *ctx, const void 
> *state, unsigned int version)
>               domain->features = sd->features;
>  }
>  
> +const char *dump_state_glb_quota(FILE *fp)
> +{
> +     struct xs_state_record_header *head;
> +     struct xs_state_glb_quota *glb;
> +     void *record;
> +     unsigned int n_quota;
> +     unsigned int len = sizeof(*glb);
> +     size_t ret;
> +
> +     n_quota = get_quota_size(quotas, &len);

So, get_quota_size is actually an "add" the size to this variable, and
not "store" the size in this variable. That's not confusing at all.

> +     len += n_quota * sizeof(glb->quota_val[0]);
> +     len = ROUNDUP(len, 3);
> +
> +     record = talloc_size(NULL, len + sizeof(*head));
> +     if (!record)
> +             return "Dump global quota allocation error";
> +
> +     head = record;
> +     head->type = XS_STATE_TYPE_GLB_QUOTA;
> +     head->length = len;
> +
> +     glb = (struct xs_state_glb_quota *)(head + 1);
> +     glb->n_dom_quota = n_quota;
> +     glb->n_glob_quota = 0;

Shouldn't `n_quota` be assigned to `n_glob_quota` instead? We don't have
per-domain quota yet, and only have global quota, right?

> +
> +     build_quota_data(quotas, glb->quota_val,
> +                      (char *)(glb->quota_val + n_quota));
> +
> +     ret = fwrite(record, len + sizeof(*head), 1, fp);
> +
> +     talloc_free(record);
> +
> +     if (ret != 1 || dump_state_align(fp))
> +             return "Dump global quota error";
> +
> +     return NULL;
> +}
> +
> +void read_state_glb_quota(const void *ctx, const void *state)
> +{
> +     const struct xs_state_glb_quota *glb = state;
> +     unsigned int n_quota = glb->n_dom_quota + glb->n_glob_quota;
> +     const char *name = (const char *)(glb->quota_val + n_quota);
> +
> +     parse_quota_data(glb->quota_val, name, n_quota, quotas);
> +}
> +

Thanks,


--
Anthony Perard | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.