1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4 * Live Update interfaces for Xen Store Daemon.
5 * Copyright (C) 2022 Juergen Gross, SUSE LLC
6 */
7
8 #include <assert.h>
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <syslog.h>
13 #include <time.h>
14 #include <unistd.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17
18 #include "talloc.h"
19 #include "core.h"
20 #include "domain.h"
21 #include "lu.h"
22 #include "watch.h"
23
24 struct live_update *lu_status;
25
26 #ifndef NO_LIVE_UPDATE
27
28 struct lu_dump_state {
29 void *buf;
30 unsigned int buf_size;
31 size_t size;
32 size_t offset;
33 char *filename;
34 FILE *fp;
35 };
36
lu_destroy(void * data)37 static int lu_destroy(void *data)
38 {
39 lu_status = NULL;
40
41 return 0;
42 }
43
lu_begin(struct connection * conn)44 const char *lu_begin(struct connection *conn)
45 {
46 if (lu_status)
47 return "live-update session already active.";
48
49 lu_status = talloc_zero(conn, struct live_update);
50 if (!lu_status)
51 return "Allocation failure.";
52 lu_status->conn = conn;
53 talloc_set_destructor(lu_status, lu_destroy);
54
55 return NULL;
56 }
57
lu_get_connection(void)58 struct connection *lu_get_connection(void)
59 {
60 return lu_status ? lu_status->conn : NULL;
61 }
62
lu_write_response(FILE * fp)63 unsigned int lu_write_response(FILE *fp)
64 {
65 struct xsd_sockmsg msg;
66
67 assert(lu_status);
68
69 msg = lu_status->in->hdr.msg;
70
71 msg.len = sizeof("OK");
72 if (fp && fwrite(&msg, sizeof(msg), 1, fp) != 1)
73 return 0;
74 if (fp && fwrite("OK", msg.len, 1, fp) != 1)
75 return 0;
76
77 return sizeof(msg) + msg.len;
78 }
79
lu_is_pending(void)80 bool lu_is_pending(void)
81 {
82 return lu_status != NULL;
83 }
84
lu_get_dump_state(void * ctx,struct lu_dump_state * state)85 static void lu_get_dump_state(void *ctx, struct lu_dump_state *state)
86 {
87 struct stat statbuf;
88 int fd;
89
90 state->size = 0;
91
92 state->filename = talloc_asprintf(NULL, "%s/state_dump",
93 xenstore_rundir());
94 if (!state->filename)
95 barf("Allocation failure");
96
97 fd = open(state->filename, O_RDONLY);
98 if (fd < 0)
99 barf("No state file found");
100 if (fstat(fd, &statbuf) != 0)
101 barf("Could not fstat state file");
102 state->size = statbuf.st_size;
103
104 /* Start with a 4k buffer. If needed we'll reallocate a larger one. */
105 state->buf_size = 4096;
106 state->buf = talloc_size(ctx, state->buf_size);
107 if (!state->buf)
108 barf("Allocation failure");
109
110 state->fp = fdopen(fd, "r");
111 }
112
lu_dump_close(FILE * fp)113 static void lu_dump_close(FILE *fp)
114 {
115 fclose(fp);
116 }
117
lu_close_dump_state(struct lu_dump_state * state)118 static void lu_close_dump_state(struct lu_dump_state *state)
119 {
120 assert(state->filename != NULL);
121
122 lu_dump_close(state->fp);
123
124 unlink(state->filename);
125 talloc_free(state->filename);
126 talloc_free(state->buf);
127 }
128
lu_read_data(void * ctx,struct lu_dump_state * state,unsigned int size)129 static void lu_read_data(void *ctx, struct lu_dump_state *state,
130 unsigned int size)
131 {
132 if (state->offset + size > state->size)
133 barf("Inconsistent state data");
134
135 if (size > state->buf_size) {
136 state->buf = talloc_realloc_size(ctx, state->buf, size);
137 if (!state->buf)
138 barf("Allocation failure");
139 state->buf_size = size;
140 }
141
142 if (fread(state->buf, size, 1, state->fp) != 1)
143 barf("State read error");
144
145 state->offset += size;
146 }
147
lu_read_state(void)148 void lu_read_state(void)
149 {
150 struct lu_dump_state state = {};
151 struct xs_state_record_header head;
152 void *ctx = talloc_new(NULL); /* Work context for subfunctions. */
153 struct xs_state_preamble *pre;
154 unsigned int version;
155
156 syslog(LOG_INFO, "live-update: read state\n");
157 lu_get_dump_state(ctx, &state);
158 if (state.size == 0)
159 barf_perror("No state found after live-update");
160
161 lu_read_data(ctx, &state, sizeof(*pre));
162 pre = state.buf;
163 version = be32toh(pre->version);
164 if (memcmp(pre->ident, XS_STATE_IDENT, sizeof(pre->ident)) ||
165 !version || version > XS_STATE_VERSION ||
166 pre->flags != XS_STATE_FLAGS)
167 barf("Unknown record identifier");
168
169 for (;;) {
170 lu_read_data(ctx, &state, sizeof(head));
171 head = *(struct xs_state_record_header *)(state.buf);
172 if (head.type == XS_STATE_TYPE_END)
173 break;
174 lu_read_data(ctx, &state, head.length);
175
176 switch (head.type) {
177 case XS_STATE_TYPE_GLOBAL:
178 read_state_global(ctx, state.buf);
179 break;
180 case XS_STATE_TYPE_CONN:
181 read_state_connection(ctx, state.buf);
182 break;
183 case XS_STATE_TYPE_WATCH:
184 read_state_watch(ctx, state.buf);
185 break;
186 case XS_STATE_TYPE_TA:
187 xprintf("live-update: ignore transaction record\n");
188 break;
189 case XS_STATE_TYPE_NODE:
190 read_state_node(ctx, state.buf);
191 break;
192 case XS_STATE_TYPE_DOMAIN:
193 read_state_domain(ctx, state.buf, version);
194 break;
195 default:
196 xprintf("live-update: unknown state record %08x\n",
197 head.type);
198 break;
199 }
200 }
201
202 lu_close_dump_state(&state);
203
204 talloc_free(ctx);
205
206 /*
207 * We may have missed the VIRQ_DOM_EXC notification and a domain may
208 * have died while we were live-updating. So check all the domains are
209 * still alive.
210 */
211 check_domains();
212 }
213
lu_abort(const void * ctx,struct connection * conn)214 static const char *lu_abort(const void *ctx, struct connection *conn)
215 {
216 syslog(LOG_INFO, "live-update: abort\n");
217
218 if (!lu_status)
219 return "No live-update session active.";
220
221 /* Destructor will do the real abort handling. */
222 talloc_free(lu_status);
223
224 return NULL;
225 }
226
lu_cmdline(const void * ctx,struct connection * conn,const char * cmdline)227 static const char *lu_cmdline(const void *ctx, struct connection *conn,
228 const char *cmdline)
229 {
230 syslog(LOG_INFO, "live-update: cmdline %s\n", cmdline);
231
232 if (!lu_status || lu_status->conn != conn)
233 return "Not in live-update session.";
234
235 lu_status->cmdline = talloc_strdup(lu_status, cmdline);
236 if (!lu_status->cmdline)
237 return "Allocation failure.";
238
239 return NULL;
240 }
241
lu_check_lu_allowed(void)242 static bool lu_check_lu_allowed(void)
243 {
244 struct connection *conn;
245 time_t now = time(NULL);
246 unsigned int ta_total = 0, ta_long = 0;
247
248 list_for_each_entry(conn, &connections, list) {
249 if (conn->ta_start_time) {
250 ta_total++;
251 if (now - conn->ta_start_time >= lu_status->timeout)
252 ta_long++;
253 }
254 }
255
256 /*
257 * Allow LiveUpdate if one of the following conditions is met:
258 * - There is no active transactions
259 * - All transactions are long running (e.g. they have been
260 * active for more than lu_status->timeout sec) and the admin as
261 * requested to force the operation.
262 */
263 return ta_total ? (lu_status->force && ta_long == ta_total) : true;
264 }
265
lu_reject_reason(const void * ctx)266 static const char *lu_reject_reason(const void *ctx)
267 {
268 char *ret = NULL;
269 struct connection *conn;
270 time_t now = time(NULL);
271
272 list_for_each_entry(conn, &connections, list) {
273 unsigned long tdiff = now - conn->ta_start_time;
274
275 if (conn->ta_start_time && (tdiff >= lu_status->timeout)) {
276 ret = talloc_asprintf(ctx, "%s\nDomain %u: %ld s",
277 ret ? : "Domains with long running transactions:",
278 conn->id, tdiff);
279 }
280 }
281
282 return ret ? (const char *)ret : "Overlapping transactions";
283 }
284
lu_dump_open(const void * ctx)285 static FILE *lu_dump_open(const void *ctx)
286 {
287 char *filename;
288 int fd;
289
290 filename = talloc_asprintf(ctx, "%s/state_dump",
291 xenstore_rundir());
292 if (!filename)
293 return NULL;
294
295 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
296 if (fd < 0)
297 return NULL;
298
299 return fdopen(fd, "w");
300 }
301
lu_dump_state(const void * ctx,struct connection * conn)302 static const char *lu_dump_state(const void *ctx, struct connection *conn)
303 {
304 FILE *fp;
305 const char *ret;
306 struct xs_state_record_header end;
307 struct xs_state_preamble pre;
308
309 fp = lu_dump_open(ctx);
310 if (!fp)
311 return "Dump state open error";
312
313 memcpy(pre.ident, XS_STATE_IDENT, sizeof(pre.ident));
314 pre.version = htobe32(lu_status->version);
315 pre.flags = XS_STATE_FLAGS;
316 if (fwrite(&pre, sizeof(pre), 1, fp) != 1) {
317 ret = "Dump write error";
318 goto out;
319 }
320
321 ret = dump_state_global(fp);
322 if (ret)
323 goto out;
324 ret = dump_state_connections(fp);
325 if (ret)
326 goto out;
327 ret = dump_state_nodes(fp, ctx);
328 if (ret)
329 goto out;
330 ret = dump_state_domains(fp);
331 if (ret)
332 goto out;
333
334 end.type = XS_STATE_TYPE_END;
335 end.length = 0;
336 if (fwrite(&end, sizeof(end), 1, fp) != 1)
337 ret = "Dump write error";
338
339 out:
340 lu_dump_close(fp);
341
342 return ret;
343 }
344
lu_activate_binary(const void * ctx)345 static const char *lu_activate_binary(const void *ctx)
346 {
347 int argc;
348 char **argv;
349 unsigned int i;
350
351 if (lu_status->cmdline) {
352 argc = 4; /* At least one arg + progname + "-U" + NULL. */
353 for (i = 0; lu_status->cmdline[i]; i++)
354 if (isspace(lu_status->cmdline[i]))
355 argc++;
356 argv = talloc_array(ctx, char *, argc);
357 if (!argv)
358 return "Allocation failure.";
359
360 i = 0;
361 argc = 1;
362 argv[1] = strtok(lu_status->cmdline, " \t");
363 while (argv[argc]) {
364 if (!strcmp(argv[argc], "-U"))
365 i = 1;
366 argc++;
367 argv[argc] = strtok(NULL, " \t");
368 }
369
370 if (!i) {
371 argv[argc++] = "-U";
372 argv[argc] = NULL;
373 }
374 } else {
375 for (i = 0; i < orig_argc; i++)
376 if (!strcmp(orig_argv[i], "-U"))
377 break;
378
379 argc = orig_argc;
380 argv = talloc_array(ctx, char *, orig_argc + 2);
381 if (!argv)
382 return "Allocation failure.";
383
384 memcpy(argv, orig_argv, orig_argc * sizeof(*argv));
385 if (i == orig_argc)
386 argv[argc++] = "-U";
387 argv[argc] = NULL;
388 }
389
390 domain_deinit();
391
392 return lu_exec(ctx, argc, argv);
393 }
394
do_lu_start(struct delayed_request * req)395 static bool do_lu_start(struct delayed_request *req)
396 {
397 time_t now = time(NULL);
398 const char *ret;
399 struct buffered_data *saved_in;
400 struct connection *conn = req->data;
401
402 /*
403 * Cancellation may have been requested asynchronously. In this
404 * case, lu_status will be NULL.
405 */
406 if (!lu_status) {
407 ret = "Cancellation was requested";
408 goto out;
409 }
410
411 assert(lu_status->conn == conn);
412
413 if (!lu_check_lu_allowed()) {
414 if (now < lu_status->started_at + lu_status->timeout)
415 return false;
416 if (!lu_status->force) {
417 ret = lu_reject_reason(req);
418 goto out;
419 }
420 }
421
422 assert(req->in == lu_status->in);
423 /* Dump out internal state, including "OK" for live update. */
424 ret = lu_dump_state(req->in, conn);
425 if (!ret) {
426 /* Perform the activation of new binary. */
427 ret = lu_activate_binary(req->in);
428 }
429
430 /* We will reach this point only in case of failure. */
431 out:
432 /*
433 * send_reply() will send the response for conn->in. Save the current
434 * conn->in and restore it afterwards.
435 */
436 saved_in = conn->in;
437 conn->in = req->in;
438 send_reply(conn, XS_CONTROL, ret, strlen(ret) + 1);
439 conn->in = saved_in;
440 talloc_free(lu_status);
441
442 return true;
443 }
444
lu_start(const void * ctx,struct connection * conn,bool force,unsigned int to,unsigned int vers)445 static const char *lu_start(const void *ctx, struct connection *conn,
446 bool force, unsigned int to, unsigned int vers)
447 {
448 syslog(LOG_INFO, "live-update: start, force=%d, to=%u\n", force, to);
449
450 if (!lu_status || lu_status->conn != conn)
451 return "Not in live-update session.";
452
453 if (!vers || vers > XS_STATE_VERSION)
454 return "Migration stream version not supported.";
455
456 #ifdef __MINIOS__
457 if (lu_status->kernel_size != lu_status->kernel_off)
458 return "Kernel not complete.";
459 #endif
460
461 lu_status->force = force;
462 lu_status->timeout = to;
463 lu_status->version = vers;
464 lu_status->started_at = time(NULL);
465 lu_status->in = conn->in;
466
467 errno = delay_request(conn, conn->in, do_lu_start, conn, false);
468
469 return NULL;
470 }
471
do_control_lu(const void * ctx,struct connection * conn,const char ** vec,int num)472 int do_control_lu(const void *ctx, struct connection *conn, const char **vec,
473 int num)
474 {
475 const char *ret = NULL;
476 unsigned int i;
477 bool force = false;
478 unsigned int to = 0;
479 unsigned int vers = XS_STATE_VERSION;
480
481 if (num < 1)
482 return EINVAL;
483
484 if (!strcmp(vec[0], "-a")) {
485 if (num == 1)
486 ret = lu_abort(ctx, conn);
487 else
488 return EINVAL;
489 } else if (!strcmp(vec[0], "-c")) {
490 if (num == 2)
491 ret = lu_cmdline(ctx, conn, vec[1]);
492 else
493 return EINVAL;
494 } else if (!strcmp(vec[0], "-s")) {
495 for (i = 1; i < num; i++) {
496 if (!strcmp(vec[i], "-F")) {
497 force = true;
498 } else if (!strcmp(vec[i], "-t") && i < num - 1) {
499 i++;
500 to = atoi(vec[i]);
501 } else if (!strcmp(vec[i], "-v") && i < num - 1) {
502 i++;
503 vers = atoi(vec[i]);
504 } else {
505 return EINVAL;
506 }
507 }
508 ret = lu_start(ctx, conn, force, to, vers);
509 if (!ret)
510 return errno;
511 } else {
512 ret = lu_arch(ctx, conn, vec, num);
513 if (!ret && errno)
514 return errno;
515 }
516
517 if (!ret)
518 ret = "OK";
519 send_reply(conn, XS_CONTROL, ret, strlen(ret) + 1);
520 return 0;
521 }
522 #endif
523