From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anthony Liguori Subject: [PATCH 5/7] VMDK Snapshot Support Date: Fri, 03 Nov 2006 00:30:38 -0600 Message-ID: <454AE20E.8010006@cs.utexas.edu> References: <454AE007.5070905@cs.utexas.edu> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------070001070403010207090006" Return-path: To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org In-Reply-To: <454AE007.5070905-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org Errors-To: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org List-Id: kvm.vger.kernel.org This is a multi-part message in MIME format. --------------070001070403010207090006 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit This is from Avi's original patch. It implements snapshot support for VMDK disk images. It's not directly related to KVM but it's included here for completeness. Regards, Anthony Liguori --------------070001070403010207090006 Content-Type: text/x-patch; name="vmdk-snapshot.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="vmdk-snapshot.diff" diff -r 1e79f1fb1c91 Makefile --- a/Makefile Thu Nov 02 19:04:46 2006 -0600 +++ b/Makefile Thu Nov 02 19:06:29 2006 -0600 @@ -13,7 +13,7 @@ CFLAGS+=-mcpu=ultrasparc CFLAGS+=-mcpu=ultrasparc endif LDFLAGS=-g -LIBS= +LIBS=-luuid DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE TOOLS=qemu-img$(EXESUF) ifdef CONFIG_STATIC diff -r 1e79f1fb1c91 Makefile.target --- a/Makefile.target Thu Nov 02 19:04:46 2006 -0600 +++ b/Makefile.target Thu Nov 02 19:07:05 2006 -0600 @@ -407,7 +407,7 @@ ifndef CONFIG_DARWIN ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS=-lutil -lrt +VL_LIBS=-lutil -lrt -luuid endif endif endif diff -r 1e79f1fb1c91 block-vmdk.c --- a/block-vmdk.c Thu Nov 02 19:04:46 2006 -0600 +++ b/block-vmdk.c Thu Nov 02 19:07:41 2006 -0600 @@ -22,6 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include "vl.h" #include "block_int.h" @@ -89,6 +90,190 @@ static int vmdk_probe(const uint8_t *buf return 0; } +#define SECTOR_SIZE 512 +#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each +#define HEADER_SIZE 512 // first sector of 512 bytes +int vmdk_snapshot_create(BlockDriverState *bs) +{ + int snp_fd, p_fd; + uint32_t p_cid; + char *p_name, *gd_buf, *rgd_buf; + VMDK4Header header; + uint32_t gde_entries, gd_size; + int64_t gd_offset, rgd_offset, capacity, gt_size; + char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE]; + char parent_filename[1024]; + char snapshot_filename[1024]; + uuid_t name; + char *desc_template = + "# Disk DescriptorFile\n" + "version=1\n" + "CID=%x\n" + "parentCID=%x\n" + "createType=\"monolithicSparse\"\n" + "parentFileNameHint=\"%s\"\n" + "\n" + "# Extent description\n" + "RW %lu SPARSE \"%s\"\n" + "\n" + "# The Disk Data Base \n" + "#DDB\n" + "\n"; + + strcpy(parent_filename, bs->filename); + uuid_generate(name); // it should be unique filename + uuid_unparse(name, snapshot_filename); + strcat(snapshot_filename,".vmdk"); + + snp_fd = open(snapshot_filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644); + if (snp_fd < 0) + return -1; + p_fd = open(parent_filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (p_fd < 0) { + close(snp_fd); + return -1; + } + + if (lseek(p_fd, 0x0, SEEK_SET) == -1) + goto fail; + if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) + goto fail; + + /* write the header */ + if (lseek(snp_fd, 0x0, SEEK_SET) == -1) + goto fail; + if (write(snp_fd, hdr, HEADER_SIZE) == -1) + goto fail; + + memset(&header, 0, sizeof(header)); + memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC + + ftruncate(snp_fd, header.grain_offset << 9); + /* the descriptor offset = 0x200 */ + if (lseek(p_fd, 0x200, SEEK_SET) == -1) + goto fail; + if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) + goto fail; + + if ((p_name = strstr(p_desc,"CID")) != 0) { + p_name += sizeof("CID"); + sscanf(p_name,"%x",&p_cid); + } + sprintf(s_desc, desc_template, p_cid, p_cid, parent_filename + , (uint32_t)header.capacity, snapshot_filename); + + bs->parent_cid = p_cid; + + /* write the descriptor */ + if (lseek(snp_fd, 0x200, SEEK_SET) == -1) + goto fail; + if (write(snp_fd, s_desc, strlen(s_desc)) == -1) + goto fail; + + gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table + rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table + capacity = header.capacity * SECTOR_SIZE; // Extent size + /* + * Each GDE span 32M disk, means: + * 512 GTE per GT, each GTE points to grain + */ + gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE; + if (!gt_size) + goto fail; + gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde + gd_size = gde_entries * sizeof(uint32_t); + + /* write RGD */ + rgd_buf = qemu_malloc(gd_size); + if (!rgd_buf) + goto fail; + if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) + goto fail_rgd; + if (read(p_fd, rgd_buf, gd_size) != gd_size) + goto fail_rgd; + if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) + goto fail_rgd; + if (write(snp_fd, rgd_buf, gd_size) == -1) + goto fail_rgd; + qemu_free(rgd_buf); + + /* write GD */ + gd_buf = qemu_malloc(gd_size); + if (!gd_buf) + goto fail_rgd; + if (lseek(p_fd, gd_offset, SEEK_SET) == -1) + goto fail_gd; + if (read(p_fd, gd_buf, gd_size) != gd_size) + goto fail_gd; + if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) + goto fail_gd; + if (write(snp_fd, gd_buf, gd_size) == -1) + goto fail_gd; + qemu_free(gd_buf); + + close(p_fd); + close(snp_fd); + return 0; + + fail_gd: + qemu_free(gd_buf); + fail_rgd: + qemu_free(rgd_buf); + fail: + close(p_fd); + close(snp_fd); + return -1; +} + +static void vmdk_parent_close(BlockDriverState *bs) +{ + if (bs->bs_par_table) + bdrv_close(bs->bs_par_table); +} + +static int vmdk_parent_open(BlockDriverState *bs, int fd) +{ + char *p_name; + char desc[DESC_SIZE]; + static int idx=0; + + /* the descriptor offset = 0x200 */ + if (lseek(fd, 0x200, SEEK_SET) == -1) + return -1; + if (read(fd, desc, DESC_SIZE) != DESC_SIZE) + return -1; + + if ((p_name = strstr(desc,"parentFileNameHint")) != 0) { + char *end_name, *tmp_name; + char name[256], buf[128]; + int name_size; + + p_name += sizeof("parentFileNameHint") + 1; + if ((end_name = strchr(p_name,'\"')) == 0) + return -1; + + bs->parent_img_name = qemu_mallocz(end_name - p_name + 2); + strncpy(bs->parent_img_name, p_name, end_name - p_name); + + tmp_name = strstr(bs->device_name,"_QEMU"); + name_size = tmp_name ? (tmp_name - bs->device_name) : sizeof(bs->device_name); + strncpy(name,bs->device_name,name_size); + sprintf(buf, "_QEMU_%d", ++idx); + + bs->bs_par_table = bdrv_new(strcat(name, buf)); + if (!bs->bs_par_table) { + failure: + bdrv_close(bs); + return -1; + } + + if (bdrv_open(bs->bs_par_table, bs->parent_img_name, 0) < 0) + goto failure; + } + + return 0; +} + static int vmdk_open(BlockDriverState *bs, const char *filename) { BDRVVmdkState *s = bs->opaque; @@ -133,6 +318,10 @@ static int vmdk_open(BlockDriverState *b / s->l1_entry_sectors; s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; + + // try to open parent images, if exist + if (vmdk_parent_open(bs, fd) != 0) + goto fail; } else { goto fail; } @@ -275,11 +464,17 @@ static int vmdk_read(BlockDriverState *b if (n > nb_sectors) n = nb_sectors; if (!cluster_offset) { - memset(buf, 0, 512 * n); + // try to read from parent image, if exist + if (bs->bs_par_table) { + if (vmdk_read(bs->bs_par_table, sector_num, buf, nb_sectors) == -1) + return -1; + } else { + memset(buf, 0, 512 * n); + } } else { lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); ret = read(s->fd, buf, n * 512); - if (ret != n * 512) + if (ret != n * 512) return -1; } nb_sectors -= n; @@ -421,9 +616,12 @@ static void vmdk_close(BlockDriverState static void vmdk_close(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; + qemu_free(s->l1_table); qemu_free(s->l2_cache); close(s->fd); + // try to close parent image, if exist + vmdk_parent_close(bs); } static void vmdk_flush(BlockDriverState *bs) diff -r 1e79f1fb1c91 block_int.h --- a/block_int.h Thu Nov 02 19:04:46 2006 -0600 +++ b/block_int.h Thu Nov 02 19:06:21 2006 -0600 @@ -67,12 +67,17 @@ struct BlockDriverState { int is_temporary; BlockDriverState *backing_hd; + + BlockDriverState *bs_par_table; + char *parent_img_name; + uint32_t parent_cid; + uint32_t cid; /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ int cyls, heads, secs, translation; int type; - char device_name[32]; + char device_name[256]; BlockDriverState *next; }; --------------070001070403010207090006 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 --------------070001070403010207090006 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kvm-devel mailing list kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/kvm-devel --------------070001070403010207090006--