From 39097daf15c42243742667607d2cad2c9dc4f764 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Fri, 1 Mar 2013 11:40:27 -0600 Subject: qemu-ga: use key-value store to avoid recycling fd handles after restart Hosts hold on to handles provided by guest-file-open for periods that can span beyond the life of the qemu-ga process that issued them. Since these are issued starting from 0 on every restart, we run the risk of issuing duplicate handles after restarts/reboots. As a result, users with a stale copy of these handles may end up reading/writing corrupted data due to their existing handles effectively being re-assigned to an unexpected file or offset. We unfortunately do not issue handles as strings, but as integers, so a solution such as using UUIDs can't be implemented without introducing a new interface. As a workaround, we fix this by implementing a persistent key-value store that will be used to track the value of the last handle that was issued across restarts/reboots to avoid issuing duplicates. The store is automatically written to the same directory we currently set via --statedir to track fsfreeze state, and so should be applicable for stable releases where this flag is supported. A follow-up can use this same store for handling fsfreeze state, but that change is cosmetic and left out for now. Signed-off-by: Michael Roth Cc: qemu-stable@nongnu.org * fixed guest_file_handle_add() return value from uint64_t to int64_t --- qga/commands-posix.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'qga/commands-posix.c') diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 7a0202eb2a..1c2aff356a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -129,14 +129,22 @@ static struct { QTAILQ_HEAD(, GuestFileHandle) filehandles; } guest_file_state; -static void guest_file_handle_add(FILE *fh) +static int64_t guest_file_handle_add(FILE *fh, Error **errp) { GuestFileHandle *gfh; + int64_t handle; + + handle = ga_get_fd_handle(ga_state, errp); + if (error_is_set(errp)) { + return 0; + } gfh = g_malloc0(sizeof(GuestFileHandle)); - gfh->id = fileno(fh); + gfh->id = handle; gfh->fh = fh; QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); + + return handle; } static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) @@ -158,7 +166,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E { FILE *fh; int fd; - int64_t ret = -1; + int64_t ret = -1, handle; if (!has_mode) { mode = "r"; @@ -184,9 +192,14 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E return -1; } - guest_file_handle_add(fh); - slog("guest-file-open, handle: %d", fd); - return fd; + handle = guest_file_handle_add(fh, err); + if (error_is_set(err)) { + fclose(fh); + return -1; + } + + slog("guest-file-open, handle: %d", handle); + return handle; } void qmp_guest_file_close(int64_t handle, Error **err) -- cgit v1.2.1