From 49adae7dfd478b6befd2ce46322886ff731cd0f5 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 14 Sep 2012 11:09:45 +0200 Subject: [PATCH] snapshot_start: use bdrv instead of file So that we can store state on any valid qemu block device. qemu-img: return success for non-existing snapshots on snapshot removal --- Makefile | 2 +- debian/changelog | 8 +- .../fix-qemu-img-snapshot-removal.patch | 15 ++ debian/patches/internal-snapshot.patch | 64 ++++- debian/patches/series | 1 + debian/rules | 2 +- new/qemu-file.h | 239 ++++++++++++++++++ 7 files changed, 323 insertions(+), 8 deletions(-) create mode 100644 debian/patches/fix-qemu-img-snapshot-removal.patch create mode 100644 new/qemu-file.h diff --git a/Makefile b/Makefile index b803664..3b54169 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ RELEASE=2.2 # also update debian/changelog KVMVER=1.2 -KVMPKGREL=5 +KVMPKGREL=6 KVMPACKAGE=pve-qemu-kvm KVMDIR=qemu-kvm diff --git a/debian/changelog b/debian/changelog index e9b3310..39d032f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,13 @@ +pve-qemu-kvm (1.2-6) unstable; urgency=low + + * qemu-img: return success for non-existing snapshots on snapshot removal + + -- Proxmox Support Team Fri, 14 Sep 2012 11:09:09 +0200 + pve-qemu-kvm (1.2-5) unstable; urgency=low * update to 1.2.0 - + -- Proxmox Support Team Fri, 07 Sep 2012 07:40:06 +0200 pve-qemu-kvm (1.2-4) unstable; urgency=low diff --git a/debian/patches/fix-qemu-img-snapshot-removal.patch b/debian/patches/fix-qemu-img-snapshot-removal.patch new file mode 100644 index 0000000..14a2eaa --- /dev/null +++ b/debian/patches/fix-qemu-img-snapshot-removal.patch @@ -0,0 +1,15 @@ +Index: new/qemu-img.c +=================================================================== +--- new.orig/qemu-img.c 2012-09-14 11:03:04.000000000 +0200 ++++ new/qemu-img.c 2012-09-14 11:13:39.000000000 +0200 +@@ -1288,7 +1288,9 @@ + error_report("Could not delete snapshot '%s': %d (%s)", + snapshot_name, ret, strerror(-ret)); + } +- break; ++ // return success if snapshot does not exists ++ if (ret == -ENOENT) ret = 0; ++ break; + } + + /* Cleanup */ diff --git a/debian/patches/internal-snapshot.patch b/debian/patches/internal-snapshot.patch index bf1fdf6..f88af28 100644 --- a/debian/patches/internal-snapshot.patch +++ b/debian/patches/internal-snapshot.patch @@ -18,8 +18,8 @@ Index: new/qapi-schema.json Index: new/qmp.c =================================================================== --- new.orig/qmp.c 2012-09-07 07:41:45.000000000 +0200 -+++ new/qmp.c 2012-09-13 09:22:06.000000000 +0200 -@@ -479,3 +479,191 @@ ++++ new/qmp.c 2012-09-14 14:06:56.000000000 +0200 +@@ -479,3 +479,224 @@ return arch_query_cpu_definitions(errp); } @@ -28,8 +28,23 @@ Index: new/qmp.c + int saved_vm_running; +} snap_state; + ++static int block_put_buffer(void *opaque, const uint8_t *buf, ++ int64_t pos, int size) ++{ ++ bdrv_pwrite(opaque, pos, buf, size); ++ return size; ++} ++ ++static int bdrv_fclose(void *opaque) ++{ ++ return bdrv_flush(opaque); ++} ++ +void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp) +{ ++ BlockDriverState *bs = NULL; ++ BlockDriver *drv = NULL; ++ int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR; + QEMUFile *f; + int ret; + @@ -48,19 +63,35 @@ Index: new/qmp.c + if (!has_statefile) + return; + -+ f = qemu_fopen(statefile, "wb"); ++ /* Open the image */ ++ bs = bdrv_new("vmstate"); ++ ret = bdrv_open(bs, statefile, bdrv_oflags, drv); ++ if (ret < 0) { ++ error_set(errp, QERR_OPEN_FILE_FAILED, statefile); ++ goto restart; ++ } ++ ++ f = qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, ++ NULL, NULL, NULL); + if (!f) { + error_set(errp, QERR_OPEN_FILE_FAILED, statefile); + goto restart; + } + + ret = qemu_savevm_state(f); ++ ++ bdrv_truncate(bs, qemu_ftell(f)); // ignore errors ++ + qemu_fclose(f); ++ + if (ret < 0) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "Error %d while writing VM state\n", ret); -+ goto restart; ++ goto restart; + } ++end: ++ if (bs) ++ bdrv_delete(bs); + + return; + @@ -71,6 +102,8 @@ Index: new/qmp.c + if (snap_state.saved_vm_running) { + vm_start(); + } ++ ++ goto end; +} + +void qmp_snapshot_end(Error **errp) @@ -345,7 +378,16 @@ Index: new/hmp-commands.hx Index: new/savevm.c =================================================================== --- new.orig/savevm.c 2012-09-07 07:41:45.000000000 +0200 -+++ new/savevm.c 2012-09-13 09:22:06.000000000 +0200 ++++ new/savevm.c 2012-09-14 11:32:17.000000000 +0200 +@@ -404,7 +404,7 @@ + return bdrv_flush(opaque); + } + +-static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) ++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) + { + if (is_writable) + return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, @@ -1724,7 +1724,7 @@ } } @@ -367,3 +409,15 @@ Index: new/sysemu.h int qemu_loadvm_state(QEMUFile *f); /* SLIRP */ +Index: new/qemu-file.h +=================================================================== +--- new.orig/qemu-file.h 2012-09-14 11:51:31.000000000 +0200 ++++ new/qemu-file.h 2012-09-14 11:51:47.000000000 +0200 +@@ -68,6 +68,7 @@ + QEMUFile *qemu_fopen(const char *filename, const char *mode); + QEMUFile *qemu_fdopen(int fd, const char *mode); + QEMUFile *qemu_fopen_socket(int fd); ++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable); + QEMUFile *qemu_popen(FILE *popen_file, const char *mode); + QEMUFile *qemu_popen_cmd(const char *command, const char *mode); + int qemu_stdio_fd(QEMUFile *f); diff --git a/debian/patches/series b/debian/patches/series index e605ce2..e1f6444 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -11,3 +11,4 @@ ahci-properly-reset-pxcmd.patch #modify-qapi-schema.patch #implement-snapshot-drive.patch internal-snapshot.patch +fix-qemu-img-snapshot-removal.patch diff --git a/debian/rules b/debian/rules index 2604b8d..d5d132d 100755 --- a/debian/rules +++ b/debian/rules @@ -41,7 +41,7 @@ build-stamp: config.status dh_testdir # Add here commands to compile the package. - $(MAKE) V=1 + $(MAKE) #docbook-to-man debian/kvm.sgml > kvm.1 diff --git a/new/qemu-file.h b/new/qemu-file.h new file mode 100644 index 0000000..f719b02 --- /dev/null +++ b/new/qemu-file.h @@ -0,0 +1,239 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_FILE_H +#define QEMU_FILE_H 1 + +/* This function writes a chunk of data to a file at the given position. + * The pos argument can be ignored if the file is only being used for + * streaming. The handler should try to write all of the data it can. + */ +typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, + int64_t pos, int size); + +/* Read a chunk of data from a file at the given position. The pos argument + * can be ignored if the file is only be used for streaming. The number of + * bytes actually read should be returned. + */ +typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, + int64_t pos, int size); + +/* Close a file + * + * Return negative error number on error, 0 or positive value on success. + * + * The meaning of return value on success depends on the specific back-end being + * used. + */ +typedef int (QEMUFileCloseFunc)(void *opaque); + +/* Called to determine if the file has exceeded its bandwidth allocation. The + * bandwidth capping is a soft limit, not a hard limit. + */ +typedef int (QEMUFileRateLimit)(void *opaque); + +/* Called to change the current bandwidth allocation. This function must return + * the new actual bandwidth. It should be new_rate if everything goes ok, and + * the old rate otherwise + */ +typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate); +typedef int64_t (QEMUFileGetRateLimit)(void *opaque); + +QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, + QEMUFileGetBufferFunc *get_buffer, + QEMUFileCloseFunc *close, + QEMUFileRateLimit *rate_limit, + QEMUFileSetRateLimit *set_rate_limit, + QEMUFileGetRateLimit *get_rate_limit); +QEMUFile *qemu_fopen(const char *filename, const char *mode); +QEMUFile *qemu_fdopen(int fd, const char *mode); +QEMUFile *qemu_fopen_socket(int fd); +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable); +QEMUFile *qemu_popen(FILE *popen_file, const char *mode); +QEMUFile *qemu_popen_cmd(const char *command, const char *mode); +int qemu_stdio_fd(QEMUFile *f); +void qemu_fflush(QEMUFile *f); +int qemu_fclose(QEMUFile *f); +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_byte(QEMUFile *f, int v); + +static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, (int)v); +} + +#define qemu_put_sbyte qemu_put_byte + +void qemu_put_be16(QEMUFile *f, unsigned int v); +void qemu_put_be32(QEMUFile *f, unsigned int v); +void qemu_put_be64(QEMUFile *f, uint64_t v); +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +int qemu_get_byte(QEMUFile *f); + +static inline unsigned int qemu_get_ubyte(QEMUFile *f) +{ + return (unsigned int)qemu_get_byte(f); +} + +#define qemu_get_sbyte qemu_get_byte + +unsigned int qemu_get_be16(QEMUFile *f); +unsigned int qemu_get_be32(QEMUFile *f); +uint64_t qemu_get_be64(QEMUFile *f); + +int qemu_file_rate_limit(QEMUFile *f); +int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); +int64_t qemu_file_get_rate_limit(QEMUFile *f); +int qemu_file_get_error(QEMUFile *f); +void qemu_file_set_error(QEMUFile *f, int error); + +/* Try to send any outstanding data. This function is useful when output is + * halted due to rate limiting or EAGAIN errors occur as it can be used to + * resume output. */ +void qemu_file_put_notify(QEMUFile *f); + +static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) +{ + qemu_put_be64(f, *pv); +} + +static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) +{ + qemu_put_be32(f, *pv); +} + +static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) +{ + qemu_put_be16(f, *pv); +} + +static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) +{ + qemu_put_byte(f, *pv); +} + +static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) +{ + *pv = qemu_get_be64(f); +} + +static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) +{ + *pv = qemu_get_be32(f); +} + +static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) +{ + *pv = qemu_get_be16(f); +} + +static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) +{ + *pv = qemu_get_byte(f); +} + +// Signed versions for type safety +static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size) +{ + qemu_put_buffer(f, (const uint8_t *)buf, size); +} + +static inline void qemu_put_sbe16(QEMUFile *f, int v) +{ + qemu_put_be16(f, (unsigned int)v); +} + +static inline void qemu_put_sbe32(QEMUFile *f, int v) +{ + qemu_put_be32(f, (unsigned int)v); +} + +static inline void qemu_put_sbe64(QEMUFile *f, int64_t v) +{ + qemu_put_be64(f, (uint64_t)v); +} + +static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size) +{ + return qemu_get_buffer(f, (uint8_t *)buf, size); +} + +static inline int qemu_get_sbe16(QEMUFile *f) +{ + return (int)qemu_get_be16(f); +} + +static inline int qemu_get_sbe32(QEMUFile *f) +{ + return (int)qemu_get_be32(f); +} + +static inline int64_t qemu_get_sbe64(QEMUFile *f) +{ + return (int64_t)qemu_get_be64(f); +} + +static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv) +{ + qemu_put_8s(f, (const uint8_t *)pv); +} + +static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv) +{ + qemu_put_be16s(f, (const uint16_t *)pv); +} + +static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv) +{ + qemu_put_be32s(f, (const uint32_t *)pv); +} + +static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv) +{ + qemu_put_be64s(f, (const uint64_t *)pv); +} + +static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv) +{ + qemu_get_8s(f, (uint8_t *)pv); +} + +static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv) +{ + qemu_get_be16s(f, (uint16_t *)pv); +} + +static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv) +{ + qemu_get_be32s(f, (uint32_t *)pv); +} + +static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) +{ + qemu_get_be64s(f, (uint64_t *)pv); +} + +int64_t qemu_ftell(QEMUFile *f); +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); + +#endif -- 2.39.2