* [Qemu-devel] [PATCH v2 0/4] usb-mtp events support
@ 2015-11-10 22:58 Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 1/4] usb-mtp: use a list for keeping track of children Bandan Das
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Bandan Das @ 2015-11-10 22:58 UTC (permalink / raw)
To: qemu-devel; +Cc: kraxel
This series adds support for mtp events that are piggybacked on
top of the Linux provided inotify mechanism. It performs well with some
light unit testing in a linux guest. The mtp share is still read only,
but now the guest will notice updates to the share as long as the
mtp client being used supports it.
v2:
1/4: Split up the check in usb_mtp_handle_reset into a new patch
Rerrange the check for a null "o"
2/4:
New patch that handles freeing of objects during a reset
3/4:
Reword comment for DELETE event
Reword comment for CREATE event for directories
Rearrange the inotifyfd reading loop for readability
Check for duplicates when creating a new object
Remove unnecessary enum and replace with mtp event codes
Add ifdefs and empty stubs for non linux systems. Ugly but I really
wanted to minimize ifdef clutter. The other option is to compile
mtp support for linux only but that seems a bit restrictive.
Change behavior for "failed events" Instead of bailing out immediately,
check if there's still some left that we can process.
4/4: No change
Bandan Das (4):
usb-mtp: use a list for keeping track of children
usb-mtp: free objects on a mtp reset
usb-mtp: Add support for inotify based file monitoring
usb-mtp: add support for basic mtp events
hw/usb/dev-mtp.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
trace-events | 4 +
2 files changed, 351 insertions(+), 18 deletions(-)
--
2.5.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 1/4] usb-mtp: use a list for keeping track of children
2015-11-10 22:58 [Qemu-devel] [PATCH v2 0/4] usb-mtp events support Bandan Das
@ 2015-11-10 22:58 ` Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 2/4] usb-mtp: free objects on a mtp reset Bandan Das
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Bandan Das @ 2015-11-10 22:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Bandan Das, kraxel
To support adding/removal of objects, we will need to update
the object cache hierarchy we have built internally. Convert
to using a Qlist for easier management.
Signed-off-by: Bandan Das <bsd@redhat.com>
---
hw/usb/dev-mtp.c | 55 +++++++++++++++++++++++++++++++++++++++----------------
trace-events | 1 +
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index a276267..eea2dad 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -109,8 +109,9 @@ struct MTPObject {
char *path;
struct stat stat;
MTPObject *parent;
- MTPObject **children;
uint32_t nchildren;
+ QLIST_HEAD(, MTPObject) children;
+ QLIST_ENTRY(MTPObject) list;
bool have_children;
QTAILQ_ENTRY(MTPObject) next;
};
@@ -317,15 +318,23 @@ ignore:
static void usb_mtp_object_free(MTPState *s, MTPObject *o)
{
- int i;
+ MTPObject *iter;
+
+ if (!o) {
+ return;
+ }
trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
QTAILQ_REMOVE(&s->objects, o, next);
- for (i = 0; i < o->nchildren; i++) {
- usb_mtp_object_free(s, o->children[i]);
+ if (o->parent) {
+ QLIST_REMOVE(o, list);
+ o->parent->nchildren--;
+ }
+
+ QLIST_FOREACH(iter, &o->children, list) {
+ usb_mtp_object_free(s, iter);
}
- g_free(o->children);
g_free(o->name);
g_free(o->path);
g_free(o);
@@ -343,6 +352,25 @@ static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
return NULL;
}
+static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
+ char *name)
+{
+ MTPObject *child =
+ usb_mtp_object_alloc(s, s->next_handle++, o, name);
+
+ if (child) {
+ trace_usb_mtp_add_child(s->dev.addr, child->handle, child->path);
+ QLIST_INSERT_HEAD(&o->children, child, list);
+ o->nchildren++;
+
+ if (child->format == FMT_ASSOCIATION) {
+ QLIST_INIT(&child->children);
+ }
+ }
+
+ return child;
+}
+
static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
{
struct dirent *entry;
@@ -358,14 +386,7 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
return;
}
while ((entry = readdir(dir)) != NULL) {
- if ((o->nchildren % 32) == 0) {
- o->children = g_renew(MTPObject *, o->children, o->nchildren + 32);
- }
- o->children[o->nchildren] =
- usb_mtp_object_alloc(s, s->next_handle++, o, entry->d_name);
- if (o->children[o->nchildren] != NULL) {
- o->nchildren++;
- }
+ usb_mtp_add_child(s, o, entry->d_name);
}
closedir(dir);
}
@@ -617,13 +638,15 @@ static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
MTPObject *o)
{
MTPData *d = usb_mtp_data_alloc(c);
- uint32_t i, handles[o->nchildren];
+ uint32_t i = 0, handles[o->nchildren];
+ MTPObject *iter;
trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
- for (i = 0; i < o->nchildren; i++) {
- handles[i] = o->children[i]->handle;
+ QLIST_FOREACH(iter, &o->children, list) {
+ handles[i++] = iter->handle;
}
+ assert(i == o->nchildren);
usb_mtp_add_u32_array(d, o->nchildren, handles);
return d;
diff --git a/trace-events b/trace-events
index ea2d32e..6a11f62 100644
--- a/trace-events
+++ b/trace-events
@@ -552,6 +552,7 @@ usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32
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"
# hw/usb/host-libusb.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
--
2.5.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 2/4] usb-mtp: free objects on a mtp reset
2015-11-10 22:58 [Qemu-devel] [PATCH v2 0/4] usb-mtp events support Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 1/4] usb-mtp: use a list for keeping track of children Bandan Das
@ 2015-11-10 22:58 ` Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 4/4] usb-mtp: add support for basic mtp events Bandan Das
3 siblings, 0 replies; 7+ messages in thread
From: Bandan Das @ 2015-11-10 22:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Bandan Das, kraxel
On a reset, call usb_mtp_object_free on all objects and their children
Signed-off-by: Bandan Das <bsd@redhat.com>
---
hw/usb/dev-mtp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index eea2dad..c39b81a 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -907,6 +907,7 @@ static void usb_mtp_handle_reset(USBDevice *dev)
trace_usb_mtp_reset(s->dev.addr);
+ usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
s->session = 0;
usb_mtp_data_free(s->data_in);
s->data_in = NULL;
--
2.5.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring
2015-11-10 22:58 [Qemu-devel] [PATCH v2 0/4] usb-mtp events support Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 1/4] usb-mtp: use a list for keeping track of children Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 2/4] usb-mtp: free objects on a mtp reset Bandan Das
@ 2015-11-10 22:58 ` Bandan Das
2015-11-13 12:34 ` Gerd Hoffmann
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 4/4] usb-mtp: add support for basic mtp events Bandan Das
3 siblings, 1 reply; 7+ messages in thread
From: Bandan Das @ 2015-11-10 22:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Bandan Das, kraxel
For now, we use inotify watches to track only a small number of
events, namely, add, delete and modify. Note that for delete, the kernel
already deactivates the watch for us and we just need to
take care of modifying our internal state.
inotify is a linux only mechanism. Provide empty stubs and
error out initialization for non linux systems.
Suggested-by: Gerd Hoffman <kraxel@redhat.com>
Signed-off-by: Bandan Das <bsd@redhat.com>
---
hw/usb/dev-mtp.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
trace-events | 3 +
2 files changed, 287 insertions(+), 2 deletions(-)
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index c39b81a..3c39a64 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -15,15 +15,50 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
+#ifdef __linux__
+#include <sys/inotify.h>
+#endif
#include "qemu-common.h"
#include "qemu/iov.h"
+#include "qemu/main-loop.h"
#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
/* ----------------------------------------------------------------------- */
+/* Empty inotify function stubs for non linux systems */
+#ifndef __linux__
+enum inotify_events {
+ IN_MODIFY = 0x00000002,
+ IN_CREATE = 0x00000100,
+ IN_DELETE = 0x00000200,
+ IN_ISDIR = 0x40000000,
+ IN_NONBLOCK = O_NONBLOCK,
+ IN_IGNORED = 0x00008000,
+};
+
+/* Structure describing an inotify event. */
+struct inotify_event {
+ int wd; /* Watch descriptor. */
+ uint32_t mask; /* Watch mask. */
+ uint32_t cookie; /* Cookie to synchronize two events. */
+ uint32_t len; /* Length (including NULs) of name. */
+ char name __flexarr; /* Name. */
+};
+
+static int inotify_init1(int fd)
+{
+ return 0;
+}
+
+static int inotify_add_watch(int fd, char *path, uint32_t mask)
+{
+ return 0;
+}
+#endif
+
enum mtp_container_type {
TYPE_COMMAND = 1,
TYPE_DATA = 2,
@@ -62,6 +97,11 @@ enum mtp_code {
/* format codes */
FMT_UNDEFINED_OBJECT = 0x3000,
FMT_ASSOCIATION = 0x3001,
+
+ /* event codes */
+ EVT_OBJ_ADDED = 0x4002,
+ EVT_OBJ_REMOVED = 0x4003,
+ EVT_OBJ_INFO_CHANGED = 0x4007,
};
typedef struct {
@@ -77,6 +117,7 @@ typedef struct MTPState MTPState;
typedef struct MTPControl MTPControl;
typedef struct MTPData MTPData;
typedef struct MTPObject MTPObject;
+typedef struct MTPMonEntry MTPMonEntry;
enum {
EP_DATA_IN = 1,
@@ -84,6 +125,13 @@ enum {
EP_EVENT,
};
+struct MTPMonEntry {
+ uint32_t event;
+ uint32_t handle;
+
+ QTAILQ_ENTRY(MTPMonEntry) next;
+};
+
struct MTPControl {
uint16_t code;
uint32_t trans;
@@ -108,6 +156,8 @@ struct MTPObject {
char *name;
char *path;
struct stat stat;
+ /* inotify watch cookie */
+ int watchfd;
MTPObject *parent;
uint32_t nchildren;
QLIST_HEAD(, MTPObject) children;
@@ -121,6 +171,8 @@ struct MTPState {
char *root;
char *desc;
uint32_t flags;
+ /* inotify descriptor */
+ int inotifyfd;
MTPData *data_in;
MTPData *data_out;
@@ -129,6 +181,7 @@ struct MTPState {
uint32_t next_handle;
QTAILQ_HEAD(, MTPObject) objects;
+ QTAILQ_HEAD(events, MTPMonEntry) events;
};
#define TYPE_USB_MTP "usb-mtp"
@@ -270,6 +323,40 @@ static const USBDesc desc = {
};
/* ----------------------------------------------------------------------- */
+static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
+ char *name, int len)
+{
+ MTPObject *iter;
+
+ QLIST_FOREACH(iter, &parent->children, list) {
+ if (strncmp(iter->name, name, len) == 0) {
+ return iter;
+ }
+ }
+
+ return NULL;
+}
+
+static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
+{
+ MTPObject *iter;
+
+ QTAILQ_FOREACH(iter, &s->objects, next) {
+ if (iter->watchfd == wd) {
+ return iter;
+ }
+ }
+
+ return NULL;
+}
+
+static int usb_mtp_add_watch(int inotifyfd, char *path)
+{
+ uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY |
+ IN_ISDIR;
+
+ return inotify_add_watch(inotifyfd, path, mask);
+}
static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
MTPObject *parent, char *name)
@@ -316,6 +403,46 @@ ignore:
return NULL;
}
+static void usb_mtp_inotify_cleanup(MTPState *s)
+{
+ MTPMonEntry *e;
+
+ if (!s->inotifyfd) {
+ return;
+ }
+
+ qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s);
+ close(s->inotifyfd);
+
+ QTAILQ_FOREACH(e, &s->events, next) {
+ QTAILQ_REMOVE(&s->events, e, next);
+ g_free(e);
+ }
+}
+
+static int usb_mtp_inotify_mon(MTPState *s, MTPObject *o)
+{
+ int watchfd;
+
+ if (!s->inotifyfd) {
+ return 0;
+ }
+ assert(o->format == FMT_ASSOCIATION);
+ if (o->watchfd > 0) {
+ /* already watching */
+ return 0;
+ }
+
+ watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
+ if (watchfd == -1) {
+ return 1;
+ }
+
+ o->watchfd = watchfd;
+ trace_usb_mtp_mon(s->dev.addr, o->path, watchfd);
+
+ return 0;
+}
static void usb_mtp_object_free(MTPState *s, MTPObject *o)
{
MTPObject *iter;
@@ -371,6 +498,153 @@ static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
return child;
}
+static void inotify_watchfn(void *arg)
+{
+ MTPState *s = arg;
+ ssize_t bytes;
+ /* From the man page: atleast one event can be read */
+ int len = sizeof(struct inotify_event) + NAME_MAX + 1;
+ int pos;
+ char buf[len];
+
+ for (;;) {
+ bytes = read(s->inotifyfd, buf, len);
+ pos = 0;
+
+ if (bytes <= 0) {
+ /* Better luck next time */
+ return;
+ }
+
+ /*
+ * TODO: Ignore initiator initiated events.
+ * For now we are good because the store is RO
+ */
+ 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;
+ char *name, *path;
+
+ pos = pos + sizeof(struct inotify_event) + event->len;
+ bytes = bytes - pos;
+
+ if (!parent) {
+ continue;
+ }
+
+ switch (mask) {
+ case IN_CREATE:
+ if (event->mask & IN_ISDIR) {
+ /*
+ * Add the watchpoint first so we
+ * don't miss events in this subdir
+ */
+ name = g_strndup(event->name, event->len);
+ path = g_strdup_printf("%s/%s", parent->path, name);
+
+ watchfd = usb_mtp_add_watch(s->inotifyfd, path);
+ g_free(path);
+ g_free(name);
+
+ if (watchfd == -1) {
+ continue;
+ }
+ }
+
+ 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, path,
+ 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;
+ usb_mtp_object_free(s, o);
+ trace_usb_mtp_inotify_event(s->dev.addr, o->path,
+ event->mask, "Obj Deleted");
+ 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:
+ o = usb_mtp_object_lookup_name(parent, event->name, event->len);
+ trace_usb_mtp_inotify_event(s->dev.addr, o->path,
+ event->mask, "Obj ignored");
+ break;
+
+ default:
+ fprintf(stderr, "usb-mtp: failed to parse inotify event\n");
+ continue;
+ }
+
+ if (entry) {
+ QTAILQ_INSERT_HEAD(&s->events, entry, next);
+ }
+ }
+ }
+}
+
+static int usb_mtp_inotify_init(MTPState *s)
+{
+ int fd;
+
+#ifndef __linux__
+ return 1;
+#endif
+
+ fd = inotify_init1(IN_NONBLOCK);
+ if (fd == -1) {
+ return 1;
+ }
+
+ QTAILQ_INIT(&s->events);
+ s->inotifyfd = fd;
+
+ qemu_set_fd_handler(fd, inotify_watchfn, NULL, s);
+
+ return 0;
+}
+
static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
{
struct dirent *entry;
@@ -639,11 +913,11 @@ static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
{
MTPData *d = usb_mtp_data_alloc(c);
uint32_t i = 0, handles[o->nchildren];
- MTPObject *iter;
+ MTPObject *iter, *next;
trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
- QLIST_FOREACH(iter, &o->children, list) {
+ QLIST_FOREACH_SAFE(iter, &o->children, list, next) {
handles[i++] = iter->handle;
}
assert(i == o->nchildren);
@@ -777,11 +1051,15 @@ 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);
+ if (usb_mtp_inotify_init(s)) {
+ fprintf(stderr, "usb-mtp: file monitoring init failed\n");
+ }
break;
case CMD_CLOSE_SESSION:
trace_usb_mtp_op_close_session(s->dev.addr);
s->session = 0;
s->next_handle = 0;
+ usb_mtp_inotify_cleanup(s);
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
assert(QTAILQ_EMPTY(&s->objects));
break;
@@ -827,6 +1105,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
return;
}
usb_mtp_object_readdir(s, o);
+ if (usb_mtp_inotify_mon(s, o)) {
+ fprintf(stderr, "usb-mtp: adding watch for %s failed\n", o->path);
+ }
if (c->code == CMD_GET_NUM_OBJECTS) {
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
nres = 1;
@@ -907,6 +1188,7 @@ static void usb_mtp_handle_reset(USBDevice *dev)
trace_usb_mtp_reset(s->dev.addr);
+ usb_mtp_inotify_cleanup(s);
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
s->session = 0;
usb_mtp_data_free(s->data_in);
diff --git a/trace-events b/trace-events
index 6a11f62..5b832a5 100644
--- a/trace-events
+++ b/trace-events
@@ -553,6 +553,9 @@ 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_mon(int dev, const char *path, int fd) "dev %d, path %s watchfd %d"
+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_mon(int dev, const char *path, int watchfd) "dev %d path %s watchfd %d"
# hw/usb/host-libusb.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
--
2.5.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 4/4] usb-mtp: add support for basic mtp events
2015-11-10 22:58 [Qemu-devel] [PATCH v2 0/4] usb-mtp events support Bandan Das
` (2 preceding siblings ...)
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring Bandan Das
@ 2015-11-10 22:58 ` Bandan Das
3 siblings, 0 replies; 7+ messages in thread
From: Bandan Das @ 2015-11-10 22:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Bandan Das, kraxel
When the host polls for events, we check our
events qlist and send one event at a time. Also, note
that the event packet needs to be sent in one go, so
I increased the max packet size to 64.
Tested with a linux guest.
Signed-off-by: Bandan Das <bsd@redhat.com>
---
hw/usb/dev-mtp.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 3c39a64..d9bc428 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -237,7 +237,7 @@ static const USBDescIface desc_iface_full = {
},{
.bEndpointAddress = USB_DIR_IN | EP_EVENT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
+ .wMaxPacketSize = 64,
.bInterval = 0x0a,
},
}
@@ -279,7 +279,7 @@ static const USBDescIface desc_iface_high = {
},{
.bEndpointAddress = USB_DIR_IN | EP_EVENT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
+ .wMaxPacketSize = 64,
.bInterval = 0x0a,
},
}
@@ -1349,6 +1349,29 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
}
break;
case EP_EVENT:
+ if (!QTAILQ_EMPTY(&s->events)) {
+ struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
+ uint32_t handle;
+ int len = sizeof(container) + sizeof(uint32_t);
+
+ if (p->iov.size < len) {
+ trace_usb_mtp_stall(s->dev.addr,
+ "packet too small to send event");
+ p->status = USB_RET_STALL;
+ return;
+ }
+
+ QTAILQ_REMOVE(&s->events, e, next);
+ container.length = cpu_to_le32(len);
+ container.type = cpu_to_le32(TYPE_EVENT);
+ container.code = cpu_to_le16(e->event);
+ container.trans = 0; /* no trans specific events */
+ handle = cpu_to_le32(e->handle);
+ usb_packet_copy(p, &container, sizeof(container));
+ usb_packet_copy(p, &handle, sizeof(uint32_t));
+ g_free(e);
+ return;
+ }
p->status = USB_RET_NAK;
return;
default:
--
2.5.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring Bandan Das
@ 2015-11-13 12:34 ` Gerd Hoffmann
2015-11-13 17:16 ` Bandan Das
0 siblings, 1 reply; 7+ messages in thread
From: Gerd Hoffmann @ 2015-11-13 12:34 UTC (permalink / raw)
To: Bandan Das; +Cc: qemu-devel
Hi,
> + switch (mask) {
> + case IN_CREATE:
> + if (event->mask & IN_ISDIR) {
> + /*
> + * Add the watchpoint first so we
> + * don't miss events in this subdir
> + */
> + name = g_strndup(event->name, event->len);
> + path = g_strdup_printf("%s/%s", parent->path, name);
> +
> + watchfd = usb_mtp_add_watch(s->inotifyfd, path);
> + g_free(path);
> + g_free(name);
> +
> + if (watchfd == -1) {
> + continue;
> + }
> + }
So, to follow up my mail from today in the morning:
I think this is not needed here ...
> usb_mtp_object_readdir(s, o);
> + if (usb_mtp_inotify_mon(s, o)) {
> + fprintf(stderr, "usb-mtp: adding watch for %s failed\n", o->path);
> + }
... but here we have to add the watch first, then read the directory.
When reading the directory first we'll miss new files which are added
after readdir() but before add_watch().
cheers,
Gerd
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring
2015-11-13 12:34 ` Gerd Hoffmann
@ 2015-11-13 17:16 ` Bandan Das
0 siblings, 0 replies; 7+ messages in thread
From: Bandan Das @ 2015-11-13 17:16 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
Gerd Hoffmann <kraxel@redhat.com> writes:
> Hi,
>
>> + switch (mask) {
>> + case IN_CREATE:
>> + if (event->mask & IN_ISDIR) {
>> + /*
>> + * Add the watchpoint first so we
>> + * don't miss events in this subdir
>> + */
>> + name = g_strndup(event->name, event->len);
>> + path = g_strdup_printf("%s/%s", parent->path, name);
>> +
>> + watchfd = usb_mtp_add_watch(s->inotifyfd, path);
>> + g_free(path);
>> + g_free(name);
>> +
>> + if (watchfd == -1) {
>> + continue;
>> + }
>> + }
>
> So, to follow up my mail from today in the morning:
>
> I think this is not needed here ...
>
>> usb_mtp_object_readdir(s, o);
>> + if (usb_mtp_inotify_mon(s, o)) {
>> + fprintf(stderr, "usb-mtp: adding watch for %s failed\n", o->path);
>> + }
>
> ... but here we have to add the watch first, then read the directory.
> When reading the directory first we'll miss new files which are added
> after readdir() but before add_watch().
Yep, this makes sense. So:
1. No need to add watch as soon as possible. As long as the guest knows there
is a directory(which it would because of the create event), it can request contents
at any time.
2. When it does, the first thing to do is add a watchpoint. Then, readdir does its thing
getting the dir contents and the watchpoint which has already been added will track new
changes.
3. We don't have to worry about content changes before the guest has requested
the folder contents.
Thanks for the review!
> cheers,
> Gerd
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-11-13 17:17 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-10 22:58 [Qemu-devel] [PATCH v2 0/4] usb-mtp events support Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 1/4] usb-mtp: use a list for keeping track of children Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 2/4] usb-mtp: free objects on a mtp reset Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 3/4] usb-mtp: Add support for inotify based file monitoring Bandan Das
2015-11-13 12:34 ` Gerd Hoffmann
2015-11-13 17:16 ` Bandan Das
2015-11-10 22:58 ` [Qemu-devel] [PATCH v2 4/4] usb-mtp: add support for basic mtp events Bandan Das
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).