All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: valerio@aimale.com, qemu-devel@nongnu.org
Cc: armbru@redhat.com, ehabkost@redhat.com, lcapitulino@redhat.com
Subject: Re: [Qemu-devel] [PATCH] QEMU patch for libvmi to introspect QEMU/kvm virtual machines. Usually this patch is distributed with libvmi, but, it might be more useful to have it in the QEMU source permanently.
Date: Mon, 19 Oct 2015 15:33:42 -0600	[thread overview]
Message-ID: <562561B6.9010100@redhat.com> (raw)
In-Reply-To: <1444952643-5033-2-git-send-email-valerio@aimale.com>

[-- Attachment #1: Type: text/plain, Size: 10877 bytes --]

On 10/15/2015 05:44 PM, valerio@aimale.com wrote:
> From: Valerio Aimale <valerio@aimale.com>

Long subject line, and no message body.  Remember, you want the subject
line to be a one-line short summary of 'what', then the commit body
message for 'why', as in:

qmp: add command for libvmi memory introspection

In the past, libvmi was relying on an out-of-tree patch to qemu that
provides a new QMP command pmemaccess.  It is now time to make this
command part of qemu.

pmemaccess is used to create a side-channel communication path that can
more effectively be used to query lots of small memory chunks without
the overhead of one QMP command per chunk. ...

> 
> ---

You are missing a Signed-off-by: tag.  Without that, we cannot take your
patch.  But at least we can still review it:

>  Makefile.target  |   2 +-
>  hmp-commands.hx  |  14 ++++
>  hmp.c            |   9 +++
>  hmp.h            |   1 +
>  memory-access.c  | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  memory-access.h  |  21 ++++++
>  qapi-schema.json |  28 ++++++++
>  qmp-commands.hx  |  23 +++++++
>  8 files changed, 303 insertions(+), 1 deletion(-)
>  create mode 100644 memory-access.c
>  create mode 100644 memory-access.h
> 
> diff --git a/Makefile.target b/Makefile.target
> index 962d004..940ab51 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -131,7 +131,7 @@ endif #CONFIG_BSD_USER
>  #########################################################
>  # System emulator target
>  ifdef CONFIG_SOFTMMU
> -obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
> +obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o memory-access.o

This line is now over 80 columns; please wrap.

>  obj-y += qtest.o bootdevice.o

In fact, you could have just appended it into this line instead.

> +++ b/hmp-commands.hx
> @@ -807,6 +807,20 @@ save to disk physical memory dump starting at @var{addr} of size @var{size}.
>  ETEXI
>  
>      {
> +        .name       = "pmemaccess",
> +        .args_type  = "path:s",
> +        .params     = "file",
> +        .help       = "open A UNIX Socket access to physical memory at 'path'",

s/A/a/

Awkward grammar; better might be:

open a Unix socket at 'path' for use in accessing physical memory

Please also document where the user can find the protocol that will be
used across the side-channel socket thus opened.


> +++ b/memory-access.c
> @@ -0,0 +1,206 @@
> +/*
> + * Access guest physical memory via a domain socket.
> + *
> + * Copyright (C) 2011 Sandia National Laboratories
> + * Original Author: Bryan D. Payne (bdpayne@acm.org)
> + * 
> + * Refurbished for modern QEMU by Valerio Aimale (valerio@aimale.com), in 2015
> + */

I would expect at least something under docs/ in addition to this file
(the protocol spoken over the socket should be well-documented, and not
just by reading the source code).  Compare with docs/qmp-spec.txt.

> +struct request{
> +    uint8_t type;      // 0 quit, 1 read, 2 write, ... rest reserved
> +    uint64_t address;  // address to read from OR write to
> +    uint64_t length;   // number of bytes to read OR write

Any particular endianness constraints to worry about?

> +};
> +
> +static uint64_t
> +connection_read_memory (uint64_t user_paddr, void *buf, uint64_t user_len)
> +{
> +    hwaddr paddr = (hwaddr) user_paddr;
> +    hwaddr len = (hwaddr) user_len;
> +    void *guestmem = cpu_physical_memory_map(paddr, &len, 0);
> +    if (!guestmem){

Space before {, throughout the patch.

> +static void
> +send_success_ack (int connection_fd)

No space before ( in function usage.

> +{
> +    uint8_t success = 1;

Magic number; I'd expect an enum or #defines somewhere.

> +    int nbytes = write(connection_fd, &success, 1);
> +    if (1 != nbytes){
> +        fprintf(stderr, "Qemu pmemaccess: failed to send success ack\n");

Is fprintf() really the best approach for error reporting?


> +static void
> +connection_handler (int connection_fd)
> +{
> +    int nbytes;
> +    struct request req;
> +
> +    while (1){
> +        // client request should match the struct request format

We prefer /* */ comments over //.

> +        nbytes = read(connection_fd, &req, sizeof(struct request));
> +        if (nbytes != sizeof(struct request)){
> +            // error
> +            continue;

Silently ignoring errors?

> +        }
> +        else if (req.type == 0){
> +            // request to quit, goodbye
> +            break;
> +        }
> +        else if (req.type == 1){
> +            // request to read
> +            char *buf = malloc(req.length + 1);

Mixing g_malloc/g_free with malloc/free makes it a bit harder to reason
about things; it might be better to use only glib allocation.

> +            nbytes = connection_read_memory(req.address, buf, req.length);
> +            if (nbytes != req.length){
> +                // read failure, return failure message
> +                buf[req.length] = 0; // set last byte to 0 for failure
> +                nbytes = write(connection_fd, buf, 1);
> +            }
> +            else{
> +                // read success, return bytes
> +                buf[req.length] = 1; // set last byte to 1 for success
> +                nbytes = write(connection_fd, buf, nbytes + 1);
> +            }
> +            free(buf);
> +        }
> +        else if (req.type == 2){
> +            // request to write
> +            void *write_buf = malloc(req.length);
> +            nbytes = read(connection_fd, &write_buf, req.length);

No error checking that the allocation succeeded? How do you protect from
bogus requests?

> +            if (nbytes != req.length){
> +                // failed reading the message to write
> +                send_fail_ack(connection_fd);
> +            }
> +            else{

} on the same line as else

> +                // do the write
> +                nbytes = connection_write_memory(req.address, write_buf, req.length);
> +                if (nbytes == req.length){
> +                    send_success_ack(connection_fd);
> +                }
> +                else{
> +                    send_fail_ack(connection_fd);
> +                }
> +            }
> +            free(write_buf);
> +        }
> +        else{
> +            // unknown command
> +            fprintf(stderr, "Qemu pmemaccess: ignoring unknown command (%d)\n", req.type);
> +            char *buf = malloc(1);
> +            buf[0] = 0;
> +            nbytes = write(connection_fd, buf, 1);
> +            free(buf);
> +        }
> +    }
> +
> +    close(connection_fd);
> +}
> +
> +static void *
> +memory_access_thread (void *p)

The most common style in qemu puts return type on the same line as the
function name.

> +{
> +    struct sockaddr_un address;
> +    int socket_fd, connection_fd;
> +    socklen_t address_length;
> +    struct pmemaccess_args *pargs = (struct pmemaccess_args *)p;

This cast is not necessary in C.

> +
> +    socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
> +    if (socket_fd < 0){
> +	error_setg(pargs->errp, "Qemu pmemaccess: socket failed");

TAB damage.  Also, mentioning 'Qemu' in an error message is probably
redundant.  That, and we prefer 'qemu' over 'Qemu'.

> +        goto error_exit;
> +    }
> +    unlink(pargs->path);

No check for errors?

> +    address.sun_family = AF_UNIX;
> +    address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", (char *) pargs->path);

Long line.  sprintf() is dangerous if you are not positive that
pargs->path fits.  Why do you need the cast?

> +
> +    if (bind(socket_fd, (struct sockaddr *) &address, address_length) != 0){
> +	error_setg(pargs->errp, "Qemu pmemaccess: bind failed");

More TAB damage.  Please read
http://wiki.qemu.org/Contribute/SubmitAPatch for more contribution
hints, and be sure to run ./scripts/checkpatch.pl.


> +void
> +qmp_pmemaccess (const char *path, Error **errp)
> +{
> +    pthread_t thread;
> +    sigset_t set, oldset;
> +    struct pmemaccess_args *pargs;
> +
> +    // create the args struct
> +    pargs = (struct pmemaccess_args *) malloc(sizeof(struct pmemaccess_args));
> +    pargs->errp = errp;
> +    // create a copy of path that we can safely use
> +    pargs->path = malloc(strlen(path) + 1);
> +    memcpy(pargs->path, path, strlen(path) + 1);

g_strdup() is your friend.


> +++ b/qapi-schema.json
> @@ -1427,6 +1427,34 @@
>    'data': {'val': 'int', 'size': 'int', 'filename': 'str'} }
>  
>  ##
> +# @pmemaccess:
> +#
> +# Open A UNIX Socket access to physical memory

s/A UNIX Socket/a Unix socket/

Same wording suggestion as earlier; might be better as:

Open a Unix socket used as a side-channel for efficiently accessing
physical memory.

> +#
> +# @path: the name of the UNIX socket pipe
> +#
> +# Returns: Nothing on success
> +#
> +# Since: 2.4.0.1

2.5, not 2.4.0.1.

> +#
> +# Notes: Derived from previously existing patches.

Dead sentence that doesn't add anything to the current specification.

> When command
> +# succeeds connect to the open socket. Write a binary structure to 
> +# the socket as:
> +# 
> +# struct request {
> +#     uint8_t type;   // 0 quit, 1 read, 2 write, ... rest reserved
> +#     uint64_t address;   // address to read from OR write to
> +#     uint64_t length;    // number of bytes to read OR write
> +# };
> +# 
> +# If it is a read operation, Qemu will return lenght+1 bytes. Read lenght+1

s/lenght/length/ twice

> +# bytes. the last byte will be a 1 for success, or a 0 for failure.
> +#  
> +##
> +{ 'command': 'pmemaccess',
> +  'data': {'path': 'str'} }
> +
> +##
>  # @cont:
>  #
>  # Resume guest VCPU execution.
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index d2ba800..26e4a51 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -472,6 +472,29 @@ Example:
>  EQMP
>  
>      {
> +        .name       = "pmemaccess",
> +        .args_type  = "path:s",
> +        .mhandler.cmd_new = qmp_marshal_input_pmemaccess,
> +    },
> +
> +SQMP
> +pmemaccess
> +----------
> +
> +Open A UNIX Socket access to physical memory
> +
> +Arguments:
> +
> +- "path": mount point path (json-string)
> +
> +Example:
> +
> +-> { "execute": "pmemaccess",
> +             "arguments": { "path": "/tmp/guestname" } }
> +<- { "return": {} }
> +
> +EQMP
> +    {
>          .name       = "inject-nmi",
>          .args_type  = "",
>          .mhandler.cmd_new = qmp_marshal_inject_nmi,
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

  reply	other threads:[~2015-10-19 21:33 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-15 23:44 [Qemu-devel] QEMU patch to allow VM introspection via libvmi valerio
2015-10-15 23:44 ` [Qemu-devel] [PATCH] QEMU patch for libvmi to introspect QEMU/kvm virtual machines. Usually this patch is distributed with libvmi, but, it might be more useful to have it in the QEMU source permanently valerio
2015-10-19 21:33   ` Eric Blake [this message]
2015-10-21 15:11     ` Valerio Aimale
2015-10-16  8:15 ` [Qemu-devel] QEMU patch to allow VM introspection via libvmi Markus Armbruster
2015-10-16 14:30   ` Valerio Aimale
2015-10-19  7:52     ` Markus Armbruster
2015-10-19 14:37       ` Valerio Aimale
2015-10-21 10:54         ` Markus Armbruster
2015-10-21 15:50           ` Valerio Aimale
2015-10-22 11:50             ` Markus Armbruster
2015-10-22 18:11               ` Valerio Aimale
2015-10-23  6:31                 ` Markus Armbruster
2015-10-22 18:43           ` Valerio Aimale
2015-10-22 18:54             ` Eric Blake
2015-10-22 19:12           ` Eduardo Habkost
2015-10-22 19:57             ` Valerio Aimale
2015-10-22 20:03               ` Eric Blake
2015-10-22 20:45                 ` Valerio Aimale
2015-10-22 21:47               ` Eduardo Habkost
2015-10-22 21:51                 ` Valerio Aimale
2015-10-23  8:25                   ` Daniel P. Berrange
2015-10-23 19:00                     ` Eduardo Habkost
2015-10-23 18:55                   ` Eduardo Habkost
2015-10-23 19:08                     ` Valerio Aimale
2015-10-26  9:09                       ` Markus Armbruster
2015-10-26 17:37                         ` Valerio Aimale
2015-10-26 17:52                           ` Eduardo Habkost
2015-10-27 14:17                             ` Valerio Aimale
2015-10-27 15:00                               ` Markus Armbruster
2015-10-27 15:18                                 ` Valerio Aimale
2015-10-27 15:31                                   ` Valerio Aimale
2015-10-27 16:11                                   ` Markus Armbruster
2015-10-27 16:27                                     ` Valerio Aimale
2015-10-23  6:35             ` Markus Armbruster
2015-10-23  8:18               ` Daniel P. Berrange
2015-10-23 14:48                 ` Valerio Aimale
2015-10-23 14:44               ` Valerio Aimale
2015-10-23 14:56                 ` Eric Blake
2015-10-23 15:03                   ` Valerio Aimale
2015-10-23 19:24               ` Eduardo Habkost
2015-10-23 20:02                 ` Richard Henderson
2015-11-02 12:55                 ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=562561B6.9010100@redhat.com \
    --to=eblake@redhat.com \
    --cc=armbru@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=valerio@aimale.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.