Re: [PATCH 4/6] ch: events: Read and parse cloud-hypervisor events

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

 



On Thu, Sep 26, 2024 at 11:16:37AM -0500, Praveen K Paladugu wrote:
> 
> 
> On 9/19/2024 8:02 AM, Purna Pavan Chandra Aekkaladevi wrote:
> > Implement `chReadProcessEvents` and `chProcessEvents` to read events from
> > event monitor FIFO file and parse them accordingly.
> > 
> > Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@xxxxxxxxxxxxxxxxxxx>
> > Co-authored-by: Vineeth Pillai <viremana@xxxxxxxxxxxxxxxxxxx>
> > ---
> >   src/ch/ch_events.c  | 142 +++++++++++++++++++++++++++++++++++++++++++-
> >   src/ch/ch_events.h  |   2 +
> >   src/ch/ch_monitor.h |   6 ++
> >   3 files changed, 149 insertions(+), 1 deletion(-)
> > 
> > diff --git a/src/ch/ch_events.c b/src/ch/ch_events.c
> > index 851fbc9f26..a028f9813e 100644
> > --- a/src/ch/ch_events.c
> > +++ b/src/ch/ch_events.c
> > @@ -28,6 +28,142 @@
> >   VIR_LOG_INIT("ch.ch_events");
> > 
> 
> Please add a comment here with a sample event here for reference.
> 

Sure, will do.

> > +static int virCHProcessEvents(virCHMonitor *mon)
> > +{
> > +    char *buf = mon->event_buffer.buffer;
> > +    ssize_t sz = mon->event_buffer.buf_fill_sz;
> > +    virJSONValue *obj = NULL;
> 
> > +    int blocks = 0;
> > +    size_t i = 0;
> > +    char *json_start;
> > +    ssize_t start_index = -1;
> > +    ssize_t end_index = -1;
> > +    char tmp;
> > +    int ret = 0;
> > +
> > +    while (i < sz) {
> > +        if (buf[i] == '{') {
> > +            blocks++;
> > +            if (blocks == 1)
> > +                start_index = i;
> > +        } else if (buf[i] == '}' && blocks > 0) {
> > +            blocks--;
> > +            if (blocks == 0) {
> > +                // valid json document
> > +                end_index = i;
> > +
> > +                /*
> > +                * We may hit a corner case where a valid JSON
> > +                * doc happens to end right at the end of the buffer.
> > +                * virJSONValueFromString needs '\0' end the JSON doc.
> > +                * So we need to adjust the buffer accordingly.
> > +                */
> > +                if (end_index == CH_EVENT_BUFFER_SZ - 1) {
> > +                    if (start_index == 0) {
> > +                        /*
> > +                        * We have a valid JSON doc same as the buffer
> > +                        * size. As per protocol, max JSON doc should be
> > +                        * less than the buffer size. So this is an error.
> > +                        * Ignore this JSON doc.
> > +                        */
> > +                        VIR_WARN("Invalid JSON doc size. Expected <= %d",
> > +                                 CH_EVENT_BUFFER_SZ);
> > +                        start_index = -1;
> > +                        ret = -1;
> > +                        break;
> > +                    }
> > +
> > +                    /*
> > +                    * Move the valid JSON doc to the start of the buffer so
> > +                    * that we can safely fit a '\0' at the end.
> > +                    */
> > +                    memmove(buf, buf+start_index, end_index-start_index+1);
> > +                    end_index -= start_index;
> > +                    start_index = 0;
> > +                }
> > +
> > +                // temporarily null terminate the JSON doc
> > +                tmp = buf[end_index + 1];
> > +                buf[end_index + 1] = '\0';
> > +                json_start = buf + start_index;
> > +
> > +                if ((obj = virJSONValueFromString(json_start))) {
> > +                    /* Process the event string (obj) here */
> > +                    virJSONValueFree(obj);
> > +                } else {
> > +                    VIR_WARN("Invalid JSON event doc: %s", json_start);
> > +                    ret = -1;
> > +                }
> > +
> > +                // replace the original character
> > +                buf[end_index + 1] = tmp;
> > +                start_index = -1;
> > +            }
> > +        }
> > +
> > +        i++;
> > +    }
> > +
> > +    if (start_index == -1) {
> > +        // We have processed all the JSON docs in the buffer.
> > +        mon->event_buffer.buf_fill_sz = 0;
> > +    } else if (start_index > 0) {
> > +        // We have an incomplete JSON doc at the end of the buffer.
> > +        // Move it to the start of the buffer.
> > +        mon->event_buffer.buf_fill_sz = sz - start_index;
> > +        memmove(buf, buf+start_index, mon->event_buffer.buf_fill_sz);
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> > +static void virCHReadProcessEvents(virCHMonitor *mon,
> > +                                   int event_monitor_fd)
> > +{
> > +    size_t max_sz = CH_EVENT_BUFFER_SZ;
> To avoid the corner case in virCHProcessEvents where the event ends
> at end of buffer, you can set
> max_sz = CH_EVENT_BUFFER_SZ -1;
> 
> This ensures there is always space for a Null char at the end.

This would be same as what current logic is doing i.e., supporting
events of length less than CH_EVENT_BUFFER_SZ.
Currently, when event length is CH_EVENT_BUFFER_SZ, we warn saying
expected length is <CH_EVENT_BUFFER_SZ. Otherwise, we already have
enough space to additionally terminate with null char.

> > +    char *buf = mon->event_buffer.buffer;
> > +    virDomainObj *vm = mon->vm;
> > +    bool incomplete = false;
> > +    size_t sz = 0;
> > +
> > +    memset(buf, 0, max_sz);
> > +    do {
> > +        ssize_t ret;
> > +
> > +        ret = read(event_monitor_fd, buf + sz, max_sz - sz);
> > +        if (ret == 0 || (ret < 0 && errno == EINTR)) {
> > +            g_usleep(G_USEC_PER_SEC);
> > +            continue;
> > +        } else if (ret < 0) {
> > +            /*
> > +             * We should never reach here. read(2) says possible errors
> > +             * are EINTR, EAGAIN, EBADF, EFAULT, EINVAL, EIO, EISDIR
> > +             * We handle EINTR gracefully. There is some serious issue
> > +             * if we encounter any of the other errors(either in our code
> > +             * or in the system). Better to bail out.
> > +             */
> > +            VIR_ERROR(_("Failed to read ch events!: %1$s"), g_strerror(errno));
> > +            VIR_FORCE_CLOSE(event_monitor_fd);
> > +            abort();
> > +        }
> > +
> > +        sz += ret;
> > +        mon->event_buffer.buf_fill_sz = sz;
> > +
> > +        if (virCHProcessEvents(mon) < 0)
> > +            VIR_WARN("Failed to parse and process events");
> > +
> > +        if (mon->event_buffer.buf_fill_sz != 0)
> > +            incomplete = true;
> > +        else
> > +            incomplete = false;
> > +        sz = mon->event_buffer.buf_fill_sz;
> > +
> > +    } while (virDomainObjIsActive(vm) && (sz < max_sz) && incomplete);
> > +
> > +    return;
> > +}
> > +
> >   static void virCHEventHandlerLoop(void *data)
> >   {
> >       virCHMonitor *mon = data;
> > @@ -51,6 +187,9 @@ static void virCHEventHandlerLoop(void *data)
> >       }
> >       VIR_DEBUG("Opened the event monitor FIFO(%s)", mon->eventmonitorpath);
> > +    mon->event_buffer.buffer = g_malloc_n(sizeof(char), CH_EVENT_BUFFER_SZ);
> > +    mon->event_buffer.buf_fill_sz = 0;
> > +
> >       /*
> >        * We would need to wait until VM is initialized.
> >        */
> > @@ -59,9 +198,10 @@ static void virCHEventHandlerLoop(void *data)
> >       while (g_atomic_int_get(&mon->event_handler_stop) == 0) {
> >           VIR_DEBUG("Reading events from event monitor file...");
> > -        /* Read and process events here */
> > +        virCHReadProcessEvents(mon, event_monitor_fd);
> >       }
> > +    g_free(mon->event_buffer.buffer);
> >       VIR_FORCE_CLOSE(event_monitor_fd);
> >       virObjectUnref(vm);
> > diff --git a/src/ch/ch_events.h b/src/ch/ch_events.h
> > index 4c8a48231d..2e9cdf03bb 100644
> > --- a/src/ch/ch_events.h
> > +++ b/src/ch/ch_events.h
> > @@ -22,5 +22,7 @@
> >   #include "ch_monitor.h"
> > +#define CH_EVENT_BUFFER_SZ  PIPE_BUF
> > +
> >   int virCHStartEventHandler(virCHMonitor *mon);
> >   void virCHStopEventHandler(virCHMonitor *mon);
> > diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h
> > index 878a185f29..6b4045d300 100644
> > --- a/src/ch/ch_monitor.h
> > +++ b/src/ch/ch_monitor.h
> > @@ -99,6 +99,12 @@ struct _virCHMonitor {
> >       virThread event_handler_thread;
> >       int event_handler_stop;
> > +    struct {
> > +        // Buffer to hold the data read from pipe
> 
> Please replace all `//`  comments with `/**/`. This is the preferred
> comment style in Libvirt.
> 

Will take care of it in V2.

> > +        char *buffer;
> > +        // Size of the data read from pipe in buffer
> nit: "Size of the data read from pipe into buffer"

Sure

> > +        size_t buf_fill_sz;
> > +    } event_buffer;
> >       pid_t pid;
> 
> -- 
> Regards,
> Praveen K Paladugu

Regards,
Purna Pavan Chandra



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux