1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
From 97cf5df76657bab81d6b8669607f6f13215201c1 Mon Sep 17 00:00:00 2001
From: Fam Zheng <famcool@gmail.com>
Date: Tue, 12 Jul 2011 19:56:31 +0800
Subject: [PATCH 05/12] VMDK: separate vmdk_open by format version
Separate vmdk_open by subformats to:
* vmdk_open_vmdk3
* vmdk_open_vmdk4
Signed-off-by: Fam Zheng <famcool@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block/vmdk.c | 178 +++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 112 insertions(+), 66 deletions(-)
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -458,67 +458,20 @@ static VmdkExtent *vmdk_add_extent(Block
return extent;
}
-
-static int vmdk_open(BlockDriverState *bs, int flags)
+static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
{
- BDRVVmdkState *s = bs->opaque;
- uint32_t magic;
- int i;
- uint32_t l1_size, l1_entry_sectors;
- VmdkExtent *extent = NULL;
-
- if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic))
- goto fail;
-
- magic = be32_to_cpu(magic);
- if (magic == VMDK3_MAGIC) {
- VMDK3Header header;
- if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header))
- != sizeof(header)) {
- goto fail;
- }
- extent = vmdk_add_extent(bs, bs->file, false,
- le32_to_cpu(header.disk_sectors),
- le32_to_cpu(header.l1dir_offset) << 9, 0,
- 1 << 6, 1 << 9, le32_to_cpu(header.granularity));
- } else if (magic == VMDK4_MAGIC) {
- VMDK4Header header;
- if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header))
- != sizeof(header)) {
- goto fail;
- }
- l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
- * le64_to_cpu(header.granularity);
- l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
- / l1_entry_sectors;
- extent = vmdk_add_extent(bs, bs->file, false,
- le64_to_cpu(header.capacity),
- le64_to_cpu(header.gd_offset) << 9,
- le64_to_cpu(header.rgd_offset) << 9,
- l1_size,
- le32_to_cpu(header.num_gtes_per_gte),
- le64_to_cpu(header.granularity));
- if (extent->l1_entry_sectors <= 0) {
- goto fail;
- }
- // try to open parent images, if exist
- if (vmdk_parent_open(bs) != 0)
- goto fail;
- // write the CID once after the image creation
- s->parent_cid = vmdk_read_cid(bs,1);
- } else {
- goto fail;
- }
+ int ret;
+ int l1_size, i;
/* read the L1 table */
l1_size = extent->l1_size * sizeof(uint32_t);
extent->l1_table = qemu_malloc(l1_size);
- if (bdrv_pread(bs->file,
- extent->l1_table_offset,
- extent->l1_table,
- l1_size)
- != l1_size) {
- goto fail;
+ ret = bdrv_pread(extent->file,
+ extent->l1_table_offset,
+ extent->l1_table,
+ l1_size);
+ if (ret < 0) {
+ goto fail_l1;
}
for (i = 0; i < extent->l1_size; i++) {
le32_to_cpus(&extent->l1_table[i]);
@@ -526,12 +479,12 @@ static int vmdk_open(BlockDriverState *b
if (extent->l1_backup_table_offset) {
extent->l1_backup_table = qemu_malloc(l1_size);
- if (bdrv_pread(bs->file,
- extent->l1_backup_table_offset,
- extent->l1_backup_table,
- l1_size)
- != l1_size) {
- goto fail;
+ ret = bdrv_pread(extent->file,
+ extent->l1_backup_table_offset,
+ extent->l1_backup_table,
+ l1_size);
+ if (ret < 0) {
+ goto fail_l1b;
}
for (i = 0; i < extent->l1_size; i++) {
le32_to_cpus(&extent->l1_backup_table[i]);
@@ -541,9 +494,102 @@ static int vmdk_open(BlockDriverState *b
extent->l2_cache =
qemu_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
return 0;
+ fail_l1b:
+ qemu_free(extent->l1_backup_table);
+ fail_l1:
+ qemu_free(extent->l1_table);
+ return ret;
+}
+
+static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
+{
+ int ret;
+ uint32_t magic;
+ VMDK3Header header;
+ VmdkExtent *extent;
+
+ ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+ if (ret < 0) {
+ goto fail;
+ }
+ extent = vmdk_add_extent(bs,
+ bs->file, false,
+ le32_to_cpu(header.disk_sectors),
+ le32_to_cpu(header.l1dir_offset) << 9,
+ 0, 1 << 6, 1 << 9,
+ le32_to_cpu(header.granularity));
+ ret = vmdk_init_tables(bs, extent);
+ if (ret) {
+ /* vmdk_init_tables cleans up on fail, so only free allocation of
+ * vmdk_add_extent here. */
+ goto fail;
+ }
+ return 0;
fail:
vmdk_free_extents(bs);
- return -1;
+ return ret;
+}
+
+static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
+{
+ int ret;
+ uint32_t magic;
+ uint32_t l1_size, l1_entry_sectors;
+ VMDK4Header header;
+ BDRVVmdkState *s = bs->opaque;
+ VmdkExtent *extent;
+
+ ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+ if (ret < 0) {
+ goto fail;
+ }
+ l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
+ * le64_to_cpu(header.granularity);
+ l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
+ / l1_entry_sectors;
+ extent = vmdk_add_extent(bs, bs->file, false,
+ le64_to_cpu(header.capacity),
+ le64_to_cpu(header.gd_offset) << 9,
+ le64_to_cpu(header.rgd_offset) << 9,
+ l1_size,
+ le32_to_cpu(header.num_gtes_per_gte),
+ le64_to_cpu(header.granularity));
+ if (extent->l1_entry_sectors <= 0) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ /* try to open parent images, if exist */
+ ret = vmdk_parent_open(bs);
+ if (ret) {
+ goto fail;
+ }
+ s->parent_cid = vmdk_read_cid(bs, 1);
+ ret = vmdk_init_tables(bs, extent);
+ if (ret) {
+ goto fail;
+ }
+ return 0;
+ fail:
+ vmdk_free_extents(bs);
+ return ret;
+}
+
+static int vmdk_open(BlockDriverState *bs, int flags)
+{
+ uint32_t magic;
+
+ if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
+ return -EIO;
+ }
+
+ magic = be32_to_cpu(magic);
+ if (magic == VMDK3_MAGIC) {
+ return vmdk_open_vmdk3(bs, flags);
+ } else if (magic == VMDK4_MAGIC) {
+ return vmdk_open_vmdk4(bs, flags);
+ } else {
+ return -EINVAL;
+ }
}
static int get_whole_cluster(BlockDriverState *bs,
@@ -630,11 +676,11 @@ static uint64_t get_cluster_offset(Block
if (!l2_offset) {
return 0;
}
- for(i = 0; i < L2_CACHE_SIZE; i++) {
+ for (i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == extent->l2_cache_offsets[i]) {
/* increment the hit count */
if (++extent->l2_cache_counts[i] == 0xffffffff) {
- for(j = 0; j < L2_CACHE_SIZE; j++) {
+ for (j = 0; j < L2_CACHE_SIZE; j++) {
extent->l2_cache_counts[j] >>= 1;
}
}
@@ -645,7 +691,7 @@ static uint64_t get_cluster_offset(Block
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
- for(i = 0; i < L2_CACHE_SIZE; i++) {
+ for (i = 0; i < L2_CACHE_SIZE; i++) {
if (extent->l2_cache_counts[i] < min_count) {
min_count = extent->l2_cache_counts[i];
min_index = i;
|