mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Test and fix acknowedge_watch from returning EINVAL.
Also ensure that daemon re-xmits event if they ack wrong thing (otherwise confused clients get stuck, as we will send no more data while awaiting ack). Signed-off-by: Rusty Russel <rusty@rustcorp.com.au> Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
a9c1da21e1
commit
e08ecc0000
4 files changed
+34
-7
No files matched your search
@@ -0,0 +1,22 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This demonstrates a bug where an xs_acknowledge_watch returns
|
||||
# EINVAL, because the daemon doesn't track what watch event it sent
|
||||
# and relies on it being the "first" watch which has an event.
|
||||
# Watches firing after the first event is sent out will change this.
|
||||
|
||||
# Create three things to watch.
|
||||
echo mkdir /test | ./xs_test
|
||||
echo mkdir /test/1 | ./xs_test
|
||||
echo mkdir /test/2 | ./xs_test
|
||||
echo mkdir /test/3 | ./xs_test
|
||||
|
||||
# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2.
|
||||
[ "`echo '1 watch /test/1 token1 0
|
||||
1 watch /test/2 token2 0
|
||||
1 watch /test/3 token3 0
|
||||
2 write /test/2 create contents2
|
||||
1 waitwatch
|
||||
2 write /test/1 create contents1
|
||||
2 write /test/3 create contents3
|
||||
1 ackwatch token2' | ./xs_test 2>&1`" = "1:/test/2:token2" ]
|
||||
@@ -1166,7 +1166,7 @@ static void consider_message(struct connection *conn)
|
||||
/* We might get a command while waiting for an ack: this means
|
||||
* the other end discarded it: we will re-transmit. */
|
||||
if (type != XS_WATCH_ACK)
|
||||
conn->waiting_for_ack = false;
|
||||
conn->waiting_for_ack = NULL;
|
||||
|
||||
/* Careful: process_message may free connection. We detach
|
||||
* "in" beforehand and allocate the new buffer to avoid
|
||||
|
||||
@@ -64,7 +64,7 @@ struct connection
|
||||
bool can_write;
|
||||
|
||||
/* Are we waiting for a watch event ack? */
|
||||
bool waiting_for_ack;
|
||||
struct watch *waiting_for_ack;
|
||||
|
||||
/* Buffered incoming data. */
|
||||
struct buffered_data *in;
|
||||
|
||||
@@ -102,7 +102,7 @@ void queue_next_event(struct connection *conn)
|
||||
if (conn->waiting_reply) {
|
||||
conn->out = conn->waiting_reply;
|
||||
conn->waiting_reply = NULL;
|
||||
conn->waiting_for_ack = false;
|
||||
conn->waiting_for_ack = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ void queue_next_event(struct connection *conn)
|
||||
return;
|
||||
|
||||
/* If we decide to cancel, we will reset this. */
|
||||
conn->waiting_for_ack = true;
|
||||
conn->waiting_for_ack = event->watches[0];
|
||||
|
||||
/* If we deleted /foo and they're watching /foo/bar, that's what we
|
||||
* tell them has changed. */
|
||||
@@ -348,12 +348,17 @@ bool do_watch_ack(struct connection *conn, const char *token)
|
||||
if (!conn->waiting_for_ack)
|
||||
return send_error(conn, ENOENT);
|
||||
|
||||
event = get_first_event(conn);
|
||||
if (!streq(event->watches[0]->token, token))
|
||||
event = list_top(&conn->waiting_for_ack->events,
|
||||
struct watch_event, list);
|
||||
assert(event->watches[0] == conn->waiting_for_ack);
|
||||
if (!streq(conn->waiting_for_ack->token, token)) {
|
||||
/* They're confused: this will cause us to send event again */
|
||||
conn->waiting_for_ack = NULL;
|
||||
return send_error(conn, EINVAL);
|
||||
}
|
||||
|
||||
move_event_onwards(event);
|
||||
conn->waiting_for_ack = false;
|
||||
conn->waiting_for_ack = NULL;
|
||||
return send_ack(conn, XS_WATCH_ACK);
|
||||
}
|
||||
|
||||
|
||||