@@ -36,6 +36,8 @@
#include "qapi/qapi-visit-sockets.h"
#include "chardev/char-io.h"
+#include "sysemu/sysemu.h"
+#include "qemu/cutils.h"
/***********************************************************/
/* TCP Net console */
@@ -400,6 +402,7 @@ static void tcp_chr_free_connection(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
int i;
+ unsetenv_fd(chr->label);
if (s->read_msgfds_num) {
for (i = 0; i < s->read_msgfds_num; i++) {
close(s->read_msgfds[i]);
@@ -1375,6 +1378,9 @@ static void qmp_chardev_open_socket(Chardev *chr,
return;
}
}
+
+ load_char_socket_fd(chr);
+
}
static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
@@ -1517,3 +1523,32 @@ static void register_types(void)
}
type_init(register_types);
+
+void save_char_socket_fd(Chardev *chr)
+{
+ SocketChardev *sockchar = SOCKET_CHARDEV(chr);
+
+ if (sockchar->sioc) {
+ setenv_fd(chr->label, sockchar->sioc->fd);
+ }
+}
+
+void load_char_socket_fd(Chardev *chr)
+{
+ SocketChardev *sockchar;
+ QIOChannelSocket *sioc;
+
+ int fd = getenv_fd(chr->label);
+
+ if (fd != -1) {
+ unsetenv_fd(chr->label);
+ sockchar = SOCKET_CHARDEV(chr);
+ sioc = qio_channel_socket_accept(*sockchar->listener->sioc, fd, NULL);
+ if (sioc) {
+ tcp_chr_accept(sockchar->listener, sioc, chr);
+ } else {
+ error_printf("error: could not restore socket for %s\n",
+ chr->label);
+ }
+ }
+}
@@ -34,6 +34,7 @@
#include "qapi/qapi-commands-char.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/replay.h"
+#include "sysemu/sysemu.h"
#include "qemu/help_option.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -1174,3 +1175,16 @@ static void register_types(void)
}
type_init(register_types);
+
+static int chardev_is_socket(Object *child, void *opaque)
+{
+ if (CHARDEV_IS_SOCKET(child)) {
+ save_char_socket_fd((Chardev *) child);
+ }
+ return 0;
+}
+
+void save_chardev_fds(void)
+{
+ object_child_foreach(get_chardevs_root(), chardev_is_socket, NULL);
+}
@@ -250,6 +250,8 @@ int qemu_chr_wait_connected(Chardev *chr, Error **errp);
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
#define CHARDEV_IS_PTY(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_PTY)
+#define CHARDEV_IS_SOCKET(chr) \
+ object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_SOCKET)
typedef struct ChardevClass {
ObjectClass parent_class;
@@ -290,4 +292,7 @@ GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms,
/* console.c */
void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp);
+void save_char_socket_fd(Chardev *);
+void load_char_socket_fd(Chardev *);
+
#endif
@@ -27,6 +27,7 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify);
void save_cpr_snapshot(const char *file, const char *mode, Error **errp);
void load_cpr_snapshot(const char *file, Error **errp);
+void save_chardev_fds(void);
extern int autostart;
@@ -2700,6 +2700,12 @@ static QEMUFile *qf_file_open(const char *filename, int flags, int mode,
return qemu_fopen_channel_input(ioc);
}
+static int preserve_fd(const char *name, const char *val, void *handle)
+{
+ qemu_clr_cloexec(atoi(val));
+ return 0;
+}
+
void save_cpr_snapshot(const char *file, const char *mode, Error **errp)
{
int ret = 0;
@@ -2761,6 +2767,8 @@ void save_cpr_snapshot(const char *file, const char *mode, Error **errp)
if (qemu_preserve_ram(errp)) {
return;
}
+ save_chardev_fds();
+ walkenv(FD_PREFIX, preserve_fd, 0);
qemu_system_exec_request();
putenv((char *)"QEMU_START_FREEZE=");
}