[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v6 05/11] hw/usb: switch MTP to use new inotify
From: |
Marc-André Lureau |
Subject: |
Re: [Qemu-devel] [PATCH v6 05/11] hw/usb: switch MTP to use new inotify APIs |
Date: |
Wed, 7 Nov 2018 22:26:29 +0400 |
On Fri, Oct 19, 2018 at 5:42 PM Daniel P. Berrangé <address@hidden> wrote:
>
> The internal inotify APIs allow alot of conditional statements to be
a lot
> cleared out, and provide a simpler callback for handling events.
>
> Signed-off-by: Daniel P. Berrangé <address@hidden>
> ---
> hw/usb/dev-mtp.c | 250 ++++++++++++++++----------------------------
> hw/usb/trace-events | 2 +-
> 2 files changed, 93 insertions(+), 159 deletions(-)
>
> diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
> index ccbe25820b..1a8d0f088d 100644
> --- a/hw/usb/dev-mtp.c
> +++ b/hw/usb/dev-mtp.c
> @@ -15,13 +15,11 @@
> #include <dirent.h>
>
> #include <sys/statvfs.h>
> -#ifdef CONFIG_INOTIFY1
> -#include <sys/inotify.h>
> -#include "qemu/main-loop.h"
> -#endif
> +
>
> #include "qemu-common.h"
> #include "qemu/iov.h"
> +#include "qemu/filemonitor.h"
> #include "trace.h"
> #include "hw/usb.h"
> #include "desc.h"
> @@ -124,7 +122,6 @@ enum {
> EP_EVENT,
> };
>
> -#ifdef CONFIG_INOTIFY1
> typedef struct MTPMonEntry MTPMonEntry;
>
> struct MTPMonEntry {
> @@ -133,7 +130,6 @@ struct MTPMonEntry {
>
> QTAILQ_ENTRY(MTPMonEntry) next;
> };
> -#endif
>
> struct MTPControl {
> uint16_t code;
> @@ -162,10 +158,8 @@ struct MTPObject {
> char *name;
> char *path;
> struct stat stat;
> -#ifdef CONFIG_INOTIFY1
> - /* inotify watch cookie */
> + /* file monitor watch cookie */
> int watchfd;
Why not rename it watchid to avoid confusion?
> -#endif
> MTPObject *parent;
> uint32_t nchildren;
> QLIST_HEAD(, MTPObject) children;
> @@ -188,11 +182,8 @@ struct MTPState {
> bool readonly;
>
> QTAILQ_HEAD(, MTPObject) objects;
> -#ifdef CONFIG_INOTIFY1
> - /* inotify descriptor */
> - int inotifyfd;
> + QFileMonitor *file_monitor;
> QTAILQ_HEAD(events, MTPMonEntry) events;
> -#endif
> /* Responder is expecting a write operation */
> bool write_pending;
> struct {
> @@ -477,6 +468,10 @@ static MTPObject *usb_mtp_object_lookup_name(MTPObject
> *parent,
> {
> MTPObject *iter;
>
> + if (len == -1) {
> + len = strlen(name);
> + }
> +
> QLIST_FOREACH(iter, &parent->children, list) {
> if (strncmp(iter->name, name, len) == 0) {
> return iter;
> @@ -486,7 +481,6 @@ static MTPObject *usb_mtp_object_lookup_name(MTPObject
> *parent,
> return NULL;
> }
>
> -#ifdef CONFIG_INOTIFY1
> static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
> {
> MTPObject *iter;
> @@ -500,158 +494,98 @@ static MTPObject *usb_mtp_object_lookup_wd(MTPState
> *s, int wd)
> return NULL;
> }
>
> -static void inotify_watchfn(void *arg)
> +static void file_monitor_event(int wd,
> + QFileMonitorEvent ev,
> + const char *name,
> + void *opaque)
> {
> - MTPState *s = arg;
> - ssize_t bytes;
> - /* From the man page: atleast one event can be read */
> - int pos;
> - char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
> -
> - for (;;) {
> - bytes = read(s->inotifyfd, buf, sizeof(buf));
> - pos = 0;
> -
> - if (bytes <= 0) {
> - /* Better luck next time */
> + MTPState *s = opaque;
> + int watchfd = 0;
> + MTPObject *parent = usb_mtp_object_lookup_wd(s, wd);
> + MTPMonEntry *entry = NULL;
> + MTPObject *o;
> +
> + if (!parent) {
> + return;
> + }
> +
> + switch (ev) {
> + case QFILE_MONITOR_EVENT_CREATED:
> + if (usb_mtp_object_lookup_name(parent, name, -1)) {
> + /* Duplicate create event */
> return;
> }
> + entry = g_new0(MTPMonEntry, 1);
> + entry->handle = s->next_handle;
> + entry->event = EVT_OBJ_ADDED;
> + o = usb_mtp_add_child(s, parent, name);
> + if (!o) {
> + g_free(entry);
> + return;
> + }
> + o->watchfd = watchfd;
this effectively always set o->watchfd to 0, which is already
initialized to 0 with g_new0(), you can drop it
> + trace_usb_mtp_file_monitor_event(s->dev.addr, name, "Obj Added");
> + break;
>
> + case QFILE_MONITOR_EVENT_DELETED:
> /*
> - * TODO: Ignore initiator initiated events.
> - * For now we are good because the store is RO
> + * The kernel issues a IN_IGNORED event
> + * when a dir containing a watchpoint is
> + * deleted, so we don't have to delete the
> + * watchpoint
> */
> - while (bytes > 0) {
> - char *p = buf + pos;
> - struct inotify_event *event = (struct inotify_event *)p;
> - int watchfd = 0;
> - uint32_t mask = event->mask & (IN_CREATE | IN_DELETE |
> - IN_MODIFY | IN_IGNORED);
> - MTPObject *parent = usb_mtp_object_lookup_wd(s, event->wd);
> - MTPMonEntry *entry = NULL;
> - MTPObject *o;
> -
> - pos = pos + sizeof(struct inotify_event) + event->len;
> - bytes = bytes - pos;
> -
> - if (!parent) {
> - continue;
> - }
> -
> - switch (mask) {
> - case IN_CREATE:
> - if (usb_mtp_object_lookup_name
> - (parent, event->name, event->len)) {
> - /* Duplicate create event */
> - continue;
> - }
> - entry = g_new0(MTPMonEntry, 1);
> - entry->handle = s->next_handle;
> - entry->event = EVT_OBJ_ADDED;
> - o = usb_mtp_add_child(s, parent, event->name);
> - if (!o) {
> - g_free(entry);
> - continue;
> - }
> - o->watchfd = watchfd;
> - trace_usb_mtp_inotify_event(s->dev.addr, event->name,
> - event->mask, "Obj Added");
> - break;
> -
> - case IN_DELETE:
> - /*
> - * The kernel issues a IN_IGNORED event
> - * when a dir containing a watchpoint is
> - * deleted, so we don't have to delete the
> - * watchpoint
> - */
> - o = usb_mtp_object_lookup_name(parent, event->name,
> event->len);
> - if (!o) {
> - continue;
> - }
> - entry = g_new0(MTPMonEntry, 1);
> - entry->handle = o->handle;
> - entry->event = EVT_OBJ_REMOVED;
> - trace_usb_mtp_inotify_event(s->dev.addr, o->path,
> - event->mask, "Obj Deleted");
> - usb_mtp_object_free(s, o);
> - break;
> -
> - case IN_MODIFY:
> - o = usb_mtp_object_lookup_name(parent, event->name,
> event->len);
> - if (!o) {
> - continue;
> - }
> - entry = g_new0(MTPMonEntry, 1);
> - entry->handle = o->handle;
> - entry->event = EVT_OBJ_INFO_CHANGED;
> - trace_usb_mtp_inotify_event(s->dev.addr, o->path,
> - event->mask, "Obj Modified");
> - break;
> -
> - case IN_IGNORED:
> - trace_usb_mtp_inotify_event(s->dev.addr, parent->path,
> - event->mask, "Obj parent dir ignored");
> - break;
> -
> - default:
> - fprintf(stderr, "usb-mtp: failed to parse inotify event\n");
> - continue;
> - }
> + o = usb_mtp_object_lookup_name(parent, name, -1);
> + if (!o) {
> + return;
> + }
> + entry = g_new0(MTPMonEntry, 1);
> + entry->handle = o->handle;
> + entry->event = EVT_OBJ_REMOVED;
> + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj
> Deleted");
> + usb_mtp_object_free(s, o);
> + break;
>
> - if (entry) {
> - QTAILQ_INSERT_HEAD(&s->events, entry, next);
> - }
> + case QFILE_MONITOR_EVENT_MODIFIED:
> + o = usb_mtp_object_lookup_name(parent, name, -1);
> + if (!o) {
> + return;
> }
> - }
> -}
> + entry = g_new0(MTPMonEntry, 1);
> + entry->handle = o->handle;
> + entry->event = EVT_OBJ_INFO_CHANGED;
> + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj
> Modified");
> + break;
>
> -static int usb_mtp_inotify_init(MTPState *s)
> -{
> - int fd;
> + case QFILE_MONITOR_EVENT_IGNORED:
> + trace_usb_mtp_file_monitor_event(s->dev.addr, parent->path,
> + "Obj parent dir ignored");
> + break;
>
> - fd = inotify_init1(IN_NONBLOCK);
> - if (fd == -1) {
> - return 1;
> + default:
> + g_assert_not_reached();
> }
>
> - QTAILQ_INIT(&s->events);
> - s->inotifyfd = fd;
> -
> - qemu_set_fd_handler(fd, inotify_watchfn, NULL, s);
> -
> - return 0;
> + if (entry) {
> + QTAILQ_INSERT_HEAD(&s->events, entry, next);
> + }
> }
>
> -static void usb_mtp_inotify_cleanup(MTPState *s)
> +static void usb_mtp_file_monitor_cleanup(MTPState *s)
> {
> MTPMonEntry *e, *p;
>
> - if (!s->inotifyfd) {
> - return;
> - }
> -
> - qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s);
> - close(s->inotifyfd);
> -
> QTAILQ_FOREACH_SAFE(e, &s->events, next, p) {
> QTAILQ_REMOVE(&s->events, e, next);
> g_free(e);
> }
> }
>
> -static int usb_mtp_add_watch(int inotifyfd, const char *path)
> -{
> - uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY;
> -
> - return inotify_add_watch(inotifyfd, path, mask);
> -}
> -#endif
>
> static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
> {
> struct dirent *entry;
> DIR *dir;
> + Error *err = NULL;
>
> if (o->have_children) {
> return;
> @@ -662,16 +596,19 @@ static void usb_mtp_object_readdir(MTPState *s,
> MTPObject *o)
> if (!dir) {
> return;
> }
> -#ifdef CONFIG_INOTIFY1
> - int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
> +
> + int watchfd = qemu_file_monitor_add_watch(s->file_monitor, o->path, NULL,
> + file_monitor_event, s, &err);
There is an add_watch(), but I don't see the corresponding
remove_watch(). This may probably cause crashes if MTPState is freed.
> if (watchfd == -1) {
> - fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path);
> + fprintf(stderr, "usb-mtp: failed to add watch for %s: %s\n", o->path,
> + error_get_pretty(err));
maybe it's a good time to turn into error_report() ?
> + error_free(err);
> } else {
> - trace_usb_mtp_inotify_event(s->dev.addr, o->path,
> - 0, "Watch Added");
> + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path,
> + "Watch Added");
> o->watchfd = watchfd;
> }
> -#endif
> +
> while ((entry = readdir(dir)) != NULL) {
> usb_mtp_add_child(s, o, entry->d_name);
> }
> @@ -1179,13 +1116,11 @@ enum {
> /* Assumes that children, if any, have been already freed */
> static void usb_mtp_object_free_one(MTPState *s, MTPObject *o)
> {
> -#ifndef CONFIG_INOTIFY1
> assert(o->nchildren == 0);
> QTAILQ_REMOVE(&s->objects, o, next);
> g_free(o->name);
> g_free(o->path);
> g_free(o);
> -#endif
> }
>
> static int usb_mtp_deletefn(MTPState *s, MTPObject *o, uint32_t trans)
> @@ -1284,6 +1219,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
> MTPData *data_in = NULL;
> MTPObject *o = NULL;
> uint32_t nres = 0, res0 = 0;
> + Error *err = NULL;
>
> /* sanity checks */
> if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
> @@ -1311,19 +1247,21 @@ static void usb_mtp_command(MTPState *s, MTPControl
> *c)
> trace_usb_mtp_op_open_session(s->dev.addr);
> s->session = c->argv[0];
> usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
> -#ifdef CONFIG_INOTIFY1
> - if (usb_mtp_inotify_init(s)) {
> - fprintf(stderr, "usb-mtp: file monitoring init failed\n");
> +
> + s->file_monitor = qemu_file_monitor_get_instance(&err);
> + if (err) {
> + fprintf(stderr, "usb-mtp: file monitoring init failed: %s\n",
> + error_get_pretty(err));
> + error_free(err);
> + } else {
> + QTAILQ_INIT(&s->events);
> }
> -#endif
> break;
> case CMD_CLOSE_SESSION:
> trace_usb_mtp_op_close_session(s->dev.addr);
> s->session = 0;
> s->next_handle = 0;
> -#ifdef CONFIG_INOTIFY1
> - usb_mtp_inotify_cleanup(s);
> -#endif
> + usb_mtp_file_monitor_cleanup(s);
> usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
> assert(QTAILQ_EMPTY(&s->objects));
> break;
> @@ -1536,9 +1474,7 @@ static void usb_mtp_handle_reset(USBDevice *dev)
>
> trace_usb_mtp_reset(s->dev.addr);
>
> -#ifdef CONFIG_INOTIFY1
> - usb_mtp_inotify_cleanup(s);
> -#endif
> + usb_mtp_file_monitor_cleanup(s);
> usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
> s->session = 0;
> usb_mtp_data_free(s->data_in);
> @@ -1967,7 +1903,6 @@ static void usb_mtp_handle_data(USBDevice *dev,
> USBPacket *p)
> }
> break;
> case EP_EVENT:
> -#ifdef CONFIG_INOTIFY1
> if (!QTAILQ_EMPTY(&s->events)) {
> struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
> uint32_t handle;
> @@ -1991,7 +1926,6 @@ static void usb_mtp_handle_data(USBDevice *dev,
> USBPacket *p)
> g_free(e);
> return;
> }
> -#endif
> p->status = USB_RET_NAK;
> return;
> default:
> diff --git a/hw/usb/trace-events b/hw/usb/trace-events
> index 2c18770ca5..99b1e8b8ce 100644
> --- a/hw/usb/trace-events
> +++ b/hw/usb/trace-events
> @@ -237,7 +237,7 @@ usb_mtp_op_unknown(int dev, uint32_t code) "dev %d,
> command code 0x%x"
> usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d,
> handle 0x%x, path %s"
> usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d,
> handle 0x%x, path %s"
> usb_mtp_add_child(int dev, uint32_t handle, const char *path) "dev %d,
> handle 0x%x, path %s"
> -usb_mtp_inotify_event(int dev, const char *path, uint32_t mask, const char
> *s) "dev %d, path %s mask 0x%x event %s"
> +usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev
> %d, path %s event %s"
>
> # hw/usb/host-libusb.c
> usb_host_open_started(int bus, int addr) "dev %d:%d"
> --
> 2.17.2
>
>
--
Marc-André Lureau
- Re: [Qemu-devel] [PATCH v6 05/11] hw/usb: switch MTP to use new inotify APIs,
Marc-André Lureau <=