]>
git.proxmox.com Git - qemu.git/blob - block-vmdk.c
2 * Block driver for the VMDK format
4 * Copyright (c) 2004 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "block_int.h"
27 /* XXX: this code is untested */
28 /* XXX: add write support */
30 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
31 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
36 uint32_t disk_sectors
;
38 uint32_t l1dir_offset
;
40 uint32_t file_sectors
;
43 uint32_t sectors_per_track
;
53 int32_t num_gtes_per_gte
;
61 #define L2_CACHE_SIZE 16
63 typedef struct BDRVVmdkState
{
65 int64_t l1_table_offset
;
68 uint32_t l1_entry_sectors
;
72 uint32_t l2_cache_offsets
[L2_CACHE_SIZE
];
73 uint32_t l2_cache_counts
[L2_CACHE_SIZE
];
75 unsigned int cluster_sectors
;
78 static int vmdk_probe(const uint8_t *buf
, int buf_size
, const char *filename
)
84 magic
= be32_to_cpu(*(uint32_t *)buf
);
85 if (magic
== VMDK3_MAGIC
||
92 static int vmdk_open(BlockDriverState
*bs
, const char *filename
)
94 BDRVVmdkState
*s
= bs
->opaque
;
99 fd
= open(filename
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
102 if (read(fd
, &magic
, sizeof(magic
)) != sizeof(magic
))
104 magic
= le32_to_cpu(magic
);
106 if (magic
== VMDK3_MAGIC
) {
108 if (read(fd
, &header
, sizeof(header
)) !=
111 s
->cluster_sectors
= le32_to_cpu(header
.granularity
);
114 bs
->total_sectors
= le32_to_cpu(header
.disk_sectors
);
115 s
->l1_table_offset
= le32_to_cpu(header
.l1dir_offset
) * 512;
116 s
->l1_entry_sectors
= s
->l2_size
* s
->cluster_sectors
;
117 } else if (magic
== VMDK4_MAGIC
) {
120 if (read(fd
, &header
, sizeof(header
)) != sizeof(header
))
122 bs
->total_sectors
= le32_to_cpu(header
.capacity
);
123 s
->cluster_sectors
= le32_to_cpu(header
.granularity
);
124 s
->l2_size
= le32_to_cpu(header
.num_gtes_per_gte
);
125 s
->l1_entry_sectors
= s
->l2_size
* s
->cluster_sectors
;
126 if (s
->l1_entry_sectors
<= 0)
128 s
->l1_size
= (bs
->total_sectors
+ s
->l1_entry_sectors
- 1)
129 / s
->l1_entry_sectors
;
130 s
->l1_table_offset
= le64_to_cpu(header
.rgd_offset
) * 512;
134 /* read the L1 table */
135 l1_size
= s
->l1_size
* sizeof(uint32_t);
136 s
->l1_table
= qemu_malloc(l1_size
);
139 if (read(s
->fd
, s
->l1_table
, l1_size
) != l1_size
)
141 for(i
= 0; i
< s
->l1_size
; i
++) {
142 le32_to_cpus(&s
->l1_table
[i
]);
145 s
->l2_cache
= qemu_malloc(s
->l2_size
* L2_CACHE_SIZE
* sizeof(uint32_t));
149 /* XXX: currently only read only */
153 qemu_free(s
->l1_table
);
154 qemu_free(s
->l2_cache
);
159 static uint64_t get_cluster_offset(BlockDriverState
*bs
,
162 BDRVVmdkState
*s
= bs
->opaque
;
163 unsigned int l1_index
, l2_offset
, l2_index
;
165 uint32_t min_count
, *l2_table
;
166 uint64_t cluster_offset
;
168 l1_index
= (offset
>> 9) / s
->l1_entry_sectors
;
169 if (l1_index
>= s
->l1_size
)
171 l2_offset
= s
->l1_table
[l1_index
];
175 for(i
= 0; i
< L2_CACHE_SIZE
; i
++) {
176 if (l2_offset
== s
->l2_cache_offsets
[i
]) {
177 /* increment the hit count */
178 if (++s
->l2_cache_counts
[i
] == 0xffffffff) {
179 for(j
= 0; j
< L2_CACHE_SIZE
; j
++) {
180 s
->l2_cache_counts
[j
] >>= 1;
183 l2_table
= s
->l2_cache
+ (i
* s
->l2_size
);
187 /* not found: load a new entry in the least used one */
189 min_count
= 0xffffffff;
190 for(i
= 0; i
< L2_CACHE_SIZE
; i
++) {
191 if (s
->l2_cache_counts
[i
] < min_count
) {
192 min_count
= s
->l2_cache_counts
[i
];
196 l2_table
= s
->l2_cache
+ (min_index
* s
->l2_size
);
197 lseek(s
->fd
, (int64_t)l2_offset
* 512, SEEK_SET
);
198 if (read(s
->fd
, l2_table
, s
->l2_size
* sizeof(uint32_t)) !=
199 s
->l2_size
* sizeof(uint32_t))
201 s
->l2_cache_offsets
[min_index
] = l2_offset
;
202 s
->l2_cache_counts
[min_index
] = 1;
204 l2_index
= ((offset
>> 9) / s
->cluster_sectors
) % s
->l2_size
;
205 cluster_offset
= le32_to_cpu(l2_table
[l2_index
]);
206 cluster_offset
<<= 9;
207 return cluster_offset
;
210 static int vmdk_is_allocated(BlockDriverState
*bs
, int64_t sector_num
,
211 int nb_sectors
, int *pnum
)
213 BDRVVmdkState
*s
= bs
->opaque
;
214 int index_in_cluster
, n
;
215 uint64_t cluster_offset
;
217 cluster_offset
= get_cluster_offset(bs
, sector_num
<< 9);
218 index_in_cluster
= sector_num
% s
->cluster_sectors
;
219 n
= s
->cluster_sectors
- index_in_cluster
;
223 return (cluster_offset
!= 0);
226 static int vmdk_read(BlockDriverState
*bs
, int64_t sector_num
,
227 uint8_t *buf
, int nb_sectors
)
229 BDRVVmdkState
*s
= bs
->opaque
;
230 int ret
, index_in_cluster
, n
;
231 uint64_t cluster_offset
;
233 while (nb_sectors
> 0) {
234 cluster_offset
= get_cluster_offset(bs
, sector_num
<< 9);
235 index_in_cluster
= sector_num
% s
->cluster_sectors
;
236 n
= s
->cluster_sectors
- index_in_cluster
;
239 if (!cluster_offset
) {
240 memset(buf
, 0, 512 * n
);
242 lseek(s
->fd
, cluster_offset
+ index_in_cluster
* 512, SEEK_SET
);
243 ret
= read(s
->fd
, buf
, n
* 512);
254 static int vmdk_write(BlockDriverState
*bs
, int64_t sector_num
,
255 const uint8_t *buf
, int nb_sectors
)
260 static int vmdk_close(BlockDriverState
*bs
)
262 BDRVVmdkState
*s
= bs
->opaque
;
263 qemu_free(s
->l1_table
);
264 qemu_free(s
->l2_cache
);
268 BlockDriver bdrv_vmdk
= {
270 sizeof(BDRVVmdkState
),
276 NULL
, /* no create yet */