root / block / cow.c @ 8c116b0e
History | View | Annotate | Download (12.1 kB)
1 | ea2384d3 | bellard | /*
|
---|---|---|---|
2 | ea2384d3 | bellard | * Block driver for the COW format
|
3 | 5fafdf24 | ths | *
|
4 | ea2384d3 | bellard | * Copyright (c) 2004 Fabrice Bellard
|
5 | 5fafdf24 | ths | *
|
6 | ea2384d3 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | ea2384d3 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | ea2384d3 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | ea2384d3 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | ea2384d3 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | ea2384d3 | bellard | * furnished to do so, subject to the following conditions:
|
12 | ea2384d3 | bellard | *
|
13 | ea2384d3 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | ea2384d3 | bellard | * all copies or substantial portions of the Software.
|
15 | ea2384d3 | bellard | *
|
16 | ea2384d3 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | ea2384d3 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | ea2384d3 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | ea2384d3 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | ea2384d3 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | ea2384d3 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | ea2384d3 | bellard | * THE SOFTWARE.
|
23 | ea2384d3 | bellard | */
|
24 | faf07963 | pbrook | #include "qemu-common.h" |
25 | 737e150e | Paolo Bonzini | #include "block/block_int.h" |
26 | 1de7afc9 | Paolo Bonzini | #include "qemu/module.h" |
27 | ea2384d3 | bellard | |
28 | ea2384d3 | bellard | /**************************************************************/
|
29 | ea2384d3 | bellard | /* COW block driver using file system holes */
|
30 | ea2384d3 | bellard | |
31 | ea2384d3 | bellard | /* user mode linux compatible COW file */
|
32 | ea2384d3 | bellard | #define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
33 | ea2384d3 | bellard | #define COW_VERSION 2 |
34 | ea2384d3 | bellard | |
35 | ea2384d3 | bellard | struct cow_header_v2 {
|
36 | ea2384d3 | bellard | uint32_t magic; |
37 | ea2384d3 | bellard | uint32_t version; |
38 | ea2384d3 | bellard | char backing_file[1024]; |
39 | ea2384d3 | bellard | int32_t mtime; |
40 | ea2384d3 | bellard | uint64_t size; |
41 | ea2384d3 | bellard | uint32_t sectorsize; |
42 | ea2384d3 | bellard | }; |
43 | ea2384d3 | bellard | |
44 | ea2384d3 | bellard | typedef struct BDRVCowState { |
45 | 848c66e8 | Paolo Bonzini | CoMutex lock; |
46 | ea2384d3 | bellard | int64_t cow_sectors_offset; |
47 | ea2384d3 | bellard | } BDRVCowState; |
48 | ea2384d3 | bellard | |
49 | ea2384d3 | bellard | static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) |
50 | ea2384d3 | bellard | { |
51 | ea2384d3 | bellard | const struct cow_header_v2 *cow_header = (const void *)buf; |
52 | ea2384d3 | bellard | |
53 | 712e7874 | bellard | if (buf_size >= sizeof(struct cow_header_v2) && |
54 | 712e7874 | bellard | be32_to_cpu(cow_header->magic) == COW_MAGIC && |
55 | 5fafdf24 | ths | be32_to_cpu(cow_header->version) == COW_VERSION) |
56 | ea2384d3 | bellard | return 100; |
57 | ea2384d3 | bellard | else
|
58 | ea2384d3 | bellard | return 0; |
59 | ea2384d3 | bellard | } |
60 | ea2384d3 | bellard | |
61 | 015a1036 | Max Reitz | static int cow_open(BlockDriverState *bs, QDict *options, int flags, |
62 | 015a1036 | Max Reitz | Error **errp) |
63 | ea2384d3 | bellard | { |
64 | ea2384d3 | bellard | BDRVCowState *s = bs->opaque; |
65 | ea2384d3 | bellard | struct cow_header_v2 cow_header;
|
66 | 893a9cb4 | Christoph Hellwig | int bitmap_size;
|
67 | ea2384d3 | bellard | int64_t size; |
68 | 16d2fc00 | Li Zhi Hui | int ret;
|
69 | ea2384d3 | bellard | |
70 | ea2384d3 | bellard | /* see if it is a cow image */
|
71 | 16d2fc00 | Li Zhi Hui | ret = bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header)); |
72 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
73 | 16d2fc00 | Li Zhi Hui | goto fail;
|
74 | 16d2fc00 | Li Zhi Hui | } |
75 | 16d2fc00 | Li Zhi Hui | |
76 | 16d2fc00 | Li Zhi Hui | if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
|
77 | 15bac0d5 | Stefan Weil | ret = -EMEDIUMTYPE; |
78 | ea2384d3 | bellard | goto fail;
|
79 | ea2384d3 | bellard | } |
80 | ea2384d3 | bellard | |
81 | 16d2fc00 | Li Zhi Hui | if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
82 | 16d2fc00 | Li Zhi Hui | char version[64]; |
83 | 16d2fc00 | Li Zhi Hui | snprintf(version, sizeof(version),
|
84 | 16d2fc00 | Li Zhi Hui | "COW version %d", cow_header.version);
|
85 | 16d2fc00 | Li Zhi Hui | qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, |
86 | 16d2fc00 | Li Zhi Hui | bs->device_name, "cow", version);
|
87 | 16d2fc00 | Li Zhi Hui | ret = -ENOTSUP; |
88 | ea2384d3 | bellard | goto fail;
|
89 | ea2384d3 | bellard | } |
90 | 3b46e624 | ths | |
91 | ea2384d3 | bellard | /* cow image found */
|
92 | ea2384d3 | bellard | size = be64_to_cpu(cow_header.size); |
93 | ea2384d3 | bellard | bs->total_sectors = size / 512;
|
94 | ea2384d3 | bellard | |
95 | 5fafdf24 | ths | pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
96 | ea2384d3 | bellard | cow_header.backing_file); |
97 | 3b46e624 | ths | |
98 | 893a9cb4 | Christoph Hellwig | bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
99 | 893a9cb4 | Christoph Hellwig | s->cow_sectors_offset = (bitmap_size + 511) & ~511; |
100 | 848c66e8 | Paolo Bonzini | qemu_co_mutex_init(&s->lock); |
101 | ea2384d3 | bellard | return 0; |
102 | ea2384d3 | bellard | fail:
|
103 | 16d2fc00 | Li Zhi Hui | return ret;
|
104 | ea2384d3 | bellard | } |
105 | ea2384d3 | bellard | |
106 | 14b98fda | Charlie Shepherd | static inline void cow_set_bits(uint8_t *bitmap, int start, int64_t nb_sectors) |
107 | ea2384d3 | bellard | { |
108 | 14b98fda | Charlie Shepherd | int64_t bitnum = start, last = start + nb_sectors; |
109 | 14b98fda | Charlie Shepherd | while (bitnum < last) {
|
110 | 14b98fda | Charlie Shepherd | if ((bitnum & 7) == 0 && bitnum + 8 <= last) { |
111 | 14b98fda | Charlie Shepherd | bitmap[bitnum / 8] = 0xFF; |
112 | 14b98fda | Charlie Shepherd | bitnum += 8;
|
113 | 14b98fda | Charlie Shepherd | continue;
|
114 | 26ae9804 | Paolo Bonzini | } |
115 | 14b98fda | Charlie Shepherd | bitmap[bitnum/8] |= (1 << (bitnum % 8)); |
116 | 14b98fda | Charlie Shepherd | bitnum++; |
117 | 26ae9804 | Paolo Bonzini | } |
118 | ea2384d3 | bellard | } |
119 | ea2384d3 | bellard | |
120 | 276cbc7f | Paolo Bonzini | #define BITS_PER_BITMAP_SECTOR (512 * 8) |
121 | 276cbc7f | Paolo Bonzini | |
122 | 276cbc7f | Paolo Bonzini | /* Cannot use bitmap.c on big-endian machines. */
|
123 | 276cbc7f | Paolo Bonzini | static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap) |
124 | ea2384d3 | bellard | { |
125 | 276cbc7f | Paolo Bonzini | return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0; |
126 | 276cbc7f | Paolo Bonzini | } |
127 | ea2384d3 | bellard | |
128 | 276cbc7f | Paolo Bonzini | static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors) |
129 | 276cbc7f | Paolo Bonzini | { |
130 | 276cbc7f | Paolo Bonzini | int streak_value = value ? 0xFF : 0; |
131 | 276cbc7f | Paolo Bonzini | int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR);
|
132 | 276cbc7f | Paolo Bonzini | int bitnum = start;
|
133 | 276cbc7f | Paolo Bonzini | while (bitnum < last) {
|
134 | 276cbc7f | Paolo Bonzini | if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) { |
135 | 276cbc7f | Paolo Bonzini | bitnum += 8;
|
136 | 276cbc7f | Paolo Bonzini | continue;
|
137 | 276cbc7f | Paolo Bonzini | } |
138 | 276cbc7f | Paolo Bonzini | if (cow_test_bit(bitnum, bitmap) == value) {
|
139 | 276cbc7f | Paolo Bonzini | bitnum++; |
140 | 276cbc7f | Paolo Bonzini | continue;
|
141 | 276cbc7f | Paolo Bonzini | } |
142 | 276cbc7f | Paolo Bonzini | break;
|
143 | 893a9cb4 | Christoph Hellwig | } |
144 | 276cbc7f | Paolo Bonzini | return MIN(bitnum, last) - start;
|
145 | 893a9cb4 | Christoph Hellwig | } |
146 | ea2384d3 | bellard | |
147 | ea2384d3 | bellard | /* Return true if first block has been changed (ie. current version is
|
148 | ea2384d3 | bellard | * in COW file). Set the number of continuous blocks for which that
|
149 | ea2384d3 | bellard | * is true. */
|
150 | 81145834 | Stefan Hajnoczi | static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs, |
151 | 81145834 | Stefan Hajnoczi | int64_t sector_num, int nb_sectors, int *num_same) |
152 | ea2384d3 | bellard | { |
153 | 276cbc7f | Paolo Bonzini | int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; |
154 | 276cbc7f | Paolo Bonzini | uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
155 | 091b1108 | Charlie Shepherd | bool first = true; |
156 | 091b1108 | Charlie Shepherd | int changed = 0, same = 0; |
157 | ea2384d3 | bellard | |
158 | 091b1108 | Charlie Shepherd | do {
|
159 | 091b1108 | Charlie Shepherd | int ret;
|
160 | 091b1108 | Charlie Shepherd | uint8_t bitmap[BDRV_SECTOR_SIZE]; |
161 | 091b1108 | Charlie Shepherd | |
162 | 091b1108 | Charlie Shepherd | bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
163 | 091b1108 | Charlie Shepherd | int sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
|
164 | 091b1108 | Charlie Shepherd | |
165 | 091b1108 | Charlie Shepherd | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
166 | 091b1108 | Charlie Shepherd | if (ret < 0) { |
167 | 091b1108 | Charlie Shepherd | return ret;
|
168 | 091b1108 | Charlie Shepherd | } |
169 | 091b1108 | Charlie Shepherd | |
170 | 091b1108 | Charlie Shepherd | if (first) {
|
171 | 091b1108 | Charlie Shepherd | changed = cow_test_bit(bitnum, bitmap); |
172 | 091b1108 | Charlie Shepherd | first = false;
|
173 | 091b1108 | Charlie Shepherd | } |
174 | 091b1108 | Charlie Shepherd | |
175 | 091b1108 | Charlie Shepherd | same += cow_find_streak(bitmap, changed, bitnum, nb_sectors); |
176 | 091b1108 | Charlie Shepherd | |
177 | 091b1108 | Charlie Shepherd | bitnum += sector_bits; |
178 | 091b1108 | Charlie Shepherd | nb_sectors -= sector_bits; |
179 | 091b1108 | Charlie Shepherd | offset += BDRV_SECTOR_SIZE; |
180 | 091b1108 | Charlie Shepherd | } while (nb_sectors);
|
181 | ea2384d3 | bellard | |
182 | 091b1108 | Charlie Shepherd | *num_same = same; |
183 | ea2384d3 | bellard | return changed;
|
184 | ea2384d3 | bellard | } |
185 | ea2384d3 | bellard | |
186 | b6b8a333 | Paolo Bonzini | static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs,
|
187 | b6b8a333 | Paolo Bonzini | int64_t sector_num, int nb_sectors, int *num_same) |
188 | b6b8a333 | Paolo Bonzini | { |
189 | 4bc74be9 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
190 | 4bc74be9 | Paolo Bonzini | int ret = cow_co_is_allocated(bs, sector_num, nb_sectors, num_same);
|
191 | 4bc74be9 | Paolo Bonzini | int64_t offset = s->cow_sectors_offset + (sector_num << BDRV_SECTOR_BITS); |
192 | 4bc74be9 | Paolo Bonzini | if (ret < 0) { |
193 | 4bc74be9 | Paolo Bonzini | return ret;
|
194 | 4bc74be9 | Paolo Bonzini | } |
195 | 4bc74be9 | Paolo Bonzini | return (ret ? BDRV_BLOCK_DATA : 0) | offset | BDRV_BLOCK_OFFSET_VALID; |
196 | b6b8a333 | Paolo Bonzini | } |
197 | b6b8a333 | Paolo Bonzini | |
198 | 893a9cb4 | Christoph Hellwig | static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, |
199 | 893a9cb4 | Christoph Hellwig | int nb_sectors)
|
200 | ea2384d3 | bellard | { |
201 | 14b98fda | Charlie Shepherd | int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; |
202 | 14b98fda | Charlie Shepherd | uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
203 | 26ae9804 | Paolo Bonzini | bool first = true; |
204 | 14b98fda | Charlie Shepherd | int sector_bits;
|
205 | 14b98fda | Charlie Shepherd | |
206 | 14b98fda | Charlie Shepherd | for ( ; nb_sectors;
|
207 | 14b98fda | Charlie Shepherd | bitnum += sector_bits, |
208 | 14b98fda | Charlie Shepherd | nb_sectors -= sector_bits, |
209 | 14b98fda | Charlie Shepherd | offset += BDRV_SECTOR_SIZE) { |
210 | 14b98fda | Charlie Shepherd | int ret, set;
|
211 | 14b98fda | Charlie Shepherd | uint8_t bitmap[BDRV_SECTOR_SIZE]; |
212 | 14b98fda | Charlie Shepherd | |
213 | 14b98fda | Charlie Shepherd | bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
214 | 14b98fda | Charlie Shepherd | sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum); |
215 | 14b98fda | Charlie Shepherd | |
216 | 14b98fda | Charlie Shepherd | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
217 | 14b98fda | Charlie Shepherd | if (ret < 0) { |
218 | 14b98fda | Charlie Shepherd | return ret;
|
219 | 14b98fda | Charlie Shepherd | } |
220 | 14b98fda | Charlie Shepherd | |
221 | 14b98fda | Charlie Shepherd | /* Skip over any already set bits */
|
222 | 14b98fda | Charlie Shepherd | set = cow_find_streak(bitmap, 1, bitnum, sector_bits);
|
223 | 14b98fda | Charlie Shepherd | bitnum += set; |
224 | 14b98fda | Charlie Shepherd | sector_bits -= set; |
225 | 14b98fda | Charlie Shepherd | nb_sectors -= set; |
226 | 14b98fda | Charlie Shepherd | if (!sector_bits) {
|
227 | 14b98fda | Charlie Shepherd | continue;
|
228 | 14b98fda | Charlie Shepherd | } |
229 | 14b98fda | Charlie Shepherd | |
230 | 14b98fda | Charlie Shepherd | if (first) {
|
231 | 14b98fda | Charlie Shepherd | ret = bdrv_flush(bs->file); |
232 | 14b98fda | Charlie Shepherd | if (ret < 0) { |
233 | 14b98fda | Charlie Shepherd | return ret;
|
234 | 14b98fda | Charlie Shepherd | } |
235 | 14b98fda | Charlie Shepherd | first = false;
|
236 | 14b98fda | Charlie Shepherd | } |
237 | 14b98fda | Charlie Shepherd | |
238 | 14b98fda | Charlie Shepherd | cow_set_bits(bitmap, bitnum, sector_bits); |
239 | 893a9cb4 | Christoph Hellwig | |
240 | 14b98fda | Charlie Shepherd | ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap));
|
241 | 14b98fda | Charlie Shepherd | if (ret < 0) { |
242 | 14b98fda | Charlie Shepherd | return ret;
|
243 | 893a9cb4 | Christoph Hellwig | } |
244 | 893a9cb4 | Christoph Hellwig | } |
245 | 893a9cb4 | Christoph Hellwig | |
246 | 14b98fda | Charlie Shepherd | return 0; |
247 | ea2384d3 | bellard | } |
248 | ea2384d3 | bellard | |
249 | e94d1387 | Stefan Hajnoczi | static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num, |
250 | e94d1387 | Stefan Hajnoczi | uint8_t *buf, int nb_sectors)
|
251 | ea2384d3 | bellard | { |
252 | ea2384d3 | bellard | BDRVCowState *s = bs->opaque; |
253 | ea2384d3 | bellard | int ret, n;
|
254 | 3b46e624 | ths | |
255 | ea2384d3 | bellard | while (nb_sectors > 0) { |
256 | d663640c | Paolo Bonzini | ret = cow_co_is_allocated(bs, sector_num, nb_sectors, &n); |
257 | d663640c | Paolo Bonzini | if (ret < 0) { |
258 | d663640c | Paolo Bonzini | return ret;
|
259 | d663640c | Paolo Bonzini | } |
260 | d663640c | Paolo Bonzini | if (ret) {
|
261 | 2063392a | Christoph Hellwig | ret = bdrv_pread(bs->file, |
262 | 2063392a | Christoph Hellwig | s->cow_sectors_offset + sector_num * 512,
|
263 | 2063392a | Christoph Hellwig | buf, n * 512);
|
264 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
265 | 16d2fc00 | Li Zhi Hui | return ret;
|
266 | 16d2fc00 | Li Zhi Hui | } |
267 | ea2384d3 | bellard | } else {
|
268 | 83f64091 | bellard | if (bs->backing_hd) {
|
269 | 83f64091 | bellard | /* read from the base image */
|
270 | 83f64091 | bellard | ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
271 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
272 | 16d2fc00 | Li Zhi Hui | return ret;
|
273 | 16d2fc00 | Li Zhi Hui | } |
274 | 83f64091 | bellard | } else {
|
275 | 16d2fc00 | Li Zhi Hui | memset(buf, 0, n * 512); |
276 | 16d2fc00 | Li Zhi Hui | } |
277 | 83f64091 | bellard | } |
278 | ea2384d3 | bellard | nb_sectors -= n; |
279 | ea2384d3 | bellard | sector_num += n; |
280 | ea2384d3 | bellard | buf += n * 512;
|
281 | ea2384d3 | bellard | } |
282 | ea2384d3 | bellard | return 0; |
283 | ea2384d3 | bellard | } |
284 | ea2384d3 | bellard | |
285 | 2914caa0 | Paolo Bonzini | static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num, |
286 | 2914caa0 | Paolo Bonzini | uint8_t *buf, int nb_sectors)
|
287 | 2914caa0 | Paolo Bonzini | { |
288 | 2914caa0 | Paolo Bonzini | int ret;
|
289 | 2914caa0 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
290 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_lock(&s->lock); |
291 | 2914caa0 | Paolo Bonzini | ret = cow_read(bs, sector_num, buf, nb_sectors); |
292 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_unlock(&s->lock); |
293 | 2914caa0 | Paolo Bonzini | return ret;
|
294 | 2914caa0 | Paolo Bonzini | } |
295 | 2914caa0 | Paolo Bonzini | |
296 | 5fafdf24 | ths | static int cow_write(BlockDriverState *bs, int64_t sector_num, |
297 | ea2384d3 | bellard | const uint8_t *buf, int nb_sectors) |
298 | ea2384d3 | bellard | { |
299 | ea2384d3 | bellard | BDRVCowState *s = bs->opaque; |
300 | 893a9cb4 | Christoph Hellwig | int ret;
|
301 | 3b46e624 | ths | |
302 | 2063392a | Christoph Hellwig | ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
|
303 | 2063392a | Christoph Hellwig | buf, nb_sectors * 512);
|
304 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
305 | 16d2fc00 | Li Zhi Hui | return ret;
|
306 | 16d2fc00 | Li Zhi Hui | } |
307 | 893a9cb4 | Christoph Hellwig | |
308 | 893a9cb4 | Christoph Hellwig | return cow_update_bitmap(bs, sector_num, nb_sectors);
|
309 | ea2384d3 | bellard | } |
310 | ea2384d3 | bellard | |
311 | e183ef75 | Paolo Bonzini | static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num, |
312 | e183ef75 | Paolo Bonzini | const uint8_t *buf, int nb_sectors) |
313 | e183ef75 | Paolo Bonzini | { |
314 | e183ef75 | Paolo Bonzini | int ret;
|
315 | e183ef75 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
316 | e183ef75 | Paolo Bonzini | qemu_co_mutex_lock(&s->lock); |
317 | e183ef75 | Paolo Bonzini | ret = cow_write(bs, sector_num, buf, nb_sectors); |
318 | e183ef75 | Paolo Bonzini | qemu_co_mutex_unlock(&s->lock); |
319 | e183ef75 | Paolo Bonzini | return ret;
|
320 | e183ef75 | Paolo Bonzini | } |
321 | e183ef75 | Paolo Bonzini | |
322 | e2731add | bellard | static void cow_close(BlockDriverState *bs) |
323 | ea2384d3 | bellard | { |
324 | ea2384d3 | bellard | } |
325 | ea2384d3 | bellard | |
326 | d5124c00 | Max Reitz | static int cow_create(const char *filename, QEMUOptionParameter *options, |
327 | d5124c00 | Max Reitz | Error **errp) |
328 | ea2384d3 | bellard | { |
329 | ea2384d3 | bellard | struct cow_header_v2 cow_header;
|
330 | ea2384d3 | bellard | struct stat st;
|
331 | 0e7e1989 | Kevin Wolf | int64_t image_sectors = 0;
|
332 | 0e7e1989 | Kevin Wolf | const char *image_filename = NULL; |
333 | 34b5d2c6 | Max Reitz | Error *local_err = NULL;
|
334 | 31f38120 | Kirill A. Shutemov | int ret;
|
335 | 3535a9c6 | Li Zhi Hui | BlockDriverState *cow_bs; |
336 | 0e7e1989 | Kevin Wolf | |
337 | 0e7e1989 | Kevin Wolf | /* Read out options */
|
338 | 0e7e1989 | Kevin Wolf | while (options && options->name) {
|
339 | 0e7e1989 | Kevin Wolf | if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
340 | 0e7e1989 | Kevin Wolf | image_sectors = options->value.n / 512;
|
341 | 0e7e1989 | Kevin Wolf | } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { |
342 | 0e7e1989 | Kevin Wolf | image_filename = options->value.s; |
343 | 0e7e1989 | Kevin Wolf | } |
344 | 0e7e1989 | Kevin Wolf | options++; |
345 | 0e7e1989 | Kevin Wolf | } |
346 | ea2384d3 | bellard | |
347 | cc84d90f | Max Reitz | ret = bdrv_create_file(filename, options, &local_err); |
348 | 3535a9c6 | Li Zhi Hui | if (ret < 0) { |
349 | cc84d90f | Max Reitz | qerror_report_err(local_err); |
350 | cc84d90f | Max Reitz | error_free(local_err); |
351 | 3535a9c6 | Li Zhi Hui | return ret;
|
352 | 3535a9c6 | Li Zhi Hui | } |
353 | 3535a9c6 | Li Zhi Hui | |
354 | 34b5d2c6 | Max Reitz | ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
355 | 3535a9c6 | Li Zhi Hui | if (ret < 0) { |
356 | 34b5d2c6 | Max Reitz | qerror_report_err(local_err); |
357 | 34b5d2c6 | Max Reitz | error_free(local_err); |
358 | 3535a9c6 | Li Zhi Hui | return ret;
|
359 | 3535a9c6 | Li Zhi Hui | } |
360 | 3535a9c6 | Li Zhi Hui | |
361 | ea2384d3 | bellard | memset(&cow_header, 0, sizeof(cow_header)); |
362 | ea2384d3 | bellard | cow_header.magic = cpu_to_be32(COW_MAGIC); |
363 | ea2384d3 | bellard | cow_header.version = cpu_to_be32(COW_VERSION); |
364 | ea2384d3 | bellard | if (image_filename) {
|
365 | 83f64091 | bellard | /* Note: if no file, we put a dummy mtime */
|
366 | 83f64091 | bellard | cow_header.mtime = cpu_to_be32(0);
|
367 | 83f64091 | bellard | |
368 | 3535a9c6 | Li Zhi Hui | if (stat(image_filename, &st) != 0) { |
369 | 83f64091 | bellard | goto mtime_fail;
|
370 | ea2384d3 | bellard | } |
371 | ea2384d3 | bellard | cow_header.mtime = cpu_to_be32(st.st_mtime); |
372 | 83f64091 | bellard | mtime_fail:
|
373 | 83f64091 | bellard | pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
374 | 83f64091 | bellard | image_filename); |
375 | ea2384d3 | bellard | } |
376 | ea2384d3 | bellard | cow_header.sectorsize = cpu_to_be32(512);
|
377 | ea2384d3 | bellard | cow_header.size = cpu_to_be64(image_sectors * 512);
|
378 | 3535a9c6 | Li Zhi Hui | ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header)); |
379 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
380 | 31f38120 | Kirill A. Shutemov | goto exit;
|
381 | 31f38120 | Kirill A. Shutemov | } |
382 | 31f38120 | Kirill A. Shutemov | |
383 | ea2384d3 | bellard | /* resize to include at least all the bitmap */
|
384 | 3535a9c6 | Li Zhi Hui | ret = bdrv_truncate(cow_bs, |
385 | 3535a9c6 | Li Zhi Hui | sizeof(cow_header) + ((image_sectors + 7) >> 3)); |
386 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
387 | 31f38120 | Kirill A. Shutemov | goto exit;
|
388 | 31f38120 | Kirill A. Shutemov | } |
389 | 31f38120 | Kirill A. Shutemov | |
390 | 31f38120 | Kirill A. Shutemov | exit:
|
391 | 4f6fd349 | Fam Zheng | bdrv_unref(cow_bs); |
392 | 31f38120 | Kirill A. Shutemov | return ret;
|
393 | ea2384d3 | bellard | } |
394 | ea2384d3 | bellard | |
395 | 0e7e1989 | Kevin Wolf | static QEMUOptionParameter cow_create_options[] = {
|
396 | db08adf5 | Kevin Wolf | { |
397 | db08adf5 | Kevin Wolf | .name = BLOCK_OPT_SIZE, |
398 | db08adf5 | Kevin Wolf | .type = OPT_SIZE, |
399 | db08adf5 | Kevin Wolf | .help = "Virtual disk size"
|
400 | db08adf5 | Kevin Wolf | }, |
401 | db08adf5 | Kevin Wolf | { |
402 | db08adf5 | Kevin Wolf | .name = BLOCK_OPT_BACKING_FILE, |
403 | db08adf5 | Kevin Wolf | .type = OPT_STRING, |
404 | db08adf5 | Kevin Wolf | .help = "File name of a base image"
|
405 | db08adf5 | Kevin Wolf | }, |
406 | 0e7e1989 | Kevin Wolf | { NULL }
|
407 | 0e7e1989 | Kevin Wolf | }; |
408 | 0e7e1989 | Kevin Wolf | |
409 | 5efa9d5a | Anthony Liguori | static BlockDriver bdrv_cow = {
|
410 | c68b89ac | Kevin Wolf | .format_name = "cow",
|
411 | c68b89ac | Kevin Wolf | .instance_size = sizeof(BDRVCowState),
|
412 | c68b89ac | Kevin Wolf | |
413 | c68b89ac | Kevin Wolf | .bdrv_probe = cow_probe, |
414 | c68b89ac | Kevin Wolf | .bdrv_open = cow_open, |
415 | c68b89ac | Kevin Wolf | .bdrv_close = cow_close, |
416 | c68b89ac | Kevin Wolf | .bdrv_create = cow_create, |
417 | 3ac21627 | Peter Lieven | .bdrv_has_zero_init = bdrv_has_zero_init_1, |
418 | c68b89ac | Kevin Wolf | |
419 | c68b89ac | Kevin Wolf | .bdrv_read = cow_co_read, |
420 | c68b89ac | Kevin Wolf | .bdrv_write = cow_co_write, |
421 | b6b8a333 | Paolo Bonzini | .bdrv_co_get_block_status = cow_co_get_block_status, |
422 | 0e7e1989 | Kevin Wolf | |
423 | 0e7e1989 | Kevin Wolf | .create_options = cow_create_options, |
424 | ea2384d3 | bellard | }; |
425 | 5efa9d5a | Anthony Liguori | |
426 | 5efa9d5a | Anthony Liguori | static void bdrv_cow_init(void) |
427 | 5efa9d5a | Anthony Liguori | { |
428 | 5efa9d5a | Anthony Liguori | bdrv_register(&bdrv_cow); |
429 | 5efa9d5a | Anthony Liguori | } |
430 | 5efa9d5a | Anthony Liguori | |
431 | 5efa9d5a | Anthony Liguori | block_init(bdrv_cow_init); |