public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: [PATCH 5/7] VMDK Snapshot Support
Date: Fri, 03 Nov 2006 00:30:38 -0600	[thread overview]
Message-ID: <454AE20E.8010006@cs.utexas.edu> (raw)
In-Reply-To: <454AE007.5070905-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 193 bytes --]

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

[-- Attachment #2: vmdk-snapshot.diff --]
[-- Type: text/x-patch, Size: 8784 bytes --]

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 <uuid/uuid.h>
 #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;
 };
 

[-- Attachment #3: Type: text/plain, Size: 373 bytes --]

-------------------------------------------------------------------------
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

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

  parent reply	other threads:[~2006-11-03  6:30 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-03  6:21 [PATCH 0/7] Split up QEMU patches Anthony Liguori
     [not found] ` <454AE007.5070905-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-03  6:25   ` [PATCH 1/7] Compile fix for usb-linux.c Anthony Liguori
2006-11-03  6:26   ` [PATCH 2/7] APIC save/restore fix Anthony Liguori
2006-11-03  6:27   ` [PATCH 3/7] Timer " Anthony Liguori
2006-11-03  6:29   ` [PATCH 4/7] gdbstub for x86-64 Anthony Liguori
2006-11-03  6:30   ` Anthony Liguori [this message]
2006-11-03  6:31   ` [PATCH 6/7] KVM changes for QEMU Anthony Liguori
2006-11-03  6:35   ` [PATCH 7/7] Allow KVM from a normal QEMU binary Anthony Liguori
     [not found]     ` <454AE323.8090309-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05  9:27       ` Avi Kivity
     [not found]         ` <454DAE74.4030306-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 17:28           ` Anthony Liguori
     [not found]             ` <454E1F40.2070200-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05 17:48               ` Avi Kivity
     [not found]                 ` <454E23EE.7040505-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 18:18                   ` Anthony Liguori
     [not found]                     ` <454E2ADC.1060607-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05 18:29                       ` Avi Kivity
     [not found]                         ` <454E2DA4.8070405-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 19:53                           ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=454AE20E.8010006@cs.utexas.edu \
    --to=aliguori-nzps4cjig2hvqtjrzfazuq@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox