mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
tools/xenstore: Don't assume conn->in points to the LU request
call_delayed() is currently assuming that conn->in is NULL when handling delayed request. However, the connection is not paused. Therefore new request can be processed and conn->in may be non-NULL if we have only received a partial request. Furthermore, as we overwrite conn->in, the current partial request will not be transferred. This will result to corrupt the connection. Rather than updating conn->in, stash the LU request in lu_status and let each callback for delayed request to update conn->in when necessary. To keep a sane interface, the code to write the "OK" response the LU request is moved in xenstored_core.c. Fixes:c5ca1404b4("tools/xenstore: add support for delaying execution of a xenstore request") Fixes:ed6eebf17d("tools/xenstore: dump the xenstore state for live update") Signed-off-by: Julien Grall <jgrall@amazon.com> Reviewed-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
1 parent
3ce271ef53
commit
65f19ed62a
3 files changed
+48
-17
No files matched your search
@@ -50,6 +50,9 @@ struct live_update {
|
||||
/* For verification the correct connection is acting. */
|
||||
struct connection *conn;
|
||||
|
||||
/* Pointer to the command used to request LU */
|
||||
struct buffered_data *in;
|
||||
|
||||
#ifdef __MINIOS__
|
||||
void *kernel;
|
||||
unsigned int kernel_size;
|
||||
@@ -100,6 +103,7 @@ static const char *lu_begin(struct connection *conn)
|
||||
if (!lu_status)
|
||||
return "Allocation failure.";
|
||||
lu_status->conn = conn;
|
||||
lu_status->in = conn->in;
|
||||
talloc_set_destructor(lu_status, lu_destroy);
|
||||
|
||||
return NULL;
|
||||
@@ -110,11 +114,34 @@ struct connection *lu_get_connection(void)
|
||||
return lu_status ? lu_status->conn : NULL;
|
||||
}
|
||||
|
||||
unsigned int lu_write_response(FILE *fp)
|
||||
{
|
||||
struct xsd_sockmsg msg;
|
||||
|
||||
assert(lu_status);
|
||||
|
||||
msg = lu_status->in->hdr.msg;
|
||||
|
||||
msg.len = sizeof("OK");
|
||||
if (fp && fwrite(&msg, sizeof(msg), 1, fp) != 1)
|
||||
return 0;
|
||||
if (fp && fwrite("OK", msg.len, 1, fp) != 1)
|
||||
return 0;
|
||||
|
||||
return sizeof(msg) + msg.len;
|
||||
}
|
||||
|
||||
#else
|
||||
struct connection *lu_get_connection(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int lu_write_response(FILE *fp)
|
||||
{
|
||||
/* Unsupported */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct cmd_s {
|
||||
@@ -658,6 +685,8 @@ static bool do_lu_start(struct delayed_request *req)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
const char *ret;
|
||||
struct buffered_data *saved_in;
|
||||
struct connection *conn = lu_status->conn;
|
||||
|
||||
if (!lu_check_lu_allowed()) {
|
||||
if (now < lu_status->started_at + lu_status->timeout)
|
||||
@@ -668,8 +697,9 @@ static bool do_lu_start(struct delayed_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
assert(req->in == lu_status->in);
|
||||
/* Dump out internal state, including "OK" for live update. */
|
||||
ret = lu_dump_state(req->in, lu_status->conn);
|
||||
ret = lu_dump_state(req->in, conn);
|
||||
if (!ret) {
|
||||
/* Perform the activation of new binary. */
|
||||
ret = lu_activate_binary(req->in);
|
||||
@@ -677,7 +707,14 @@ static bool do_lu_start(struct delayed_request *req)
|
||||
|
||||
/* We will reach this point only in case of failure. */
|
||||
out:
|
||||
send_reply(lu_status->conn, XS_CONTROL, ret, strlen(ret) + 1);
|
||||
/*
|
||||
* send_reply() will send the response for conn->in. Save the current
|
||||
* conn->in and restore it afterwards.
|
||||
*/
|
||||
saved_in = conn->in;
|
||||
conn->in = req->in;
|
||||
send_reply(conn, XS_CONTROL, ret, strlen(ret) + 1);
|
||||
conn->in = saved_in;
|
||||
talloc_free(lu_status);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -20,3 +20,6 @@ int do_control(struct connection *conn, struct buffered_data *in);
|
||||
void lu_read_state(void);
|
||||
|
||||
struct connection *lu_get_connection(void);
|
||||
|
||||
/* Write the "OK" response for the live-update command */
|
||||
unsigned int lu_write_response(FILE *fp);
|
||||
@@ -270,17 +270,12 @@ static int undelay_request(void *_req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void call_delayed(struct connection *conn, struct delayed_request *req)
|
||||
static void call_delayed(struct delayed_request *req)
|
||||
{
|
||||
assert(conn->in == NULL);
|
||||
conn->in = req->in;
|
||||
|
||||
if (req->func(req)) {
|
||||
undelay_request(req);
|
||||
talloc_set_destructor(req, NULL);
|
||||
}
|
||||
|
||||
conn->in = NULL;
|
||||
}
|
||||
|
||||
int delay_request(struct connection *conn, struct buffered_data *in,
|
||||
@@ -2342,7 +2337,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
list_for_each_entry_safe(req, tmp,
|
||||
&conn->delayed, list)
|
||||
call_delayed(conn, req);
|
||||
call_delayed(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2375,7 +2370,7 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
|
||||
struct buffered_data *out, *in = c->in;
|
||||
bool partial = true;
|
||||
|
||||
if (in && c != lu_get_connection()) {
|
||||
if (in) {
|
||||
len = in->inhdr ? in->used : sizeof(in->hdr);
|
||||
if (fp && fwrite(&in->hdr, len, 1, fp) != 1)
|
||||
return "Dump read data error";
|
||||
@@ -2416,16 +2411,12 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
|
||||
|
||||
/* Add "OK" for live-update command. */
|
||||
if (c == lu_get_connection()) {
|
||||
struct xsd_sockmsg msg = c->in->hdr.msg;
|
||||
unsigned int rc = lu_write_response(fp);
|
||||
|
||||
msg.len = sizeof("OK");
|
||||
if (fp && fwrite(&msg, sizeof(msg), 1, fp) != 1)
|
||||
if (!rc)
|
||||
return "Dump buffered data error";
|
||||
len += sizeof(msg);
|
||||
if (fp && fwrite("OK", msg.len, 1, fp) != 1)
|
||||
|
||||
return "Dump buffered data error";
|
||||
len += msg.len;
|
||||
len += rc;
|
||||
}
|
||||
|
||||
if (sc)
|
||||
|
||||