Message ID | 20190916105945.93632-12-wipawel@amazon.de (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | livepatch: new features and fixes | expand |
On 9/16/19 11:59 AM, Pawel Wieczorkiewicz wrote: > Extend the livepatch list operation to fetch also payloads' metadata. > This is achieved by extending the sysctl list interface with 2 extra > guest handles: > * metadata - an array of arbitrary size strings > * metadata_len - an array of metadata strings' lengths (uin32_t each) uint32_t > > Payloads' metadata is a string of arbitrary size and does not have an > upper bound limit. It may also vary in size between payloads. > > In order to let the userland allocate enough space for the incoming > data add a metadata total size field to the list sysctl operation and > fill it with total size of all payloads' metadata. > snip> + * `metadata` - Virtual address of where to write the metadata of the payloads. > + Caller *MUST* allocate enough space to be able to store all received data > + (i.e. total allocated space *MUST* match the `metadata_total_size` value > + provided by the hypervisor). Individual payload metadata string can be of > + arbitrary length. The metadata string format is: key=value\0...key=value\0. > + * `metadata_len` - Virtual address of where to write the length of each metadata > + string of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* > + be of sizeof(uint32_t) (4 bytes). > > If the hypercall returns an positive number, it is the number (upto `nr` > provided to the hypercall) of the payloads returned, along with `nr` updated > with the number of remaining payloads, `version` updated (it may be the same > across hypercalls - if it varies the data is stale and further calls could > -fail) and the `name_total_size` containing total size of transfered data for > -the array. The `status`, `name`, and `len` are updated at their designed index > -value (`idx`) with the returned value of data. > +fail), `name_total_size` and `metadata_total_size` containing total sizes of > +transfered data for both the arrays. transferred > +The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their > +designed index value (`idx`) with the returned value of data. > > If the hypercall returns -XEN_E2BIG the `nr` is too big and should be > lowered. > @@ -780,6 +790,7 @@ The structure is as follow: > OUT: How many payloads left. */ > uint32_t pad; /* IN: Must be zero. */ > uint64_t name_total_size; /* OUT: Total size of all transfer names */ > + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ > XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough > space allocate for nr of them. */ > XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member > @@ -788,6 +799,12 @@ The structure is as follow: > nr of them. */ > XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. > Must have nr of them. */ > + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each > + member may have an arbitrary length. > + Must have nr of them. */ > + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. > + Must have nr of them. */ > + > }; > snip > @@ -744,6 +753,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, > struct xen_livepatch_status *info, > char *name, uint32_t *len, > const uint64_t name_total_size, > + char *metadata, uint32_t *metadata_len, > + const uint64_t metadata_total_size, > unsigned int *done, unsigned int *left) > { > int rc; > @@ -752,13 +763,16 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, > DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); > DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); > DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); > + DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); > + DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); > uint32_t max_batch_sz, nr; > uint32_t version = 0, retries = 0; > uint32_t adjust = 0; > - off_t name_off = 0; > - uint64_t name_sz; > + off_t name_off = 0, metadata_off = 0; > + uint64_t name_sz, metadata_sz; As with the previous patch, I think uint32_t would be more appropriate here as I can't imagine a reason why the metadata would exceed 4 GiB? And the same suggestion as with the previous patch to then change off_t (probably to uint32_t). > > - if ( !max || !info || !name || !len || !done || !left ) > + if ( !max || !info || !name || !len || > + !metadata || !metadata_len || !done || !left ) > { > errno = EINVAL; > return -1; snip > diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h > index 503be68059..7786864926 100644 > --- a/xen/include/public/sysctl.h > +++ b/xen/include/public/sysctl.h > @@ -920,16 +920,17 @@ struct xen_sysctl_livepatch_get { > }; > > /* > - * Retrieve an array of abbreviated status and names of payloads that are > - * loaded in the hypervisor. > + * Retrieve an array of abbreviated status, names and metadata of payloads that > + * are loaded in the hypervisor. > * > * If the hypercall returns an positive number, it is the number (up to `nr`) > * of the payloads returned, along with `nr` updated with the number of remaining > * payloads, `version` updated (it may be the same across hypercalls. If it varies > - * the data is stale and further calls could fail) and the name_total_size > - * containing total size of transfered data for the array. > - * The `status`, `name`, `len` are updated at their designed index value (`idx`) > - * with the returned value of data. > + * the data is stale and further calls could fail), `name_total_size` and > + * `metadata_total_size` containing total sizes of transfered data for both the transferred > + * arrays. > + * The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their > + * designed index value (`idx`) with the returned value of data. > * > * If the hypercall returns E2BIG the `nr` is too big and should be > * lowered. The upper limit of `nr` is left to the implemention. > @@ -953,6 +954,7 @@ struct xen_sysctl_livepatch_list { > OUT: How many payloads left. */ > uint32_t pad; /* IN: Must be zero. */ > uint64_t name_total_size; /* OUT: Total size of all transfer names */ > + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ > XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough > space allocate for nr of them. */ > XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member > @@ -961,6 +963,11 @@ struct xen_sysctl_livepatch_list { > nr of them. */ > XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. > Must have nr of them. */ > + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each > + member may have an arbitrary length. > + Must have nr of them. */ > + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. > + Must have nr of them. */ > }; > > /* > Do you think it would be useful for the metadata to be an optional OUT parameter? I could imagine a caller wanting to get a list of live patches without needing/wanting to get all the metadata as well. Secondly, there should also be (optional) metadata retrieval to the XEN_SYSCTL_LIVEPATCH_GET call since a caller may want to get status & metadata for a particular live patch without having to list all of them. That should be done as a separate patch from this one, I think. Thanks,
> On 25. Sep 2019, at 17:47, Ross Lagerwall <ross.lagerwall@citrix.com> wrote: > > On 9/16/19 11:59 AM, Pawel Wieczorkiewicz wrote: >> Extend the livepatch list operation to fetch also payloads' metadata. >> This is achieved by extending the sysctl list interface with 2 extra >> guest handles: >> * metadata - an array of arbitrary size strings >> * metadata_len - an array of metadata strings' lengths (uin32_t each) > > uint32_t ACK > >> Payloads' metadata is a string of arbitrary size and does not have an >> upper bound limit. It may also vary in size between payloads. >> In order to let the userland allocate enough space for the incoming >> data add a metadata total size field to the list sysctl operation and >> fill it with total size of all payloads' metadata. > snip> + * `metadata` - Virtual address of where to write the metadata of the payloads. >> + Caller *MUST* allocate enough space to be able to store all received data >> + (i.e. total allocated space *MUST* match the `metadata_total_size` value >> + provided by the hypervisor). Individual payload metadata string can be of >> + arbitrary length. The metadata string format is: key=value\0...key=value\0. >> + * `metadata_len` - Virtual address of where to write the length of each metadata >> + string of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* >> + be of sizeof(uint32_t) (4 bytes). >> If the hypercall returns an positive number, it is the number (upto `nr` >> provided to the hypercall) of the payloads returned, along with `nr` updated >> with the number of remaining payloads, `version` updated (it may be the same >> across hypercalls - if it varies the data is stale and further calls could >> -fail) and the `name_total_size` containing total size of transfered data for >> -the array. The `status`, `name`, and `len` are updated at their designed index >> -value (`idx`) with the returned value of data. >> +fail), `name_total_size` and `metadata_total_size` containing total sizes of >> +transfered data for both the arrays. > > transferred ACK > >> +The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their >> +designed index value (`idx`) with the returned value of data. >> If the hypercall returns -XEN_E2BIG the `nr` is too big and should be >> lowered. >> @@ -780,6 +790,7 @@ The structure is as follow: >> OUT: How many payloads left. */ >> uint32_t pad; /* IN: Must be zero. */ >> uint64_t name_total_size; /* OUT: Total size of all transfer names */ >> + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ >> XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough >> space allocate for nr of them. */ >> XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member >> @@ -788,6 +799,12 @@ The structure is as follow: >> nr of them. */ >> XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. >> Must have nr of them. */ >> + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each >> + member may have an arbitrary length. >> + Must have nr of them. */ >> + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. >> + Must have nr of them. */ >> + >> }; >> > snip >> @@ -744,6 +753,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, >> struct xen_livepatch_status *info, >> char *name, uint32_t *len, >> const uint64_t name_total_size, >> + char *metadata, uint32_t *metadata_len, >> + const uint64_t metadata_total_size, >> unsigned int *done, unsigned int *left) >> { >> int rc; >> @@ -752,13 +763,16 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, >> DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >> DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >> DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >> + DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >> + DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >> uint32_t max_batch_sz, nr; >> uint32_t version = 0, retries = 0; >> uint32_t adjust = 0; >> - off_t name_off = 0; >> - uint64_t name_sz; >> + off_t name_off = 0, metadata_off = 0; >> + uint64_t name_sz, metadata_sz; > > As with the previous patch, I think uint32_t would be more appropriate here as I can't imagine a reason why the metadata would exceed 4 GiB? > > And the same suggestion as with the previous patch to then change off_t (probably to uint32_t). Ok, I will apply both suggestions. > >> - if ( !max || !info || !name || !len || !done || !left ) >> + if ( !max || !info || !name || !len || >> + !metadata || !metadata_len || !done || !left ) >> { >> errno = EINVAL; >> return -1; > snip >> diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h >> index 503be68059..7786864926 100644 >> --- a/xen/include/public/sysctl.h >> +++ b/xen/include/public/sysctl.h >> @@ -920,16 +920,17 @@ struct xen_sysctl_livepatch_get { >> }; >> /* >> - * Retrieve an array of abbreviated status and names of payloads that are >> - * loaded in the hypervisor. >> + * Retrieve an array of abbreviated status, names and metadata of payloads that >> + * are loaded in the hypervisor. >> * >> * If the hypercall returns an positive number, it is the number (up to `nr`) >> * of the payloads returned, along with `nr` updated with the number of remaining >> * payloads, `version` updated (it may be the same across hypercalls. If it varies >> - * the data is stale and further calls could fail) and the name_total_size >> - * containing total size of transfered data for the array. >> - * The `status`, `name`, `len` are updated at their designed index value (`idx`) >> - * with the returned value of data. >> + * the data is stale and further calls could fail), `name_total_size` and >> + * `metadata_total_size` containing total sizes of transfered data for both the > > transferred ACK > >> + * arrays. >> + * The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their >> + * designed index value (`idx`) with the returned value of data. >> * >> * If the hypercall returns E2BIG the `nr` is too big and should be >> * lowered. The upper limit of `nr` is left to the implemention. >> @@ -953,6 +954,7 @@ struct xen_sysctl_livepatch_list { >> OUT: How many payloads left. */ >> uint32_t pad; /* IN: Must be zero. */ >> uint64_t name_total_size; /* OUT: Total size of all transfer names */ >> + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ >> XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough >> space allocate for nr of them. */ >> XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member >> @@ -961,6 +963,11 @@ struct xen_sysctl_livepatch_list { >> nr of them. */ >> XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. >> Must have nr of them. */ >> + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each >> + member may have an arbitrary length. >> + Must have nr of them. */ >> + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. >> + Must have nr of them. */ >> }; >> /* > > Do you think it would be useful for the metadata to be an optional OUT parameter? I could imagine a caller wanting to get a list of live patches without needing/wanting to get all the metadata as well. > Hmm… that would complicate the code to some extent, because we would have to handle 3 request types: names+metadata, names, invalid. The latter worries me most, as we would have to check all the conditions. Not sure if it is worth it, since the metadata can just be retrieved and ignored (of course assuming it is not too heavy). Alternatively we could add an independent interface to retrieve just the metadata. But, when I was looking at this, it seemed like adding a lot of redundant code (because the list operation already has all what’s needed). Could the optional bits be done on top of this change as a separate patch? I would play with this first, to sense how complicated this is. > Secondly, there should also be (optional) metadata retrieval to the XEN_SYSCTL_LIVEPATCH_GET call since a caller may want to get status & metadata for a particular live patch without having to list all of them. That should be done as a separate patch from this one, I think. > Yes, that definitely makes sense and can be useful. I also agree that this should be done as a separate patch. Adding to my TODO. > Thanks, > -- > Ross Lagerwall Thanks for looking at the changes! Best Regards, Pawel Wieczorkiewicz Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Ralf Herbrich Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879
On 9/25/19 5:34 PM, Wieczorkiewicz, Pawel wrote: > > >> On 25. Sep 2019, at 17:47, Ross Lagerwall <ross.lagerwall@citrix.com> wrote: >> >> On 9/16/19 11:59 AM, Pawel Wieczorkiewicz wrote: >>> Extend the livepatch list operation to fetch also payloads' metadata. >>> This is achieved by extending the sysctl list interface with 2 extra >>> guest handles: >>> * metadata - an array of arbitrary size strings >>> * metadata_len - an array of metadata strings' lengths (uin32_t each) >> >> uint32_t > > ACK > >> >>> Payloads' metadata is a string of arbitrary size and does not have an >>> upper bound limit. It may also vary in size between payloads. >>> In order to let the userland allocate enough space for the incoming >>> data add a metadata total size field to the list sysctl operation and >>> fill it with total size of all payloads' metadata. >> snip> + * `metadata` - Virtual address of where to write the metadata of the payloads. >>> + Caller *MUST* allocate enough space to be able to store all received data >>> + (i.e. total allocated space *MUST* match the `metadata_total_size` value >>> + provided by the hypervisor). Individual payload metadata string can be of >>> + arbitrary length. The metadata string format is: key=value\0...key=value\0. >>> + * `metadata_len` - Virtual address of where to write the length of each metadata >>> + string of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* >>> + be of sizeof(uint32_t) (4 bytes). >>> If the hypercall returns an positive number, it is the number (upto `nr` >>> provided to the hypercall) of the payloads returned, along with `nr` updated >>> with the number of remaining payloads, `version` updated (it may be the same >>> across hypercalls - if it varies the data is stale and further calls could >>> -fail) and the `name_total_size` containing total size of transfered data for >>> -the array. The `status`, `name`, and `len` are updated at their designed index >>> -value (`idx`) with the returned value of data. >>> +fail), `name_total_size` and `metadata_total_size` containing total sizes of >>> +transfered data for both the arrays. >> >> transferred > > ACK > >> >>> +The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their >>> +designed index value (`idx`) with the returned value of data. >>> If the hypercall returns -XEN_E2BIG the `nr` is too big and should be >>> lowered. >>> @@ -780,6 +790,7 @@ The structure is as follow: >>> OUT: How many payloads left. */ >>> uint32_t pad; /* IN: Must be zero. */ >>> uint64_t name_total_size; /* OUT: Total size of all transfer names */ >>> + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ >>> XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough >>> space allocate for nr of them. */ >>> XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member >>> @@ -788,6 +799,12 @@ The structure is as follow: >>> nr of them. */ >>> XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. >>> Must have nr of them. */ >>> + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each >>> + member may have an arbitrary length. >>> + Must have nr of them. */ >>> + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. >>> + Must have nr of them. */ >>> + >>> }; >>> >> snip >>> @@ -744,6 +753,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, >>> struct xen_livepatch_status *info, >>> char *name, uint32_t *len, >>> const uint64_t name_total_size, >>> + char *metadata, uint32_t *metadata_len, >>> + const uint64_t metadata_total_size, >>> unsigned int *done, unsigned int *left) >>> { >>> int rc; >>> @@ -752,13 +763,16 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, >>> DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >>> DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >>> DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >>> + DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >>> + DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); >>> uint32_t max_batch_sz, nr; >>> uint32_t version = 0, retries = 0; >>> uint32_t adjust = 0; >>> - off_t name_off = 0; >>> - uint64_t name_sz; >>> + off_t name_off = 0, metadata_off = 0; >>> + uint64_t name_sz, metadata_sz; >> >> As with the previous patch, I think uint32_t would be more appropriate here as I can't imagine a reason why the metadata would exceed 4 GiB? >> >> And the same suggestion as with the previous patch to then change off_t (probably to uint32_t). > > Ok, I will apply both suggestions. > >> >>> - if ( !max || !info || !name || !len || !done || !left ) >>> + if ( !max || !info || !name || !len || >>> + !metadata || !metadata_len || !done || !left ) >>> { >>> errno = EINVAL; >>> return -1; >> snip >>> diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h >>> index 503be68059..7786864926 100644 >>> --- a/xen/include/public/sysctl.h >>> +++ b/xen/include/public/sysctl.h >>> @@ -920,16 +920,17 @@ struct xen_sysctl_livepatch_get { >>> }; >>> /* >>> - * Retrieve an array of abbreviated status and names of payloads that are >>> - * loaded in the hypervisor. >>> + * Retrieve an array of abbreviated status, names and metadata of payloads that >>> + * are loaded in the hypervisor. >>> * >>> * If the hypercall returns an positive number, it is the number (up to `nr`) >>> * of the payloads returned, along with `nr` updated with the number of remaining >>> * payloads, `version` updated (it may be the same across hypercalls. If it varies >>> - * the data is stale and further calls could fail) and the name_total_size >>> - * containing total size of transfered data for the array. >>> - * The `status`, `name`, `len` are updated at their designed index value (`idx`) >>> - * with the returned value of data. >>> + * the data is stale and further calls could fail), `name_total_size` and >>> + * `metadata_total_size` containing total sizes of transfered data for both the >> >> transferred > > ACK > >> >>> + * arrays. >>> + * The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their >>> + * designed index value (`idx`) with the returned value of data. >>> * >>> * If the hypercall returns E2BIG the `nr` is too big and should be >>> * lowered. The upper limit of `nr` is left to the implemention. >>> @@ -953,6 +954,7 @@ struct xen_sysctl_livepatch_list { >>> OUT: How many payloads left. */ >>> uint32_t pad; /* IN: Must be zero. */ >>> uint64_t name_total_size; /* OUT: Total size of all transfer names */ >>> + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ >>> XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough >>> space allocate for nr of them. */ >>> XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member >>> @@ -961,6 +963,11 @@ struct xen_sysctl_livepatch_list { >>> nr of them. */ >>> XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. >>> Must have nr of them. */ >>> + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each >>> + member may have an arbitrary length. >>> + Must have nr of them. */ >>> + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. >>> + Must have nr of them. */ >>> }; >>> /* >> >> Do you think it would be useful for the metadata to be an optional OUT parameter? I could imagine a caller wanting to get a list of live patches without needing/wanting to get all the metadata as well. >> > > Hmm… that would complicate the code to some extent, because we would have to handle 3 request types: names+metadata, names, invalid. > The latter worries me most, as we would have to check all the conditions. > > Not sure if it is worth it, since the metadata can just be retrieved and ignored (of course assuming it is not too heavy). > > Alternatively we could add an independent interface to retrieve just the metadata. > But, when I was looking at this, it seemed like adding a lot of redundant code (because the list operation already has all what’s needed). > > Could the optional bits be done on top of this change as a separate patch? > > I would play with this first, to sense how complicated this is. Sure, it doesn't have to be done right now. It was just wondering if it might be useful or for potential improvement. I agree that it might add some complications for little benefit. > >> Secondly, there should also be (optional) metadata retrieval to the XEN_SYSCTL_LIVEPATCH_GET call since a caller may want to get status & metadata for a particular live patch without having to list all of them. That should be done as a separate patch from this one, I think. >> > > Yes, that definitely makes sense and can be useful. I also agree that this should be done as a separate patch. Adding to my TODO. > >> Thanks, >> -- >> Ross Lagerwall > > Thanks for looking at the changes! > > Best Regards, > Pawel Wieczorkiewicz > > > > > > > Amazon Development Center Germany GmbH > Krausenstr. 38 > 10117 Berlin > Geschaeftsfuehrung: Christian Schlaeger, Ralf Herbrich > Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B > Sitz: Berlin > Ust-ID: DE 289 237 879 > >
diff --git a/docs/misc/livepatch.pandoc b/docs/misc/livepatch.pandoc index e7bcc70f5a..15217e3452 100644 --- a/docs/misc/livepatch.pandoc +++ b/docs/misc/livepatch.pandoc @@ -707,8 +707,8 @@ The structure is as follow: ### XEN_SYSCTL_LIVEPATCH_LIST (2) -Retrieve an array of abbreviated status and names of payloads that are loaded in the -hypervisor. +Retrieve an array of abbreviated status, names and metadata of payloads that are +loaded in the hypervisor. The caller provides: @@ -717,8 +717,9 @@ The caller provides: * `idx` Index iterator. The index into the hypervisor's payload count. It is recommended that on first invocation zero be used so that `nr` (which the hypervisor will update with the remaining payload count) be provided. - Also the hypervisor will provide `version` with the most current value and - calculated total size for all payloads' names. + Also the hypervisor will provide `version` with the most current value, + calculated total size of all payloads' names and calculated total size of + all payload's metadata. * `nr` The max number of entries to populate. Can be zero which will result in the hypercall being a probing one and return the number of payloads (and update the `version`). @@ -734,14 +735,23 @@ The caller provides: * `len` - Virtual address of where to write the length of each unique name of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* be of sizeof(uint32_t) (4 bytes). + * `metadata` - Virtual address of where to write the metadata of the payloads. + Caller *MUST* allocate enough space to be able to store all received data + (i.e. total allocated space *MUST* match the `metadata_total_size` value + provided by the hypervisor). Individual payload metadata string can be of + arbitrary length. The metadata string format is: key=value\0...key=value\0. + * `metadata_len` - Virtual address of where to write the length of each metadata + string of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* + be of sizeof(uint32_t) (4 bytes). If the hypercall returns an positive number, it is the number (upto `nr` provided to the hypercall) of the payloads returned, along with `nr` updated with the number of remaining payloads, `version` updated (it may be the same across hypercalls - if it varies the data is stale and further calls could -fail) and the `name_total_size` containing total size of transfered data for -the array. The `status`, `name`, and `len` are updated at their designed index -value (`idx`) with the returned value of data. +fail), `name_total_size` and `metadata_total_size` containing total sizes of +transfered data for both the arrays. +The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their +designed index value (`idx`) with the returned value of data. If the hypercall returns -XEN_E2BIG the `nr` is too big and should be lowered. @@ -780,6 +790,7 @@ The structure is as follow: OUT: How many payloads left. */ uint32_t pad; /* IN: Must be zero. */ uint64_t name_total_size; /* OUT: Total size of all transfer names */ + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough space allocate for nr of them. */ XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member @@ -788,6 +799,12 @@ The structure is as follow: nr of them. */ XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. Must have nr of them. */ + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each + member may have an arbitrary length. + Must have nr of them. */ + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. + Must have nr of them. */ + }; ### XEN_SYSCTL_LIVEPATCH_ACTION (3) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 252675f117..4bafd8541a 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2552,7 +2552,7 @@ int xc_livepatch_get(xc_interface *xch, /* * Get a number of available payloads and get actual total size of - * the payloads' name array. + * the payloads' name and metadata arrays. * * This functions is typically executed first before the xc_livepatch_list() * to obtain the sizes and correctly allocate all necessary data resources. @@ -2563,13 +2563,16 @@ int xc_livepatch_get(xc_interface *xch, * will contain the hypercall error code value. */ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, - uint64_t *name_total_size); + uint64_t *name_total_size, + uint64_t *metadata_total_size); /* * The heart of this function is to get an array of the following objects: * - xen_livepatch_status_t: states and return codes of payloads * - name: names of payloads * - len: lengths of corresponding payloads' names + * - metadata: payloads' metadata + * - metadata_len: lengths of corresponding payloads' metadata * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -2582,12 +2585,13 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * It is expected that the caller of this function will first issue the * xc_livepatch_list_get_sizes() in order to obtain total sizes of names - * as well as the current number of payload entries. - * The total sizes are required and supplied via the 'name_total_size' - * parameter. + * and all metadata as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' and + * 'metadata_total_size' parameters. * * The 'max' is to be provided by the caller with the maximum number of - * entries that 'info', 'name', 'len' arrays can be filled up with. + * entries that 'info', 'name', 'len', 'metadata' and 'metadata_len' arrays + * can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. @@ -2596,6 +2600,10 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * Each entry in the 'len' array is expected to be of uint32_t size. * + * Each entry in the 'metadata' array may have an arbitrary size. + * + * Each entry in the 'metadata_len' array is expected to be of uint32_t size. + * * The return value is zero if the hypercall completed successfully. * Note that the return value is _not_ the amount of entries filled * out - that is saved in 'done'. @@ -2610,6 +2618,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, struct xen_livepatch_status *info, char *name, uint32_t *len, const uint64_t name_total_size, + char *metadata, uint32_t *metadata_len, + const uint64_t metadata_total_size, unsigned int *done, unsigned int *left); /* diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index d787f3f29f..7dc9fd83ed 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -663,7 +663,7 @@ int xc_livepatch_get(xc_interface *xch, /* * Get a number of available payloads and get actual total size of - * the payloads' name array. + * the payloads' name and metadata arrays. * * This functions is typically executed first before the xc_livepatch_list() * to obtain the sizes and correctly allocate all necessary data resources. @@ -674,12 +674,13 @@ int xc_livepatch_get(xc_interface *xch, * will contain the hypercall error code value. */ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, - uint64_t *name_total_size) + uint64_t *name_total_size, + uint64_t *metadata_total_size) { DECLARE_SYSCTL; int rc; - if ( !nr || !name_total_size ) + if ( !nr || !name_total_size || !metadata_total_size ) { errno = EINVAL; return -1; @@ -695,6 +696,7 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, *nr = sysctl.u.livepatch.u.list.nr; *name_total_size = sysctl.u.livepatch.u.list.name_total_size; + *metadata_total_size = sysctl.u.livepatch.u.list.metadata_total_size; return 0; } @@ -704,6 +706,8 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * - xen_livepatch_status_t: states and return codes of payloads * - name: names of payloads * - len: lengths of corresponding payloads' names + * - metadata: payloads' metadata + * - metadata_len: lengths of corresponding payloads' metadata * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -716,12 +720,13 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * It is expected that the caller of this function will first issue the * xc_livepatch_list_get_sizes() in order to obtain total sizes of names - * as well as the current number of payload entries. - * The total sizes are required and supplied via the 'name_total_size' - * parameter. + * and all metadata as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' and + * 'metadata_total_size' parameters. * * The 'max' is to be provided by the caller with the maximum number of - * entries that 'info', 'name', 'len' arrays can be filled up with. + * entries that 'info', 'name', 'len', 'metadata' and 'metadata_len' arrays + * can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. @@ -730,6 +735,10 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * Each entry in the 'len' array is expected to be of uint32_t size. * + * Each entry in the 'metadata' array may have an arbitrary size. + * + * Each entry in the 'metadata_len' array is expected to be of uint32_t size. + * * The return value is zero if the hypercall completed successfully. * Note that the return value is _not_ the amount of entries filled * out - that is saved in 'done'. @@ -744,6 +753,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, struct xen_livepatch_status *info, char *name, uint32_t *len, const uint64_t name_total_size, + char *metadata, uint32_t *metadata_len, + const uint64_t metadata_total_size, unsigned int *done, unsigned int *left) { int rc; @@ -752,13 +763,16 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); uint32_t max_batch_sz, nr; uint32_t version = 0, retries = 0; uint32_t adjust = 0; - off_t name_off = 0; - uint64_t name_sz; + off_t name_off = 0, metadata_off = 0; + uint64_t name_sz, metadata_sz; - if ( !max || !info || !name || !len || !done || !left ) + if ( !max || !info || !name || !len || + !metadata || !metadata_len || !done || !left ) { errno = EINVAL; return -1; @@ -777,10 +791,11 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, max_batch_sz = max; name_sz = name_total_size; + metadata_sz = metadata_total_size; *done = 0; *left = 0; do { - uint64_t _name_sz; + uint64_t _name_sz, _metadata_sz; /* * The first time we go in this loop our 'max' may be bigger @@ -803,10 +818,14 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, HYPERCALL_BOUNCE_SET_SIZE(info, nr * sizeof(*info)); HYPERCALL_BOUNCE_SET_SIZE(name, name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, nr * sizeof(*len)); + HYPERCALL_BOUNCE_SET_SIZE(metadata, metadata_sz); + HYPERCALL_BOUNCE_SET_SIZE(metadata_len, nr * sizeof(*metadata_len)); /* Move the pointer to proper offset into 'info'. */ (HYPERCALL_BUFFER(info))->ubuf = info + *done; (HYPERCALL_BUFFER(name))->ubuf = name + name_off; (HYPERCALL_BUFFER(len))->ubuf = len + *done; + (HYPERCALL_BUFFER(metadata))->ubuf = metadata + metadata_off; + (HYPERCALL_BUFFER(metadata_len))->ubuf = metadata_len + *done; /* Allocate memory. */ rc = xc_hypercall_bounce_pre(xch, info); if ( rc ) @@ -820,9 +839,19 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, if ( rc ) break; + rc = xc_hypercall_bounce_pre(xch, metadata); + if ( rc ) + break; + + rc = xc_hypercall_bounce_pre(xch, metadata_len); + if ( rc ) + break; + set_xen_guest_handle(sysctl.u.livepatch.u.list.status, info); set_xen_guest_handle(sysctl.u.livepatch.u.list.name, name); set_xen_guest_handle(sysctl.u.livepatch.u.list.len, len); + set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata, metadata); + set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata_len, metadata_len); rc = do_sysctl(xch, &sysctl); /* @@ -839,6 +868,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); continue; } else if ( rc < 0 ) /* For all other errors we bail out. */ @@ -863,6 +894,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); continue; } @@ -875,17 +908,24 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, } *left = sysctl.u.livepatch.u.list.nr; /* Total remaining count. */ _name_sz = sysctl.u.livepatch.u.list.name_total_size; /* Total received name size. */ + _metadata_sz = sysctl.u.livepatch.u.list.metadata_total_size; /* Total received metadata size. */ /* Copy only up 'rc' of data' - we could add 'min(rc,nr) if desired. */ HYPERCALL_BOUNCE_SET_SIZE(info, (rc * sizeof(*info))); HYPERCALL_BOUNCE_SET_SIZE(name, _name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, (rc * sizeof(*len))); + HYPERCALL_BOUNCE_SET_SIZE(metadata, _metadata_sz); + HYPERCALL_BOUNCE_SET_SIZE(metadata_len, (rc * sizeof(*metadata_len))); /* Bounce the data and free the bounce buffer. */ xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); name_sz -= _name_sz; name_off += _name_sz; + metadata_sz -= _metadata_sz; + metadata_off += _metadata_sz; /* And update how many elements of info we have copied into. */ *done += rc; @@ -898,6 +938,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, len); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, info); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); } return rc > 0 ? 0 : rc; diff --git a/tools/misc/xen-livepatch.c b/tools/misc/xen-livepatch.c index 8ac3d567fc..f17340a2ee 100644 --- a/tools/misc/xen-livepatch.c +++ b/tools/misc/xen-livepatch.c @@ -69,9 +69,11 @@ static int list_func(int argc, char *argv[]) unsigned int nr, done, left, i; xen_livepatch_status_t *info = NULL; char *name = NULL; + char *metadata = NULL; uint32_t *len = NULL; - uint64_t name_total_size; - off_t name_off; + uint32_t *metadata_len = NULL; + uint64_t name_total_size, metadata_total_size; + off_t name_off, metadata_off; int rc = ENOMEM; if ( argc ) @@ -81,7 +83,7 @@ static int list_func(int argc, char *argv[]) } done = left = 0; - rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size); + rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size, &metadata_total_size); if ( rc ) { rc = errno; @@ -109,12 +111,23 @@ static int list_func(int argc, char *argv[]) if ( !len ) goto error_len; + metadata = malloc(metadata_total_size * sizeof(*metadata) + 1); + if ( !metadata ) + goto error_metadata; + + metadata_len = malloc(nr * sizeof(*metadata_len)); + if ( !metadata_len ) + goto error_metadata_len; + memset(info, 'A', nr * sizeof(*info)); memset(name, 'B', name_total_size * sizeof(*name)); memset(len, 'C', nr * sizeof(*len)); - name_off = 0; + memset(metadata, 'D', metadata_total_size * sizeof(*metadata) + 1); + memset(metadata_len, 'E', nr * sizeof(*metadata_len)); + name_off = metadata_off = 0; - rc = xc_livepatch_list(xch, nr, 0, info, name, len, name_total_size, &done, &left); + rc = xc_livepatch_list(xch, nr, 0, info, name, len, name_total_size, + metadata, metadata_len, metadata_total_size, &done, &left); if ( rc || done != nr || left > 0) { rc = errno; @@ -124,23 +137,35 @@ static int list_func(int argc, char *argv[]) goto error; } - fprintf(stdout," ID | status\n" - "----------------------------------------+------------\n"); + fprintf(stdout," ID | status | metadata\n" + "----------------------------------------+------------+---------------\n"); for ( i = 0; i < done; i++ ) { + unsigned int j; char *name_str = name + name_off; + char *metadata_str = metadata + metadata_off; printf("%-40.*s| %s", len[i], name_str, state2str(info[i].state)); if ( info[i].rc ) - printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc)); + printf(" (%d, %s) | ", -info[i].rc, strerror(-info[i].rc)); else - puts(""); + printf(" | "); + + /* Replace all '\0' with semi-colons. */ + for ( j = 0; metadata_len[i] && j < metadata_len[i] - 1; j++ ) + metadata_str[j] = (metadata_str[j] ?: ';'); + printf("%.*s\n", metadata_len[i], metadata_str); name_off += len[i]; + metadata_off += metadata_len[i]; } error: + free(metadata_len); +error_metadata_len: + free(metadata); +error_metadata: free(len); error_len: free(name); diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index e800382479..bdf2d1fc6d 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -1164,7 +1164,8 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) if ( list->nr && (!guest_handle_okay(list->status, list->nr) || - !guest_handle_okay(list->len, list->nr)) ) + !guest_handle_okay(list->len, list->nr) || + !guest_handle_okay(list->metadata_len, list->nr)) ) return -EINVAL; spin_lock(&payload_lock); @@ -1175,13 +1176,14 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) } list->name_total_size = 0; + list->metadata_total_size = 0; if ( list->nr ) { - uint64_t name_offset = 0; + uint64_t name_offset = 0, metadata_offset = 0; list_for_each_entry( data, &payload_list, list ) { - uint32_t name_len; + uint32_t name_len, metadata_len; if ( list->idx > i++ ) continue; @@ -1192,8 +1194,13 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) name_len = strlen(data->name) + 1; list->name_total_size += name_len; + metadata_len = data->metadata.len; + list->metadata_total_size += metadata_len; + if ( !guest_handle_subrange_okay(list->name, name_offset, - name_offset + name_len - 1) ) + name_offset + name_len - 1) || + !guest_handle_subrange_okay(list->metadata, metadata_offset, + metadata_offset + metadata_len - 1) ) { rc = -EINVAL; break; @@ -1203,7 +1210,10 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) if ( __copy_to_guest_offset(list->name, name_offset, data->name, name_len) || __copy_to_guest_offset(list->len, idx, &name_len, 1) || - __copy_to_guest_offset(list->status, idx, &status, 1) ) + __copy_to_guest_offset(list->status, idx, &status, 1) || + __copy_to_guest_offset(list->metadata, metadata_offset, + data->metadata.data, metadata_len) || + __copy_to_guest_offset(list->metadata_len, idx, &metadata_len, 1) ) { rc = -EFAULT; break; @@ -1211,6 +1221,7 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) idx++; name_offset += name_len; + metadata_offset += metadata_len; if ( (idx >= list->nr) || hypercall_preempt_check() ) break; @@ -1221,6 +1232,7 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) list_for_each_entry( data, &payload_list, list ) { list->name_total_size += strlen(data->name) + 1; + list->metadata_total_size += data->metadata.len; } } list->nr = payload_cnt - i; /* Remaining amount. */ diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 503be68059..7786864926 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -920,16 +920,17 @@ struct xen_sysctl_livepatch_get { }; /* - * Retrieve an array of abbreviated status and names of payloads that are - * loaded in the hypervisor. + * Retrieve an array of abbreviated status, names and metadata of payloads that + * are loaded in the hypervisor. * * If the hypercall returns an positive number, it is the number (up to `nr`) * of the payloads returned, along with `nr` updated with the number of remaining * payloads, `version` updated (it may be the same across hypercalls. If it varies - * the data is stale and further calls could fail) and the name_total_size - * containing total size of transfered data for the array. - * The `status`, `name`, `len` are updated at their designed index value (`idx`) - * with the returned value of data. + * the data is stale and further calls could fail), `name_total_size` and + * `metadata_total_size` containing total sizes of transfered data for both the + * arrays. + * The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their + * designed index value (`idx`) with the returned value of data. * * If the hypercall returns E2BIG the `nr` is too big and should be * lowered. The upper limit of `nr` is left to the implemention. @@ -953,6 +954,7 @@ struct xen_sysctl_livepatch_list { OUT: How many payloads left. */ uint32_t pad; /* IN: Must be zero. */ uint64_t name_total_size; /* OUT: Total size of all transfer names */ + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough space allocate for nr of them. */ XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member @@ -961,6 +963,11 @@ struct xen_sysctl_livepatch_list { nr of them. */ XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. Must have nr of them. */ + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each + member may have an arbitrary length. + Must have nr of them. */ + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. + Must have nr of them. */ }; /*