forked from QubesOS/qubes-vmm-xen
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpatch-0011-xenstore-add-small-default-data-buffer-to-internal-s.patch
346 lines (303 loc) · 11.7 KB
/
patch-0011-xenstore-add-small-default-data-buffer-to-internal-s.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
From 3ff5bfd3c2ffa4d9429579e21df7e51a6605aa53 Mon Sep 17 00:00:00 2001
From: Juergen Gross <[email protected]>
Date: Mon, 5 Dec 2016 08:48:52 +0100
Subject: [PATCH 11/25] xenstore: add small default data buffer to internal
struct
Instead of always allocating a data buffer for incoming or outgoing
xenstore wire data add a small buffer to the buffered_data structure
of xenstored. This has the advantage that especially sending simple
response messages like errors or "OK" will no longer need allocating
a data buffer. This requires adding a memory context where the
allocated buffer was used for that purpose.
In order to avoid allocating a new buffered_data structure for each
response reuse the structure of the original request. This in turn
will avoid any new memory allocations for sending e.g. an ENOMEM
response making it possible to send it at all. To do this the
allocation of the buffered_data structure for the incoming request
must be done when a new request is recognized instead of doing it
when accepting a new connect.
Signed-off-by: Juergen Gross <[email protected]>
Acked-by: Wei Liu <[email protected]>
---
tools/xenstore/xenstored_core.c | 80 +++++++++++++++-----------
tools/xenstore/xenstored_core.h | 6 +-
tools/xenstore/xenstored_domain.c | 4 +-
tools/xenstore/xenstored_transaction.c | 4 +-
tools/xenstore/xenstored_watch.c | 4 +-
5 files changed, 55 insertions(+), 43 deletions(-)
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8cf93fb79e1f..537967127034 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -652,17 +652,20 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
return;
}
- /* Message is a child of the connection context for auto-cleanup. */
- bdata = new_buffer(conn);
- bdata->buffer = talloc_array(bdata, char, len);
-
- /* Echo request header in reply unless this is an async watch event. */
+ /* Replies reuse the request buffer, events need a new one. */
if (type != XS_WATCH_EVENT) {
- memcpy(&bdata->hdr.msg, &conn->in->hdr.msg,
- sizeof(struct xsd_sockmsg));
+ bdata = conn->in;
+ bdata->inhdr = true;
+ bdata->used = 0;
+ conn->in = NULL;
} else {
- memset(&bdata->hdr.msg, 0, sizeof(struct xsd_sockmsg));
+ /* Message is a child of the connection for auto-cleanup. */
+ bdata = new_buffer(conn);
}
+ if (len <= DEFAULT_BUFFER_SIZE)
+ bdata->buffer = bdata->default_buffer;
+ else
+ bdata->buffer = talloc_array(bdata, char, len);
/* Update relevant header fields and fill in the message body. */
bdata->hdr.msg.type = type;
@@ -738,7 +741,7 @@ static char *perms_to_strings(const void *ctx,
return strings;
}
-char *canonicalize(struct connection *conn, const char *node)
+char *canonicalize(struct connection *conn, const void *ctx, const char *node)
{
const char *prefix;
@@ -746,7 +749,7 @@ char *canonicalize(struct connection *conn, const char *node)
return (char *)node;
prefix = get_implicit_path(conn);
if (prefix)
- return talloc_asprintf(node, "%s/%s", prefix, node);
+ return talloc_asprintf(ctx, "%s/%s", prefix, node);
return (char *)node;
}
@@ -760,7 +763,7 @@ static struct node *get_node_canonicalized(struct connection *conn,
if (!canonical_name)
canonical_name = &tmp_name;
- *canonical_name = canonicalize(conn, name);
+ *canonical_name = canonicalize(conn, ctx, name);
return get_node(conn, ctx, *canonical_name, perm);
}
@@ -870,17 +873,18 @@ static char *basename(const char *name)
return strrchr(name, '/') + 1;
}
-static struct node *construct_node(struct connection *conn, const char *name)
+static struct node *construct_node(struct connection *conn, const void *ctx,
+ const char *name)
{
const char *base;
unsigned int baselen;
struct node *parent, *node;
- char *children, *parentname = get_parent(name, name);
+ char *children, *parentname = get_parent(ctx, name);
/* If parent doesn't exist, create it. */
parent = read_node(conn, parentname, parentname);
if (!parent)
- parent = construct_node(conn, parentname);
+ parent = construct_node(conn, ctx, parentname);
if (!parent)
return NULL;
@@ -890,14 +894,14 @@ static struct node *construct_node(struct connection *conn, const char *name)
/* Add child to parent. */
base = basename(name);
baselen = strlen(base) + 1;
- children = talloc_array(name, char, parent->childlen + baselen);
+ children = talloc_array(ctx, char, parent->childlen + baselen);
memcpy(children, parent->children, parent->childlen);
memcpy(children + parent->childlen, base, baselen);
parent->children = children;
parent->childlen += baselen;
/* Allocate node */
- node = talloc(name, struct node);
+ node = talloc(ctx, struct node);
node->tdb = tdb_context(conn);
node->name = talloc_strdup(node, name);
@@ -931,13 +935,13 @@ static int destroy_node(void *_node)
return 0;
}
-static struct node *create_node(struct connection *conn,
+static struct node *create_node(struct connection *conn, const void *ctx,
const char *name,
void *data, unsigned int datalen)
{
struct node *node, *i;
- node = construct_node(conn, name);
+ node = construct_node(conn, ctx, name);
if (!node)
return NULL;
@@ -980,7 +984,8 @@ static int do_write(struct connection *conn, struct buffered_data *in)
/* No permissions, invalid input? */
if (errno != ENOENT)
return errno;
- node = create_node(conn, name, in->buffer + offset, datalen);
+ node = create_node(conn, in, name, in->buffer + offset,
+ datalen);
if (!node)
return errno;
} else {
@@ -1010,7 +1015,7 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
/* No permissions? */
if (errno != ENOENT)
return errno;
- node = create_node(conn, name, NULL, 0);
+ node = create_node(conn, in, name, NULL, 0);
if (!node)
return errno;
wrl_apply_debit_direct(conn);
@@ -1082,12 +1087,13 @@ static bool delete_child(struct connection *conn,
}
-static int _rm(struct connection *conn, struct node *node, const char *name)
+static int _rm(struct connection *conn, const void *ctx, struct node *node,
+ const char *name)
{
/* Delete from parent first, then if we crash, the worst that can
happen is the child will continue to take up space, but will
otherwise be unreachable. */
- struct node *parent = read_node(conn, name, get_parent(name, name));
+ struct node *parent = read_node(conn, ctx, get_parent(ctx, name));
if (!parent)
return EINVAL;
@@ -1104,7 +1110,7 @@ static void internal_rm(const char *name)
char *tname = talloc_strdup(NULL, name);
struct node *node = read_node(NULL, tname, tname);
if (node)
- _rm(NULL, node, tname);
+ _rm(NULL, tname, node, tname);
talloc_free(node);
talloc_free(tname);
}
@@ -1135,7 +1141,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
if (streq(name, "/"))
return EINVAL;
- ret = _rm(conn, node, name);
+ ret = _rm(conn, in, node, name);
if (ret)
return ret;
@@ -1310,8 +1316,7 @@ static void consider_message(struct connection *conn)
process_message(conn, conn->in);
- talloc_free(conn->in);
- conn->in = new_buffer(conn);
+ assert(conn->in == NULL);
}
/* Errors in reading or allocating here mean we get out of sync, so we
@@ -1319,7 +1324,15 @@ static void consider_message(struct connection *conn)
static void handle_input(struct connection *conn)
{
int bytes;
- struct buffered_data *in = conn->in;
+ struct buffered_data *in;
+
+ if (!conn->in) {
+ conn->in = new_buffer(conn);
+ /* In case of no memory just try it next time again. */
+ if (!conn->in)
+ return;
+ }
+ in = conn->in;
/* Not finished header yet? */
if (in->inhdr) {
@@ -1337,7 +1350,10 @@ static void handle_input(struct connection *conn)
goto bad_client;
}
- in->buffer = talloc_array(in, char, in->hdr.msg.len);
+ if (in->hdr.msg.len <= DEFAULT_BUFFER_SIZE)
+ in->buffer = in->default_buffer;
+ else
+ in->buffer = talloc_array(in, char, in->hdr.msg.len);
if (!in->buffer)
goto bad_client;
in->used = 0;
@@ -1386,12 +1402,6 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
INIT_LIST_HEAD(&new->watches);
INIT_LIST_HEAD(&new->transaction_list);
- new->in = new_buffer(new);
- if (new->in == NULL) {
- talloc_free(new);
- return NULL;
- }
-
list_add_tail(&new->list, &connections);
talloc_set_destructor(new, destroy_conn);
trace_create(new, "connection");
@@ -1531,7 +1541,7 @@ static void setup_structure(void)
if (remove_local) {
internal_rm("/local");
- create_node(NULL, tlocal, NULL, 0);
+ create_node(NULL, NULL, tlocal, NULL, 0);
check_store();
}
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1556f26b6c9b..77024644275e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -39,6 +39,9 @@ typedef int32_t wrl_creditt;
#define WRL_CREDIT_MAX (1000*1000*1000)
/* ^ satisfies non-overflow condition for wrl_xfer_credit */
+/* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
+#define DEFAULT_BUFFER_SIZE 16
+
struct buffered_data
{
struct list_head list;
@@ -56,6 +59,7 @@ struct buffered_data
/* The actual data. */
char *buffer;
+ char default_buffer[DEFAULT_BUFFER_SIZE];
};
struct connection;
@@ -145,7 +149,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
/* Canonicalize this path if possible. */
-char *canonicalize(struct connection *conn, const char *node);
+char *canonicalize(struct connection *conn, const void *ctx, const char *node);
/* Get this node, checking we have permissions. */
struct node *get_node(struct connection *conn,
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index cefb8e4006ce..1e88f1202d06 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -348,9 +348,7 @@ static void domain_conn_reset(struct domain *domain)
talloc_free(out);
}
- talloc_free(conn->in->buffer);
- memset(conn->in, 0, sizeof(*conn->in));
- conn->in->inhdr = true;
+ talloc_free(conn->in);
domain->interface->req_cons = domain->interface->req_prod = 0;
domain->interface->rsp_cons = domain->interface->rsp_prod = 0;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 9797fa501692..2bd34c02a771 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -211,8 +211,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
list_del(&trans->list);
conn->transaction_started--;
- /* Attach transaction to arg for auto-cleanup */
- talloc_steal(arg, trans);
+ /* Attach transaction to in for auto-cleanup */
+ talloc_steal(in, trans);
if (streq(arg, "T")) {
/* FIXME: Merge, rather failing on any change. */
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index e1146edeb29e..94251dba91bd 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -164,7 +164,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
/* check if valid event */
} else {
relative = !strstarts(vec[0], "/");
- vec[0] = canonicalize(conn, vec[0]);
+ vec[0] = canonicalize(conn, in, vec[0]);
if (!is_valid_nodename(vec[0]))
return EINVAL;
}
@@ -209,7 +209,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
return EINVAL;
- node = canonicalize(conn, vec[0]);
+ node = canonicalize(conn, in, vec[0]);
list_for_each_entry(watch, &conn->watches, list) {
if (streq(watch->node, node) && streq(watch->token, vec[1])) {
list_del(&watch->list);
--
2.25.4