WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Add sparseness flag to qcow-create.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Add sparseness flag to qcow-create.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 15 Dec 2006 10:50:26 +0000
Delivery-date: Fri, 15 Dec 2006 02:50:59 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Julian Chesterfield <julian@xxxxxxxxxxxxx>
# Node ID a05fefbeb19f065d0ed9d5b73d7572e44326fd79
# Parent  bd102b60c43bc4be403117b27ad41eeecf4c857d
Add sparseness flag to qcow-create.

For environments where space must be guaranteed in advance
use the -p flag to remove sparseness from the qcow file.

Signed-off-by: Julian Chesterfield <julian@xxxxxxxxxxxxx>
---
 tools/blktap/drivers/block-qcow.c  |  120 ++++++++++++++++++++++++++-----------
 tools/blktap/drivers/qcow-create.c |   71 ++++++++++++++++-----
 2 files changed, 141 insertions(+), 50 deletions(-)

diff -r bd102b60c43b -r a05fefbeb19f tools/blktap/drivers/block-qcow.c
--- a/tools/blktap/drivers/block-qcow.c Thu Dec 14 18:24:41 2006 +0000
+++ b/tools/blktap/drivers/block-qcow.c Thu Dec 14 20:23:07 2006 +0000
@@ -74,8 +74,9 @@ struct pending_aio {
 #define XEN_MAGIC  (('X' << 24) | ('E' << 16) | ('N' << 8) | 0xfb)
 #define QCOW_VERSION 1
 
-#define QCOW_CRYPT_NONE 0
-#define QCOW_CRYPT_AES  1
+#define QCOW_CRYPT_NONE 0x00
+#define QCOW_CRYPT_AES  0x01
+#define QCOW_SPARSE_FILE 0x02
 
 #define QCOW_OFLAG_COMPRESSED (1LL << 63)
 
@@ -101,6 +102,7 @@ typedef struct QCowHeader_ext {
         uint32_t xmagic;
         uint32_t cksum;
         uint32_t min_cluster_alloc;
+        uint32_t flags;
 } QCowHeader_ext;
 
 #define L2_CACHE_SIZE 16  /*Fixed allocation in Qemu*/
@@ -119,6 +121,7 @@ struct tdqcow_state {
        int cluster_alloc;             /*Blktap fix for allocating full 
                                        *extents*/
        int min_cluster_alloc;         /*Blktap historical extent alloc*/
+       int sparse;                    /*Indicates whether to preserve 
sparseness*/
        int l2_bits;                   /*Size of L2 table entry*/
        int l2_size;                   /*Full table size*/
        int l1_size;                   /*L1 table size*/
@@ -413,6 +416,37 @@ static void encrypt_sectors(struct tdqco
        }
 }
 
+static int qtruncate(int fd, off_t length, int sparse)
+{
+       int current, ret, i; 
+       int sectors = length/DEFAULT_SECTOR_SIZE;
+       struct stat st;
+       char buf[DEFAULT_SECTOR_SIZE];
+
+       /* If length is greater than the current file len
+        * we synchronously write zeroes to the end of the 
+        * file, otherwise we truncate the length down
+        */
+       memset(buf, 0x00, DEFAULT_SECTOR_SIZE);
+       ret = fstat(fd, &st);
+       if((ret == -1) || S_ISBLK(st.st_mode))
+               return -1;
+
+       if(st.st_size < length) {
+               /*We are extending the file*/
+               lseek(fd, 0, SEEK_END);
+               for (i = 0; i < sectors; i++ ) {
+                       ret = write(fd, buf, DEFAULT_SECTOR_SIZE);
+                       if (ret != DEFAULT_SECTOR_SIZE)
+                               return -1;
+               }
+               
+       } else if(sparse && (st.st_size > length))
+               ftruncate(fd, length);
+
+       return 1;
+}
+
 
 /* 'allocate' is:
  *
@@ -463,8 +497,8 @@ static uint64_t get_cluster_offset(struc
                
                /*Truncate file for L2 table 
                 *(initialised to zero in case we crash)*/
-               ftruncate(s->fd, l2_offset + (s->l2_size * sizeof(uint64_t)));
-               s->fd_end += (s->l2_size * sizeof(uint64_t));
+               qtruncate(s->fd, l2_offset + (s->l2_size * sizeof(uint64_t)), 
s->sparse);
+               s->fd_end = l2_offset + (s->l2_size * sizeof(uint64_t));
 
                /*Update the L1 table entry on disk
                  * (for O_DIRECT we write 4KByte blocks)*/
@@ -483,7 +517,7 @@ static uint64_t get_cluster_offset(struc
                 */
                lseek(s->fd, s->l1_table_offset + (l1_sector << 12), SEEK_SET);
                if (write(s->fd, tmp_ptr, 4096) != 4096)
-                       return 0;
+                       return 0;
                free(tmp_ptr);
 
                new_l2_table = 1;
@@ -530,8 +564,8 @@ cache_miss:
                                (s->l2_size * sizeof(uint64_t));
                        cluster_offset = (cluster_offset + s->cluster_size - 1)
                                & ~(s->cluster_size - 1);
-                       ftruncate(s->fd, cluster_offset + 
-                                 (s->cluster_size * s->l2_size));
+                       qtruncate(s->fd, cluster_offset + 
+                                 (s->cluster_size * s->l2_size), s->sparse);
                        s->fd_end = cluster_offset + 
                                (s->cluster_size * s->l2_size);
                        for (i = 0; i < s->l2_size; i++) {
@@ -542,7 +576,7 @@ cache_miss:
 
                lseek(s->fd, l2_offset, SEEK_SET);
                if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
-                   s->l2_size * sizeof(uint64_t))
+                  s->l2_size * sizeof(uint64_t))
                        return 0;
        } else {
                lseek(s->fd, l2_offset, SEEK_SET);
@@ -573,7 +607,7 @@ found:
                           overwritten */
                        if (decompress_cluster(s, cluster_offset) < 0)
                                return 0;
-                       cluster_offset = lseek(s->fd, 0, SEEK_END);
+                       cluster_offset = lseek(s->fd, s->fd_end, SEEK_SET);
                        cluster_offset = (cluster_offset + s->cluster_size - 1)
                                & ~(s->cluster_size - 1);
                        /* write the cluster content - not asynchronous */
@@ -583,14 +617,15 @@ found:
                            return -1;
                } else {
                        /* allocate a new cluster */
-                       cluster_offset = lseek(s->fd, 0, SEEK_END);
+                       cluster_offset = lseek(s->fd, s->fd_end, SEEK_SET);
                        if (allocate == 1) {
                                /* round to cluster size */
                                cluster_offset = 
                                        (cluster_offset + s->cluster_size - 1) 
                                        & ~(s->cluster_size - 1);
-                               ftruncate(s->fd, cluster_offset + 
-                                         s->cluster_size);
+                               qtruncate(s->fd, cluster_offset + 
+                                         s->cluster_size, s->sparse);
+                               s->fd_end = (cluster_offset + s->cluster_size);
                                /* if encrypted, we must initialize the cluster
                                   content which won't be written */
                                if (s->crypt_method && 
@@ -633,9 +668,9 @@ found:
                        DPRINTF("ERROR allocating memory for L1 table\n");
                }
                memcpy(tmp_ptr2, l2_ptr, 4096);
-               aio_lock(s, offset >> 9);
-               async_write(s, s->fd, 4096, l2_offset + (l2_sector << 12), 
-                           tmp_ptr2, 0, -2, offset >> 9, 0, NULL);
+               lseek(s->fd, l2_offset + (l2_sector << 12), SEEK_SET);
+               write(s->fd, tmp_ptr2, 4096);
+               free(tmp_ptr2);
        }
        return cluster_offset;
 }
@@ -733,6 +768,7 @@ int tdqcow_open (struct td_state *bs, co
        QCowHeader *header;
        QCowHeader_ext *exthdr;
        uint32_t cksum;
+       uint64_t final_cluster = 0;
 
        DPRINTF("QCOW: Opening %s\n",name);
        /* set up a pipe so that we can hand back a poll fd that won't fire.*/
@@ -766,7 +802,7 @@ int tdqcow_open (struct td_state *bs, co
        be64_to_cpus(&header->size);
        be32_to_cpus(&header->crypt_method);
        be64_to_cpus(&header->l1_table_offset);
-   
+
        if (header->magic != QCOW_MAGIC || header->version > QCOW_VERSION)
                goto fail;
        if (header->size <= 1 || header->cluster_bits < 9)
@@ -798,6 +834,7 @@ int tdqcow_open (struct td_state *bs, co
        }
        ret = posix_memalign((void **)&s->l1_table, 4096, l1_table_size);
        if (ret != 0) goto fail;
+
        memset(s->l1_table, 0x00, l1_table_size);
 
        DPRINTF("L1 Table offset detected: %llu, size %d (%d)\n",
@@ -808,10 +845,13 @@ int tdqcow_open (struct td_state *bs, co
        lseek(fd, s->l1_table_offset, SEEK_SET);
        if (read(fd, s->l1_table, l1_table_size) != l1_table_size)
                goto fail;
-/*     for(i = 0;i < s->l1_size; i++) {
+
+       for(i = 0;i < s->l1_size; i++) {
                //be64_to_cpus(&s->l1_table[i]);
-               DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]);
-               }*/
+               //DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]);
+               if (s->l1_table[i] > final_cluster)
+                       final_cluster = s->l1_table[i];
+       }
 
        /* alloc L2 cache */
        size = s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t);
@@ -870,10 +910,14 @@ int tdqcow_open (struct td_state *bs, co
                /*Finally check the L1 table cksum*/
                be32_to_cpus(&exthdr->cksum);
                cksum = gen_cksum((char *)s->l1_table, s->l1_size * 
sizeof(uint64_t));
-               if(exthdr->cksum != cksum)
+               if(exthdr->cksum != cksum) {
                        goto end_xenhdr;
+               }
                        
                be32_to_cpus(&exthdr->min_cluster_alloc);
+               be32_to_cpus(&exthdr->flags);
+               if (exthdr->flags & QCOW_SPARSE_FILE)
+                       s->sparse = 1;
                s->min_cluster_alloc = exthdr->min_cluster_alloc; 
        }
 
@@ -882,7 +926,8 @@ int tdqcow_open (struct td_state *bs, co
                DPRINTF("Unable to initialise AIO state\n");
                goto fail;
        }
-       s->fd_end = lseek(s->fd, 0, SEEK_END);
+       s->fd_end = (final_cluster == 0 ? (s->l1_table_offset + l1_table_size) 
: 
+                               (final_cluster + s->cluster_size));
 
        return 0;
        
@@ -1172,7 +1217,7 @@ int qcow_create(const char *filename, ui
        QCowHeader header;
        QCowHeader_ext exthdr;
        char backing_filename[1024], *ptr;
-       uint64_t tmp, size;
+       uint64_t tmp, size, total_length;
        struct stat st;
 
        DPRINTF("Qcow_create: size %llu\n",(long long unsigned)total_size);
@@ -1260,7 +1305,7 @@ int qcow_create(const char *filename, ui
        DPRINTF("L1 Table offset: %d, size %d\n",
                header_size,
                (int)(l1_size * sizeof(uint64_t)));
-       if (flags) {
+       if (flags & QCOW_CRYPT_AES) {
                header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
        } else {
                header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
@@ -1270,8 +1315,26 @@ int qcow_create(const char *filename, ui
        exthdr.cksum = cpu_to_be32(gen_cksum(ptr, l1_size * sizeof(uint64_t)));
        printf("Created cksum: %d\n",exthdr.cksum);
        free(ptr);
+
+       /*adjust file length to 4 KByte boundary*/
+       length = header_size + l1_size * sizeof(uint64_t);
+       if (length % 4096 > 0) {
+               length = ((length >> 12) + 1) << 12;
+               qtruncate(fd, length, 0);
+               DPRINTF("Adjusted filelength to %d for 4 "
+                       "Kbyte alignment\n",length);
+       }
+
+       if (!(flags & QCOW_SPARSE_FILE)) {
+               /*Filesize is length +  l1_size * (1 << s->l2_bits) + 
(size*512)*/
+               total_length = length + (l1_size * (1 << 9)) + (size * 512);
+               qtruncate(fd, total_length, 0);
+               printf("File truncated to length %llu\n",total_length);
+       }
+       exthdr.flags = cpu_to_be32(flags);
        
        /* write all the data */
+       lseek(fd, 0, SEEK_SET);
        ret += write(fd, &header, sizeof(header));
        ret += write(fd, &exthdr, sizeof(exthdr));
        if (backing_file) {
@@ -1283,15 +1346,6 @@ int qcow_create(const char *filename, ui
                ret += write(fd, &tmp, sizeof(tmp));
        }
 
-       /*adjust file length to 4 KByte boundary*/
-       length = header_size + l1_size * sizeof(uint64_t);
-       if (length % 4096 > 0) {
-               length = ((length >> 12) + 1) << 12;
-               ftruncate(fd, length);
-               DPRINTF("Adjusted filelength to %d for 4 "
-                       "Kbyte alignment\n",length);
-       }
-
        close(fd);
 
        return 0;
@@ -1306,7 +1360,7 @@ int qcow_make_empty(struct td_state *bs)
        lseek(s->fd, s->l1_table_offset, SEEK_SET);
        if (write(s->fd, s->l1_table, l1_length) < 0)
                return -1;
-       ftruncate(s->fd, s->l1_table_offset + l1_length);
+       qtruncate(s->fd, s->l1_table_offset + l1_length, s->sparse);
 
        memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
        memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
diff -r bd102b60c43b -r a05fefbeb19f tools/blktap/drivers/qcow-create.c
--- a/tools/blktap/drivers/qcow-create.c        Thu Dec 14 18:24:41 2006 +0000
+++ b/tools/blktap/drivers/qcow-create.c        Thu Dec 14 20:23:07 2006 +0000
@@ -47,32 +47,69 @@
 #define DFPRINTF(_f, _a...) ((void)0)
 #endif
 
+#define QCOW_NONSPARSE_FILE 0x00
+#define QCOW_SPARSE_FILE 0x02
+#define MAX_NAME_LEN 1000
+
+void help(void)
+{
+       fprintf(stderr, "Qcow-utils: v1.0.0\n");
+       fprintf(stderr, 
+               "usage: qcow-create [-h help] [-p reserve] <SIZE(MB)> 
<FILENAME> "
+               "[<BACKING_FILENAME>]\n"); 
+       exit(-1);
+}
 
 int main(int argc, char *argv[])
 {
-       int ret = -1;
+       int ret = -1, c, backed = 0;
+       int flags =  QCOW_SPARSE_FILE;
        uint64_t size;
+       char filename[MAX_NAME_LEN], bfilename[MAX_NAME_LEN];
 
-       if ( (argc < 3) || (argc > 4) ) {
-               fprintf(stderr, "Qcow-utils: v1.0.0\n");
-               fprintf(stderr, 
-                       "usage: %s <SIZE(MB)> <FILENAME> "
-                       "[<BACKING_FILENAME>]\n", 
-                       argv[0]);
+        for(;;) {
+                c = getopt(argc, argv, "hp");
+                if (c == -1)
+                        break;
+                switch(c) {
+                case 'h':
+                        help();
+                        exit(0);
+                        break;
+                case 'p':
+                       flags = QCOW_NONSPARSE_FILE;
+                       break;
+               }
+       }
+
+       printf("Optind %d, argc %d\n", optind, argc);
+       if ( !(optind == (argc - 2) || optind == (argc - 3)) )
+               help();
+
+       size = atoi(argv[optind++]);
+       size = size << 20;
+
+       if (snprintf(filename, MAX_NAME_LEN, "%s",argv[optind++]) >=
+               MAX_NAME_LEN) {
+               fprintf(stderr,"Device name too long\n");
                exit(-1);
        }
 
-       size = atoi(argv[1]);
-       size = size << 20;
-       DFPRINTF("Creating file size %llu\n",(long long unsigned)size);
-       switch(argc) {
-       case 3: 
-               ret = qcow_create(argv[2],size,NULL,0);
-               break;
-       case 4:
-               ret = qcow_create(argv[2],size,argv[3],0);
-               break;          
+       if (optind != argc) {
+               backed = 1;
+               if (snprintf(bfilename, MAX_NAME_LEN, "%s",argv[optind++]) >=
+                       MAX_NAME_LEN) {
+                       fprintf(stderr,"Device name too long\n");
+                       exit(-1);
+               }
        }
+
+       DFPRINTF("Creating file size %llu, name %s\n",(long long unsigned)size, 
filename);
+       if (!backed)
+               ret = qcow_create(filename,size,NULL,flags);
+       else
+               ret = qcow_create(filename,size,bfilename,flags);
+
        if (ret < 0) DPRINTF("Unable to create QCOW file\n");
        else DPRINTF("QCOW file successfully created\n");
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Add sparseness flag to qcow-create., Xen patchbot-unstable <=