Re: [Xen-devel] [PATCH v3 12/12] livepatch: Add python bindings for livepatch operations

2019-09-26 Thread Wieczorkiewicz, Pawel


> On 25. Sep 2019, at 18:47, Ross Lagerwall  wrote:
> 
> On 9/16/19 12:40 PM, Pawel Wieczorkiewicz wrote:
>> Extend the XC python bindings library to support also all common
>> livepatch operations and actions.
>> Add the python bindings for the following operations:
>> - status (pyxc_livepatch_status):
>>   Requires a payload name as an input.
>>   Returns a status dict containing a state string and a return code
>>   integer.
>> - action (pyxc_livepatch_action):
>>   Requires a payload name and an action id as an input. Timeout and
>>   flags are optional parameters.
>>   Returns a return code integer.
>> - upload (pyxc_livepatch_upload):
>>   Requires a payload name and a module's filename as an input.
>>   Returns a return code integer.
>> - list (pyxc_livepatch_list):
>>   Takes no parameters.
>>   Returns a list of dicts containing each payload's:
>>   * name as a string
>>   * state as a string
>>   * return code as an integer
>>   * list of metadata key=value strings
>> Each functions throws an exception error based on the errno value
>> received from its corresponding libxc function call.
>> Signed-off-by: Pawel Wieczorkiewicz 
>> Reviewed-by: Martin Mazein 
>> Reviewed-by: Andra-Irina Paraschiv 
>> Reviewed-by: Leonard Foerster 
>> Reviewed-by: Norbert Manthey 
>> Acked-by: Marek Marczykowski-Górecki 
> 
> This will be very useful, thanks!
> 
>> ---
>> Changed since v1:
>>   * changed PyList_Append() with PyList_SetItem() as requested by
>> Marek
>>  tools/python/xen/lowlevel/xc/xc.c | 273 
>> ++
>>  1 file changed, 273 insertions(+)
> snip> +static PyObject *pyxc_livepatch_action(XcObject *self,
>> +   PyObject *args,
>> +   PyObject *kwds)
>> +{
>> +int (*action_func)(xc_interface *xch, char *name, uint32_t timeout, 
>> uint64_t flags);
>> +char *name;
>> +unsigned int action;
>> +uint32_t timeout;
>> +uint64_t flags;
>> +int rc;
>> +
>> +static char *kwd_list[] = { "name", "action", "timeout", "flags", NULL 
>> };
>> +
>> +if ( !PyArg_ParseTupleAndKeywords(args, kwds, "sI|Ik", kwd_list,
>> +  , , , ) )
>> +goto error;
>> +
>> +switch (action)
>> +{
>> +case LIVEPATCH_ACTION_UNLOAD:
>> +action_func = xc_livepatch_unload;
>> +break;
>> +case LIVEPATCH_ACTION_REVERT:
>> +action_func = xc_livepatch_revert;
>> +break;
>> +case LIVEPATCH_ACTION_APPLY:
>> +action_func = xc_livepatch_apply;
>> +break;
>> +case LIVEPATCH_ACTION_REPLACE:
>> +action_func = xc_livepatch_replace;
>> +break;
>> +default:
>> +goto error;
>> +}
>> +
>> +rc = action_func(self->xc_handle, name, timeout, flags);
>> +if ( rc )
>> +goto error;
>> +
>> +return Py_BuildValue("i", rc);
> 
> For this and all the other functions which return zero on success, IMO 
> returning None would be more Pythonic.
> 

OK, will change.

>> +error:
>> +return pyxc_error_to_exception(self->xc_handle);
>> +}
>> +
>> +static PyObject *pyxc_livepatch_upload(XcObject *self,
>> +   PyObject *args,
>> +   PyObject *kwds)
>> +{
>> +unsigned char *fbuf = MAP_FAILED;
>> +char *name, *filename;
>> +struct stat buf;
>> +int fd = 0, rc;
>> +ssize_t len;
>> +
>> +static char *kwd_list[] = { "name", "filename", NULL };
>> +
>> +if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwd_list,
>> +  , ))
>> +goto error;
>> +
>> +fd = open(filename, O_RDONLY);
>> +if ( fd < 0 )
>> +goto error;
>> +
>> +if ( stat(filename, ) != 0 )
>> +goto error;
> 
> I think it would be better to use fstat() to avoid a second path lookup 
> potentially pointing to a different file.
> 

Ah, certainly! Will fix.

>> +
>> +len = buf.st_size;
>> +fbuf = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
>> +if ( fbuf == MAP_FAILED )
>> +goto error;
>> +
>> +rc = xc_livepatch_upload(self->xc_handle, name, fbuf, len);
>> +if ( rc )
>> +goto error;
>> +
>> +if ( munmap(fbuf, len) )
>> +{
>> +fbuf = MAP_FAILED;
>> +goto error;
>> +}
>> +close(fd);
>> +
>> +return Py_BuildValue("i", rc);;
> 
> Stray semicolon

ACK

> 
>> +error:
>> +if ( fbuf != MAP_FAILED )
>> +munmap(fbuf, len);
>> +if ( fd >= 0 )
>> +close(fd);
> 
> You should probably save & restore errno so you can return the original error.
> 

Yes, that’s right. Will fix.

>> +return pyxc_error_to_exception(self->xc_handle);
> 
> Maybe you can have a conditional return to avoid duplicating the munmap() & 
> close()? E.g.
> 
> return rc ? pyxc_error_to_exception(self->xc_handle) : …
> 

Oh, this indeed can work. Let me apply that. Thanks.

>> +}
>> +
>> +static 

Re: [Xen-devel] [PATCH v3 12/12] livepatch: Add python bindings for livepatch operations

2019-09-25 Thread Ross Lagerwall

On 9/16/19 12:40 PM, Pawel Wieczorkiewicz wrote:

Extend the XC python bindings library to support also all common
livepatch operations and actions.

Add the python bindings for the following operations:
- status (pyxc_livepatch_status):
   Requires a payload name as an input.
   Returns a status dict containing a state string and a return code
   integer.
- action (pyxc_livepatch_action):
   Requires a payload name and an action id as an input. Timeout and
   flags are optional parameters.
   Returns a return code integer.
- upload (pyxc_livepatch_upload):
   Requires a payload name and a module's filename as an input.
   Returns a return code integer.
- list (pyxc_livepatch_list):
   Takes no parameters.
   Returns a list of dicts containing each payload's:
   * name as a string
   * state as a string
   * return code as an integer
   * list of metadata key=value strings

Each functions throws an exception error based on the errno value
received from its corresponding libxc function call.

Signed-off-by: Pawel Wieczorkiewicz 
Reviewed-by: Martin Mazein 
Reviewed-by: Andra-Irina Paraschiv 
Reviewed-by: Leonard Foerster 
Reviewed-by: Norbert Manthey 
Acked-by: Marek Marczykowski-Górecki 


This will be very useful, thanks!


---
Changed since v1:
   * changed PyList_Append() with PyList_SetItem() as requested by
 Marek

  tools/python/xen/lowlevel/xc/xc.c | 273 ++
  1 file changed, 273 insertions(+)


snip> +static PyObject *pyxc_livepatch_action(XcObject *self,

+   PyObject *args,
+   PyObject *kwds)
+{
+int (*action_func)(xc_interface *xch, char *name, uint32_t timeout, 
uint64_t flags);
+char *name;
+unsigned int action;
+uint32_t timeout;
+uint64_t flags;
+int rc;
+
+static char *kwd_list[] = { "name", "action", "timeout", "flags", NULL };
+
+if ( !PyArg_ParseTupleAndKeywords(args, kwds, "sI|Ik", kwd_list,
+  , , , ) )
+goto error;
+
+switch (action)
+{
+case LIVEPATCH_ACTION_UNLOAD:
+action_func = xc_livepatch_unload;
+break;
+case LIVEPATCH_ACTION_REVERT:
+action_func = xc_livepatch_revert;
+break;
+case LIVEPATCH_ACTION_APPLY:
+action_func = xc_livepatch_apply;
+break;
+case LIVEPATCH_ACTION_REPLACE:
+action_func = xc_livepatch_replace;
+break;
+default:
+goto error;
+}
+
+rc = action_func(self->xc_handle, name, timeout, flags);
+if ( rc )
+goto error;
+
+return Py_BuildValue("i", rc);


For this and all the other functions which return zero on success, IMO 
returning None would be more Pythonic.



+error:
+return pyxc_error_to_exception(self->xc_handle);
+}
+
+static PyObject *pyxc_livepatch_upload(XcObject *self,
+   PyObject *args,
+   PyObject *kwds)
+{
+unsigned char *fbuf = MAP_FAILED;
+char *name, *filename;
+struct stat buf;
+int fd = 0, rc;
+ssize_t len;
+
+static char *kwd_list[] = { "name", "filename", NULL };
+
+if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwd_list,
+  , ))
+goto error;
+
+fd = open(filename, O_RDONLY);
+if ( fd < 0 )
+goto error;
+
+if ( stat(filename, ) != 0 )
+goto error;


I think it would be better to use fstat() to avoid a second path lookup 
potentially pointing to a different file.



+
+len = buf.st_size;
+fbuf = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
+if ( fbuf == MAP_FAILED )
+goto error;
+
+rc = xc_livepatch_upload(self->xc_handle, name, fbuf, len);
+if ( rc )
+goto error;
+
+if ( munmap(fbuf, len) )
+{
+fbuf = MAP_FAILED;
+goto error;
+}
+close(fd);
+
+return Py_BuildValue("i", rc);;


Stray semicolon


+error:
+if ( fbuf != MAP_FAILED )
+munmap(fbuf, len);
+if ( fd >= 0 )
+close(fd);


You should probably save & restore errno so you can return the original 
error.



+return pyxc_error_to_exception(self->xc_handle);


Maybe you can have a conditional return to avoid duplicating the 
munmap() & close()? E.g.


return rc ? pyxc_error_to_exception(self->xc_handle) : ...


+}
+
+static PyObject *pyxc_livepatch_list(XcObject *self)
+{
+PyObject *list;
+unsigned int nr, done, left, i;
+xen_livepatch_status_t *info = NULL;
+char *name = NULL;
+char *metadata = NULL;
+uint32_t *len = NULL;
+uint32_t *metadata_len = NULL;
+uint64_t name_total_size, metadata_total_size;
+off_t name_off, metadata_off;
+int rc;
+
+rc = xc_livepatch_list_get_sizes(self->xc_handle, ,
+ _total_size, _total_size);
+if ( rc )
+goto error;
+
+if ( nr == 0 )
+return PyList_New(0);
+
+rc =