All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.