qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator
@ 2014-08-11 11:55 Maria Kustova
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer Maria Kustova
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Maria Kustova @ 2014-08-11 11:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, Maria Kustova, stefanha

This patch series adds support of refcount tables and blocks to the qcow2 image
generator.

This patch series was created for the 'block-next' branch and based on the next
series:
         [PATCH V3] layout: Reduce number of generator functions in __init__

Maria Kustova (3):
  docs: List all image elements currently supported by the fuzzer
  fuzz: Add fuzzing functions for entries of refcount table and blocks
  layout: Add generators for refcount tbles and blocks

 docs/image-fuzzer.txt              |   3 +-
 tests/image-fuzzer/qcow2/fuzz.py   |  16 ++++-
 tests/image-fuzzer/qcow2/layout.py | 136 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 152 insertions(+), 3 deletions(-)

-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer
  2014-08-11 11:55 [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Maria Kustova
@ 2014-08-11 11:55 ` Maria Kustova
  2014-08-19  7:16   ` Fam Zheng
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks Maria Kustova
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Maria Kustova @ 2014-08-11 11:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, Maria Kustova, stefanha

Signed-off-by: Maria Kustova <maria.k@catit.be>
---
 docs/image-fuzzer.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/image-fuzzer.txt b/docs/image-fuzzer.txt
index 0d0005d..f707269 100644
--- a/docs/image-fuzzer.txt
+++ b/docs/image-fuzzer.txt
@@ -125,7 +125,8 @@ If a fuzzer configuration is specified, then it has the next interpretation:
     will be always fuzzed for every test. This case is useful for regression
     testing.
 
-For now only header fields, header extensions and L1/L2 tables are generated.
+The generator can create header fields, header extensions, L1/L2 tables and
+refcount blocks and table.
 
 Module interfaces
 -----------------
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks
  2014-08-11 11:55 [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Maria Kustova
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer Maria Kustova
@ 2014-08-11 11:55 ` Maria Kustova
  2014-08-19  7:36   ` Fam Zheng
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles " Maria Kustova
  2014-08-19 10:31 ` [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Stefan Hajnoczi
  3 siblings, 1 reply; 9+ messages in thread
From: Maria Kustova @ 2014-08-11 11:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, Maria Kustova, stefanha

Signed-off-by: Maria Kustova <maria.k@catit.be>
---
 tests/image-fuzzer/qcow2/fuzz.py | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py
index 57527f9..5852b4d 100644
--- a/tests/image-fuzzer/qcow2/fuzz.py
+++ b/tests/image-fuzzer/qcow2/fuzz.py
@@ -18,8 +18,8 @@
 
 import random
 
-
 UINT8 = 0xff
+UINT16 = 0xffff
 UINT32 = 0xffffffff
 UINT64 = 0xffffffffffffffff
 # Most significant bit orders
@@ -28,6 +28,8 @@ UINT64_M = 63
 # Fuzz vectors
 UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1,
            UINT8]
+UINT16_V = [0, 0x100, 0x1000, UINT16/4, UINT16/2 - 1, UINT16/2, UINT16/2 + 1,
+            UINT16 - 1, UINT16]
 UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1,
             UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32]
 UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4,
@@ -353,3 +355,15 @@ def l2_entry(current):
     value = offset + (is_cow << UINT64_M) + \
             (is_compressed << UINT64_M - 1) + is_zero
     return value
+
+
+def refcount_table_entry(current):
+    """Fuzz an entry of the refcount table."""
+    constraints = UINT64_V
+    return selector(current, constraints)
+
+
+def refcount_block_entry(current):
+    """Fuzz an entry of a refcount block."""
+    constraints = UINT16_V
+    return selector(current, constraints)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles and blocks
  2014-08-11 11:55 [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Maria Kustova
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer Maria Kustova
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks Maria Kustova
@ 2014-08-11 11:55 ` Maria Kustova
  2014-08-19  9:36   ` Fam Zheng
  2014-08-19 10:31 ` [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Stefan Hajnoczi
  3 siblings, 1 reply; 9+ messages in thread
From: Maria Kustova @ 2014-08-11 11:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, Maria Kustova, stefanha

Refcount structures are placed in clusters randomly selected from all not
allocated host clusters.

Signed-off-by: Maria Kustova <maria.k@catit.be>
---
 tests/image-fuzzer/qcow2/layout.py | 136 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 1 deletion(-)

diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py
index 730c771..2239789 100644
--- a/tests/image-fuzzer/qcow2/layout.py
+++ b/tests/image-fuzzer/qcow2/layout.py
@@ -102,6 +102,8 @@ class Image(object):
         self.end_of_extension_area = FieldsList()
         self.l2_tables = FieldsList()
         self.l1_table = FieldsList()
+        self.refcount_table = FieldsList()
+        self.refcount_blocks = FieldsList()
         self.ext_offset = 0
         self.create_header(cluster_bits, backing_file_name)
         self.set_backing_file_name(backing_file_name)
@@ -113,7 +115,8 @@ class Image(object):
     def __iter__(self):
         return chain(self.header, self.backing_file_format,
                      self.feature_name_table, self.end_of_extension_area,
-                     self.backing_file_name, self.l1_table, self.l2_tables)
+                     self.backing_file_name, self.l1_table, self.l2_tables,
+                     self.refcount_table, self.refcount_blocks)
 
     def create_header(self, cluster_bits, backing_file_name=None):
         """Generate a random valid header."""
@@ -330,6 +333,136 @@ class Image(object):
                                                 float(self.cluster_size**2)))
         self.header['l1_table_offset'][0].value = l1_offset
 
+    def create_refcount_structures(self):
+        """Generate random refcount blocks and refcount table."""
+        def allocate_rfc_blocks(data, size):
+            """Return indices of clusters allocated for recount blocks."""
+            cluster_ids = set()
+            diff = block_ids = set([x / size for x in data])
+            while len(diff) != 0:
+                # Allocate all yet not allocated clusters
+                new = self._get_available_clusters(data | cluster_ids,
+                                                   len(diff))
+                # Indices of new refcount blocks necessary to cover clusters
+                # in 'new'
+                diff = set([x / size for x in new]) - block_ids
+                cluster_ids |= new
+                block_ids |= diff
+            return cluster_ids, block_ids
+
+        def allocate_rfc_table(data, init_blocks, block_size):
+            """Return indices of clusters allocated for the refcount table
+            and updated indices of clusters allocated for blocks and indices
+            of blocks.
+            """
+            blocks = set(init_blocks)
+            clusters = set()
+            # Number of entries in one cluster of the refcount table
+            size = self.cluster_size / UINT64_S
+            # Number of clusters necessary for the refcount table based on
+            # the current number of refcount blocks
+            table_size = int(ceil((max(blocks) + 1) / float(size)))
+            # Index of the first cluster of the refcount table
+            table_start = self._get_adjacent_clusters(data, table_size + 1)
+            # Clusters allocated for the current length of the refcount table
+            table_clusters = set(range(table_start, table_start + table_size))
+            # Clusters allocated for the refcount table including
+            # last optional one for potential l1 growth
+            table_clusters_allocated = set(range(table_start, table_start +
+                                                 table_size + 1))
+            # New refcount blocks necessary for clusters occupied by the
+            # refcount table
+            diff = set([c / block_size for c in table_clusters]) - blocks
+            blocks |= diff
+            while len(diff) != 0:
+                # Allocate clusters for new refcount blocks
+                new = self._get_available_clusters((data | clusters) |
+                                                   table_clusters_allocated,
+                                                   len(diff))
+                # Indices of new refcount blocks necessary to cover
+                # clusters in 'new'
+                diff = set([x / block_size for x in new]) - blocks
+                clusters |= new
+                blocks |= diff
+                # Check if the refcount table needs one more cluster
+                if int(ceil((max(blocks) + 1) / float(size))) > table_size:
+                    new_block_id = (table_start + table_size) / block_size
+                    # Check if the additional table cluster needs
+                    # one more refcount block
+                    if new_block_id not in blocks:
+                        diff.add(new_block_id)
+                    table_clusters.add(table_start + table_size)
+                    table_size += 1
+            return table_clusters, blocks, clusters
+
+        def create_table_entry(table_offset, block_cluster, block_size,
+                               cluster):
+            """Generate a refcount table entry."""
+            offset = table_offset + UINT64_S * (cluster / block_size)
+            return ['>Q', offset, block_cluster * self.cluster_size,
+                    'refcount_table_entry']
+
+        def create_block_entry(block_cluster, block_size, cluster):
+            """Generate a list of entries for the current block."""
+            entry_size = self.cluster_size / block_size
+            offset = block_cluster * self.cluster_size
+            entry_offset = offset + entry_size * (cluster % block_size)
+            # While snapshots are not supported all refcounts are set to 1
+            return ['>H',entry_offset, 1, 'refcount_block_entry']
+
+        # Number of refcount entries per refcount block
+        block_size = self.cluster_size / \
+                     (1 << self.header['refcount_order'][0].value - 3)
+        meta_data = self._get_metadata()
+        if len(self.data_clusters) == 0:
+            # All metadata for an empty guest image needs 4 clusters:
+            # header, rfc table, rfc block, L1 table.
+            # Header takes cluster #0, other clusters ##1-3 can be used
+            block_clusters = set([random.choice(list(set(range(1, 4)) -
+                                                        meta_data))])
+            block_ids = set([0])
+            table_clusters = set([random.choice(list(set(range(1, 4)) -
+                                                        meta_data -
+                                                        block_clusters))])
+        else:
+            block_clusters, block_ids = \
+                                allocate_rfc_blocks(self.data_clusters | \
+                                                    meta_data, block_size)
+            table_clusters, block_ids, new_clusters = \
+                                    allocate_rfc_table(self.data_clusters | \
+                                                       meta_data | \
+                                                       block_clusters,
+                                                       block_ids,
+                                                       block_size)
+            block_clusters |= new_clusters
+
+        meta_data |= block_clusters | table_clusters
+        table_offset = min(table_clusters) * self.cluster_size
+        block_id = None
+        # Clusters allocated for refcount blocks
+        block_clusters = list(block_clusters)
+        # Indices of refcount blocks
+        block_ids = list(block_ids)
+        # Refcount table entries
+        rfc_table = []
+        # Refcount entries
+        rfc_blocks = []
+
+        for cluster in sorted(self.data_clusters | meta_data):
+            if cluster / block_size != block_id:
+                block_id = cluster / block_size
+                block_cluster = block_clusters[block_ids.index(block_id)]
+                rfc_table.append(create_table_entry(table_offset,
+                                                    block_cluster,
+                                                    block_size, cluster))
+            rfc_blocks.append(create_block_entry(block_cluster, block_size,
+                                                 cluster))
+        self.refcount_table = FieldsList(rfc_table)
+        self.refcount_blocks = FieldsList(rfc_blocks)
+
+        self.header['refcount_table_offset'][0].value = table_offset
+        self.header['refcount_table_clusters'][0].value = len(table_clusters)
+
     def fuzz(self, fields_to_fuzz=None):
         """Fuzz an image by corrupting values of a random subset of its fields.
 
@@ -471,6 +604,7 @@ def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None,
     image.create_feature_name_table()
     image.set_end_of_extension_area()
     image.create_l_structures()
+    image.create_refcount_structures()
     image.fuzz(fields_to_fuzz)
     image.write(test_img_path)
     return image.image_size
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer Maria Kustova
@ 2014-08-19  7:16   ` Fam Zheng
  0 siblings, 0 replies; 9+ messages in thread
From: Fam Zheng @ 2014-08-19  7:16 UTC (permalink / raw)
  To: Maria Kustova; +Cc: kwolf, qemu-devel, stefanha, Maria Kustova

On Mon, 08/11 15:55, Maria Kustova wrote:
> Signed-off-by: Maria Kustova <maria.k@catit.be>
> ---
>  docs/image-fuzzer.txt | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/image-fuzzer.txt b/docs/image-fuzzer.txt
> index 0d0005d..f707269 100644
> --- a/docs/image-fuzzer.txt
> +++ b/docs/image-fuzzer.txt
> @@ -125,7 +125,8 @@ If a fuzzer configuration is specified, then it has the next interpretation:
>      will be always fuzzed for every test. This case is useful for regression
>      testing.
>  
> -For now only header fields, header extensions and L1/L2 tables are generated.
> +The generator can create header fields, header extensions, L1/L2 tables and
> +refcount blocks and table.

"refcount table and blocks" might read better, but it doesn't hurt.

Reviewed-by: Fam Zheng <famz@redhat.com>

>  
>  Module interfaces
>  -----------------
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks Maria Kustova
@ 2014-08-19  7:36   ` Fam Zheng
  0 siblings, 0 replies; 9+ messages in thread
From: Fam Zheng @ 2014-08-19  7:36 UTC (permalink / raw)
  To: Maria Kustova; +Cc: kwolf, qemu-devel, stefanha, Maria Kustova

On Mon, 08/11 15:55, Maria Kustova wrote:
> Signed-off-by: Maria Kustova <maria.k@catit.be>
> ---
>  tests/image-fuzzer/qcow2/fuzz.py | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py
> index 57527f9..5852b4d 100644
> --- a/tests/image-fuzzer/qcow2/fuzz.py
> +++ b/tests/image-fuzzer/qcow2/fuzz.py
> @@ -18,8 +18,8 @@
>  
>  import random
>  
> -
>  UINT8 = 0xff
> +UINT16 = 0xffff
>  UINT32 = 0xffffffff
>  UINT64 = 0xffffffffffffffff
>  # Most significant bit orders
> @@ -28,6 +28,8 @@ UINT64_M = 63
>  # Fuzz vectors
>  UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1,
>             UINT8]
> +UINT16_V = [0, 0x100, 0x1000, UINT16/4, UINT16/2 - 1, UINT16/2, UINT16/2 + 1,
> +            UINT16 - 1, UINT16]
>  UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1,
>              UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32]
>  UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4,

Seeing some pattern in the vectors, but since the types are very few, we can
just construct it like this for now.

> @@ -353,3 +355,15 @@ def l2_entry(current):
>      value = offset + (is_cow << UINT64_M) + \
>              (is_compressed << UINT64_M - 1) + is_zero
>      return value
> +
> +
> +def refcount_table_entry(current):
> +    """Fuzz an entry of the refcount table."""
> +    constraints = UINT64_V
> +    return selector(current, constraints)
> +
> +
> +def refcount_block_entry(current):
> +    """Fuzz an entry of a refcount block."""
> +    constraints = UINT16_V
> +    return selector(current, constraints)
> -- 
> 1.9.3
> 

Reviewed-by: Fam Zheng <famz@redhat.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles and blocks
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles " Maria Kustova
@ 2014-08-19  9:36   ` Fam Zheng
  2014-08-19 10:12     ` M.Kustova
  0 siblings, 1 reply; 9+ messages in thread
From: Fam Zheng @ 2014-08-19  9:36 UTC (permalink / raw)
  To: Maria Kustova; +Cc: kwolf, qemu-devel, stefanha, Maria Kustova

On Mon, 08/11 15:55, Maria Kustova wrote:
> Refcount structures are placed in clusters randomly selected from all not
> allocated host clusters.

s/not allocated/unallocated/

> 
> Signed-off-by: Maria Kustova <maria.k@catit.be>
> ---
>  tests/image-fuzzer/qcow2/layout.py | 136 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 135 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py
> index 730c771..2239789 100644
> --- a/tests/image-fuzzer/qcow2/layout.py
> +++ b/tests/image-fuzzer/qcow2/layout.py
> @@ -102,6 +102,8 @@ class Image(object):
>          self.end_of_extension_area = FieldsList()
>          self.l2_tables = FieldsList()
>          self.l1_table = FieldsList()
> +        self.refcount_table = FieldsList()
> +        self.refcount_blocks = FieldsList()
>          self.ext_offset = 0
>          self.create_header(cluster_bits, backing_file_name)
>          self.set_backing_file_name(backing_file_name)
> @@ -113,7 +115,8 @@ class Image(object):
>      def __iter__(self):
>          return chain(self.header, self.backing_file_format,
>                       self.feature_name_table, self.end_of_extension_area,
> -                     self.backing_file_name, self.l1_table, self.l2_tables)
> +                     self.backing_file_name, self.l1_table, self.l2_tables,
> +                     self.refcount_table, self.refcount_blocks)
>  
>      def create_header(self, cluster_bits, backing_file_name=None):
>          """Generate a random valid header."""
> @@ -330,6 +333,136 @@ class Image(object):
>                                                  float(self.cluster_size**2)))
>          self.header['l1_table_offset'][0].value = l1_offset
>  
> +    def create_refcount_structures(self):
> +        """Generate random refcount blocks and refcount table."""
> +        def allocate_rfc_blocks(data, size):
> +            """Return indices of clusters allocated for recount blocks."""

s/recount/refcount/

> +            cluster_ids = set()
> +            diff = block_ids = set([x / size for x in data])
> +            while len(diff) != 0:
> +                # Allocate all yet not allocated clusters
> +                new = self._get_available_clusters(data | cluster_ids,
> +                                                   len(diff))
> +                # Indices of new refcount blocks necessary to cover clusters
> +                # in 'new'
> +                diff = set([x / size for x in new]) - block_ids
> +                cluster_ids |= new
> +                block_ids |= diff
> +            return cluster_ids, block_ids
> +
> +        def allocate_rfc_table(data, init_blocks, block_size):
> +            """Return indices of clusters allocated for the refcount table
> +            and updated indices of clusters allocated for blocks and indices
> +            of blocks.
> +            """
> +            blocks = set(init_blocks)
> +            clusters = set()
> +            # Number of entries in one cluster of the refcount table
> +            size = self.cluster_size / UINT64_S
> +            # Number of clusters necessary for the refcount table based on
> +            # the current number of refcount blocks
> +            table_size = int(ceil((max(blocks) + 1) / float(size)))
> +            # Index of the first cluster of the refcount table
> +            table_start = self._get_adjacent_clusters(data, table_size + 1)
> +            # Clusters allocated for the current length of the refcount table
> +            table_clusters = set(range(table_start, table_start + table_size))
> +            # Clusters allocated for the refcount table including
> +            # last optional one for potential l1 growth
> +            table_clusters_allocated = set(range(table_start, table_start +
> +                                                 table_size + 1))
> +            # New refcount blocks necessary for clusters occupied by the
> +            # refcount table
> +            diff = set([c / block_size for c in table_clusters]) - blocks
> +            blocks |= diff
> +            while len(diff) != 0:
> +                # Allocate clusters for new refcount blocks
> +                new = self._get_available_clusters((data | clusters) |
> +                                                   table_clusters_allocated,
> +                                                   len(diff))
> +                # Indices of new refcount blocks necessary to cover
> +                # clusters in 'new'
> +                diff = set([x / block_size for x in new]) - blocks
> +                clusters |= new
> +                blocks |= diff
> +                # Check if the refcount table needs one more cluster
> +                if int(ceil((max(blocks) + 1) / float(size))) > table_size:
> +                    new_block_id = (table_start + table_size) / block_size
> +                    # Check if the additional table cluster needs
> +                    # one more refcount block
> +                    if new_block_id not in blocks:
> +                        diff.add(new_block_id)
> +                    table_clusters.add(table_start + table_size)
> +                    table_size += 1
> +            return table_clusters, blocks, clusters
> +
> +        def create_table_entry(table_offset, block_cluster, block_size,
> +                               cluster):
> +            """Generate a refcount table entry."""
> +            offset = table_offset + UINT64_S * (cluster / block_size)
> +            return ['>Q', offset, block_cluster * self.cluster_size,
> +                    'refcount_table_entry']
> +
> +        def create_block_entry(block_cluster, block_size, cluster):
> +            """Generate a list of entries for the current block."""
> +            entry_size = self.cluster_size / block_size
> +            offset = block_cluster * self.cluster_size
> +            entry_offset = offset + entry_size * (cluster % block_size)
> +            # While snapshots are not supported all refcounts are set to 1
> +            return ['>H',entry_offset, 1, 'refcount_block_entry']
> +
> +        # Number of refcount entries per refcount block
> +        block_size = self.cluster_size / \
> +                     (1 << self.header['refcount_order'][0].value - 3)

Why minus 3? Could you use a named constant or a comment?

Fam

> +        meta_data = self._get_metadata()
> +        if len(self.data_clusters) == 0:
> +            # All metadata for an empty guest image needs 4 clusters:
> +            # header, rfc table, rfc block, L1 table.
> +            # Header takes cluster #0, other clusters ##1-3 can be used
> +            block_clusters = set([random.choice(list(set(range(1, 4)) -
> +                                                        meta_data))])
> +            block_ids = set([0])
> +            table_clusters = set([random.choice(list(set(range(1, 4)) -
> +                                                        meta_data -
> +                                                        block_clusters))])
> +        else:
> +            block_clusters, block_ids = \
> +                                allocate_rfc_blocks(self.data_clusters | \
> +                                                    meta_data, block_size)
> +            table_clusters, block_ids, new_clusters = \
> +                                    allocate_rfc_table(self.data_clusters | \
> +                                                       meta_data | \
> +                                                       block_clusters,
> +                                                       block_ids,
> +                                                       block_size)
> +            block_clusters |= new_clusters
> +
> +        meta_data |= block_clusters | table_clusters
> +        table_offset = min(table_clusters) * self.cluster_size
> +        block_id = None
> +        # Clusters allocated for refcount blocks
> +        block_clusters = list(block_clusters)
> +        # Indices of refcount blocks
> +        block_ids = list(block_ids)
> +        # Refcount table entries
> +        rfc_table = []
> +        # Refcount entries
> +        rfc_blocks = []
> +
> +        for cluster in sorted(self.data_clusters | meta_data):
> +            if cluster / block_size != block_id:
> +                block_id = cluster / block_size
> +                block_cluster = block_clusters[block_ids.index(block_id)]
> +                rfc_table.append(create_table_entry(table_offset,
> +                                                    block_cluster,
> +                                                    block_size, cluster))
> +            rfc_blocks.append(create_block_entry(block_cluster, block_size,
> +                                                 cluster))
> +        self.refcount_table = FieldsList(rfc_table)
> +        self.refcount_blocks = FieldsList(rfc_blocks)
> +
> +        self.header['refcount_table_offset'][0].value = table_offset
> +        self.header['refcount_table_clusters'][0].value = len(table_clusters)
> +
>      def fuzz(self, fields_to_fuzz=None):
>          """Fuzz an image by corrupting values of a random subset of its fields.
>  
> @@ -471,6 +604,7 @@ def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None,
>      image.create_feature_name_table()
>      image.set_end_of_extension_area()
>      image.create_l_structures()
> +    image.create_refcount_structures()
>      image.fuzz(fields_to_fuzz)
>      image.write(test_img_path)
>      return image.image_size
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles and blocks
  2014-08-19  9:36   ` Fam Zheng
@ 2014-08-19 10:12     ` M.Kustova
  0 siblings, 0 replies; 9+ messages in thread
From: M.Kustova @ 2014-08-19 10:12 UTC (permalink / raw)
  To: Fam Zheng; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Aug 19, 2014 at 1:36 PM, Fam Zheng <famz@redhat.com> wrote:
> On Mon, 08/11 15:55, Maria Kustova wrote:
>> Refcount structures are placed in clusters randomly selected from all not
>> allocated host clusters.
>
> s/not allocated/unallocated/
>
>>
>> Signed-off-by: Maria Kustova <maria.k@catit.be>
>> ---
>>  tests/image-fuzzer/qcow2/layout.py | 136 ++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 135 insertions(+), 1 deletion(-)
>>
>> diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py
>> index 730c771..2239789 100644
>> --- a/tests/image-fuzzer/qcow2/layout.py
>> +++ b/tests/image-fuzzer/qcow2/layout.py
>> @@ -102,6 +102,8 @@ class Image(object):
>>          self.end_of_extension_area = FieldsList()
>>          self.l2_tables = FieldsList()
>>          self.l1_table = FieldsList()
>> +        self.refcount_table = FieldsList()
>> +        self.refcount_blocks = FieldsList()
>>          self.ext_offset = 0
>>          self.create_header(cluster_bits, backing_file_name)
>>          self.set_backing_file_name(backing_file_name)
>> @@ -113,7 +115,8 @@ class Image(object):
>>      def __iter__(self):
>>          return chain(self.header, self.backing_file_format,
>>                       self.feature_name_table, self.end_of_extension_area,
>> -                     self.backing_file_name, self.l1_table, self.l2_tables)
>> +                     self.backing_file_name, self.l1_table, self.l2_tables,
>> +                     self.refcount_table, self.refcount_blocks)
>>
>>      def create_header(self, cluster_bits, backing_file_name=None):
>>          """Generate a random valid header."""
>> @@ -330,6 +333,136 @@ class Image(object):
>>                                                  float(self.cluster_size**2)))
>>          self.header['l1_table_offset'][0].value = l1_offset
>>
>> +    def create_refcount_structures(self):
>> +        """Generate random refcount blocks and refcount table."""
>> +        def allocate_rfc_blocks(data, size):
>> +            """Return indices of clusters allocated for recount blocks."""
>
> s/recount/refcount/
>
>> +            cluster_ids = set()
>> +            diff = block_ids = set([x / size for x in data])
>> +            while len(diff) != 0:
>> +                # Allocate all yet not allocated clusters
>> +                new = self._get_available_clusters(data | cluster_ids,
>> +                                                   len(diff))
>> +                # Indices of new refcount blocks necessary to cover clusters
>> +                # in 'new'
>> +                diff = set([x / size for x in new]) - block_ids
>> +                cluster_ids |= new
>> +                block_ids |= diff
>> +            return cluster_ids, block_ids
>> +
>> +        def allocate_rfc_table(data, init_blocks, block_size):
>> +            """Return indices of clusters allocated for the refcount table
>> +            and updated indices of clusters allocated for blocks and indices
>> +            of blocks.
>> +            """
>> +            blocks = set(init_blocks)
>> +            clusters = set()
>> +            # Number of entries in one cluster of the refcount table
>> +            size = self.cluster_size / UINT64_S
>> +            # Number of clusters necessary for the refcount table based on
>> +            # the current number of refcount blocks
>> +            table_size = int(ceil((max(blocks) + 1) / float(size)))
>> +            # Index of the first cluster of the refcount table
>> +            table_start = self._get_adjacent_clusters(data, table_size + 1)
>> +            # Clusters allocated for the current length of the refcount table
>> +            table_clusters = set(range(table_start, table_start + table_size))
>> +            # Clusters allocated for the refcount table including
>> +            # last optional one for potential l1 growth
>> +            table_clusters_allocated = set(range(table_start, table_start +
>> +                                                 table_size + 1))
>> +            # New refcount blocks necessary for clusters occupied by the
>> +            # refcount table
>> +            diff = set([c / block_size for c in table_clusters]) - blocks
>> +            blocks |= diff
>> +            while len(diff) != 0:
>> +                # Allocate clusters for new refcount blocks
>> +                new = self._get_available_clusters((data | clusters) |
>> +                                                   table_clusters_allocated,
>> +                                                   len(diff))
>> +                # Indices of new refcount blocks necessary to cover
>> +                # clusters in 'new'
>> +                diff = set([x / block_size for x in new]) - blocks
>> +                clusters |= new
>> +                blocks |= diff
>> +                # Check if the refcount table needs one more cluster
>> +                if int(ceil((max(blocks) + 1) / float(size))) > table_size:
>> +                    new_block_id = (table_start + table_size) / block_size
>> +                    # Check if the additional table cluster needs
>> +                    # one more refcount block
>> +                    if new_block_id not in blocks:
>> +                        diff.add(new_block_id)
>> +                    table_clusters.add(table_start + table_size)
>> +                    table_size += 1
>> +            return table_clusters, blocks, clusters
>> +
>> +        def create_table_entry(table_offset, block_cluster, block_size,
>> +                               cluster):
>> +            """Generate a refcount table entry."""
>> +            offset = table_offset + UINT64_S * (cluster / block_size)
>> +            return ['>Q', offset, block_cluster * self.cluster_size,
>> +                    'refcount_table_entry']
>> +
>> +        def create_block_entry(block_cluster, block_size, cluster):
>> +            """Generate a list of entries for the current block."""
>> +            entry_size = self.cluster_size / block_size
>> +            offset = block_cluster * self.cluster_size
>> +            entry_offset = offset + entry_size * (cluster % block_size)
>> +            # While snapshots are not supported all refcounts are set to 1
>> +            return ['>H',entry_offset, 1, 'refcount_block_entry']
>> +
>> +        # Number of refcount entries per refcount block
>> +        block_size = self.cluster_size / \
>> +                     (1 << self.header['refcount_order'][0].value - 3)
>
> Why minus 3? Could you use a named constant or a comment?
   Conversion to bytes. I will make it more descriptive.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator
  2014-08-11 11:55 [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Maria Kustova
                   ` (2 preceding siblings ...)
  2014-08-11 11:55 ` [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles " Maria Kustova
@ 2014-08-19 10:31 ` Stefan Hajnoczi
  3 siblings, 0 replies; 9+ messages in thread
From: Stefan Hajnoczi @ 2014-08-19 10:31 UTC (permalink / raw)
  To: Maria Kustova; +Cc: kwolf, famz, qemu-devel, Maria Kustova

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

On Mon, Aug 11, 2014 at 03:55:03PM +0400, Maria Kustova wrote:
> This patch series adds support of refcount tables and blocks to the qcow2 image
> generator.
> 
> This patch series was created for the 'block-next' branch and based on the next
> series:
>          [PATCH V3] layout: Reduce number of generator functions in __init__
> 
> Maria Kustova (3):
>   docs: List all image elements currently supported by the fuzzer
>   fuzz: Add fuzzing functions for entries of refcount table and blocks
>   layout: Add generators for refcount tbles and blocks
> 
>  docs/image-fuzzer.txt              |   3 +-
>  tests/image-fuzzer/qcow2/fuzz.py   |  16 ++++-
>  tests/image-fuzzer/qcow2/layout.py | 136 ++++++++++++++++++++++++++++++++++++-
>  3 files changed, 152 insertions(+), 3 deletions(-)
> 
> -- 
> 1.9.3
> 

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-08-19 10:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-11 11:55 [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Maria Kustova
2014-08-11 11:55 ` [Qemu-devel] [PATCH 1/3] docs: List all image elements currently supported by the fuzzer Maria Kustova
2014-08-19  7:16   ` Fam Zheng
2014-08-11 11:55 ` [Qemu-devel] [PATCH 2/3] fuzz: Add fuzzing functions for entries of refcount table and blocks Maria Kustova
2014-08-19  7:36   ` Fam Zheng
2014-08-11 11:55 ` [Qemu-devel] [PATCH 3/3] layout: Add generators for refcount tbles " Maria Kustova
2014-08-19  9:36   ` Fam Zheng
2014-08-19 10:12     ` M.Kustova
2014-08-19 10:31 ` [Qemu-devel] [PATCH 0/3] image-fuzzer: Support refcount structures in the qcow2 image generator Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).