* [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).