root / block / cow.c @ cc84d90f
History | View | Annotate | Download (11.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 | 893a9cb4 | Christoph Hellwig | /*
|
107 | 4e35b92a | Stefan Weil | * XXX(hch): right now these functions are extremely inefficient.
|
108 | 893a9cb4 | Christoph Hellwig | * We should just read the whole bitmap we'll need in one go instead.
|
109 | 893a9cb4 | Christoph Hellwig | */
|
110 | 26ae9804 | Paolo Bonzini | static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum, bool *first) |
111 | ea2384d3 | bellard | { |
112 | 893a9cb4 | Christoph Hellwig | uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8; |
113 | 893a9cb4 | Christoph Hellwig | uint8_t bitmap; |
114 | b0ad5a45 | Kevin Wolf | int ret;
|
115 | 893a9cb4 | Christoph Hellwig | |
116 | b0ad5a45 | Kevin Wolf | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
117 | b0ad5a45 | Kevin Wolf | if (ret < 0) { |
118 | b0ad5a45 | Kevin Wolf | return ret;
|
119 | 893a9cb4 | Christoph Hellwig | } |
120 | 893a9cb4 | Christoph Hellwig | |
121 | 26ae9804 | Paolo Bonzini | if (bitmap & (1 << (bitnum % 8))) { |
122 | 26ae9804 | Paolo Bonzini | return 0; |
123 | 26ae9804 | Paolo Bonzini | } |
124 | 26ae9804 | Paolo Bonzini | |
125 | 26ae9804 | Paolo Bonzini | if (*first) {
|
126 | 26ae9804 | Paolo Bonzini | ret = bdrv_flush(bs->file); |
127 | 26ae9804 | Paolo Bonzini | if (ret < 0) { |
128 | 26ae9804 | Paolo Bonzini | return ret;
|
129 | 26ae9804 | Paolo Bonzini | } |
130 | 26ae9804 | Paolo Bonzini | *first = false;
|
131 | 26ae9804 | Paolo Bonzini | } |
132 | 26ae9804 | Paolo Bonzini | |
133 | 893a9cb4 | Christoph Hellwig | bitmap |= (1 << (bitnum % 8)); |
134 | 893a9cb4 | Christoph Hellwig | |
135 | 26ae9804 | Paolo Bonzini | ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap));
|
136 | b0ad5a45 | Kevin Wolf | if (ret < 0) { |
137 | b0ad5a45 | Kevin Wolf | return ret;
|
138 | 893a9cb4 | Christoph Hellwig | } |
139 | 893a9cb4 | Christoph Hellwig | return 0; |
140 | ea2384d3 | bellard | } |
141 | ea2384d3 | bellard | |
142 | 276cbc7f | Paolo Bonzini | #define BITS_PER_BITMAP_SECTOR (512 * 8) |
143 | 276cbc7f | Paolo Bonzini | |
144 | 276cbc7f | Paolo Bonzini | /* Cannot use bitmap.c on big-endian machines. */
|
145 | 276cbc7f | Paolo Bonzini | static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap) |
146 | ea2384d3 | bellard | { |
147 | 276cbc7f | Paolo Bonzini | return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0; |
148 | 276cbc7f | Paolo Bonzini | } |
149 | ea2384d3 | bellard | |
150 | 276cbc7f | Paolo Bonzini | static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors) |
151 | 276cbc7f | Paolo Bonzini | { |
152 | 276cbc7f | Paolo Bonzini | int streak_value = value ? 0xFF : 0; |
153 | 276cbc7f | Paolo Bonzini | int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR);
|
154 | 276cbc7f | Paolo Bonzini | int bitnum = start;
|
155 | 276cbc7f | Paolo Bonzini | while (bitnum < last) {
|
156 | 276cbc7f | Paolo Bonzini | if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) { |
157 | 276cbc7f | Paolo Bonzini | bitnum += 8;
|
158 | 276cbc7f | Paolo Bonzini | continue;
|
159 | 276cbc7f | Paolo Bonzini | } |
160 | 276cbc7f | Paolo Bonzini | if (cow_test_bit(bitnum, bitmap) == value) {
|
161 | 276cbc7f | Paolo Bonzini | bitnum++; |
162 | 276cbc7f | Paolo Bonzini | continue;
|
163 | 276cbc7f | Paolo Bonzini | } |
164 | 276cbc7f | Paolo Bonzini | break;
|
165 | 893a9cb4 | Christoph Hellwig | } |
166 | 276cbc7f | Paolo Bonzini | return MIN(bitnum, last) - start;
|
167 | 893a9cb4 | Christoph Hellwig | } |
168 | ea2384d3 | bellard | |
169 | ea2384d3 | bellard | /* Return true if first block has been changed (ie. current version is
|
170 | ea2384d3 | bellard | * in COW file). Set the number of continuous blocks for which that
|
171 | ea2384d3 | bellard | * is true. */
|
172 | 81145834 | Stefan Hajnoczi | static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs, |
173 | 81145834 | Stefan Hajnoczi | int64_t sector_num, int nb_sectors, int *num_same) |
174 | ea2384d3 | bellard | { |
175 | 276cbc7f | Paolo Bonzini | int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; |
176 | 276cbc7f | Paolo Bonzini | uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
177 | 276cbc7f | Paolo Bonzini | uint8_t bitmap[BDRV_SECTOR_SIZE]; |
178 | 276cbc7f | Paolo Bonzini | int ret;
|
179 | ea2384d3 | bellard | int changed;
|
180 | ea2384d3 | bellard | |
181 | 276cbc7f | Paolo Bonzini | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
182 | 276cbc7f | Paolo Bonzini | if (ret < 0) { |
183 | 276cbc7f | Paolo Bonzini | return ret;
|
184 | ea2384d3 | bellard | } |
185 | ea2384d3 | bellard | |
186 | 276cbc7f | Paolo Bonzini | bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
187 | 276cbc7f | Paolo Bonzini | changed = cow_test_bit(bitnum, bitmap); |
188 | 276cbc7f | Paolo Bonzini | *num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors); |
189 | ea2384d3 | bellard | return changed;
|
190 | ea2384d3 | bellard | } |
191 | ea2384d3 | bellard | |
192 | b6b8a333 | Paolo Bonzini | static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs,
|
193 | b6b8a333 | Paolo Bonzini | int64_t sector_num, int nb_sectors, int *num_same) |
194 | b6b8a333 | Paolo Bonzini | { |
195 | 4bc74be9 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
196 | 4bc74be9 | Paolo Bonzini | int ret = cow_co_is_allocated(bs, sector_num, nb_sectors, num_same);
|
197 | 4bc74be9 | Paolo Bonzini | int64_t offset = s->cow_sectors_offset + (sector_num << BDRV_SECTOR_BITS); |
198 | 4bc74be9 | Paolo Bonzini | if (ret < 0) { |
199 | 4bc74be9 | Paolo Bonzini | return ret;
|
200 | 4bc74be9 | Paolo Bonzini | } |
201 | 4bc74be9 | Paolo Bonzini | return (ret ? BDRV_BLOCK_DATA : 0) | offset | BDRV_BLOCK_OFFSET_VALID; |
202 | b6b8a333 | Paolo Bonzini | } |
203 | b6b8a333 | Paolo Bonzini | |
204 | 893a9cb4 | Christoph Hellwig | static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, |
205 | 893a9cb4 | Christoph Hellwig | int nb_sectors)
|
206 | ea2384d3 | bellard | { |
207 | 893a9cb4 | Christoph Hellwig | int error = 0; |
208 | 893a9cb4 | Christoph Hellwig | int i;
|
209 | 26ae9804 | Paolo Bonzini | bool first = true; |
210 | 893a9cb4 | Christoph Hellwig | |
211 | 893a9cb4 | Christoph Hellwig | for (i = 0; i < nb_sectors; i++) { |
212 | 26ae9804 | Paolo Bonzini | error = cow_set_bit(bs, sector_num + i, &first); |
213 | 893a9cb4 | Christoph Hellwig | if (error) {
|
214 | 893a9cb4 | Christoph Hellwig | break;
|
215 | 893a9cb4 | Christoph Hellwig | } |
216 | 893a9cb4 | Christoph Hellwig | } |
217 | 893a9cb4 | Christoph Hellwig | |
218 | 893a9cb4 | Christoph Hellwig | return error;
|
219 | ea2384d3 | bellard | } |
220 | ea2384d3 | bellard | |
221 | e94d1387 | Stefan Hajnoczi | static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num, |
222 | e94d1387 | Stefan Hajnoczi | uint8_t *buf, int nb_sectors)
|
223 | ea2384d3 | bellard | { |
224 | ea2384d3 | bellard | BDRVCowState *s = bs->opaque; |
225 | ea2384d3 | bellard | int ret, n;
|
226 | 3b46e624 | ths | |
227 | ea2384d3 | bellard | while (nb_sectors > 0) { |
228 | d663640c | Paolo Bonzini | ret = cow_co_is_allocated(bs, sector_num, nb_sectors, &n); |
229 | d663640c | Paolo Bonzini | if (ret < 0) { |
230 | d663640c | Paolo Bonzini | return ret;
|
231 | d663640c | Paolo Bonzini | } |
232 | d663640c | Paolo Bonzini | if (ret) {
|
233 | 2063392a | Christoph Hellwig | ret = bdrv_pread(bs->file, |
234 | 2063392a | Christoph Hellwig | s->cow_sectors_offset + sector_num * 512,
|
235 | 2063392a | Christoph Hellwig | buf, n * 512);
|
236 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
237 | 16d2fc00 | Li Zhi Hui | return ret;
|
238 | 16d2fc00 | Li Zhi Hui | } |
239 | ea2384d3 | bellard | } else {
|
240 | 83f64091 | bellard | if (bs->backing_hd) {
|
241 | 83f64091 | bellard | /* read from the base image */
|
242 | 83f64091 | bellard | ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
243 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
244 | 16d2fc00 | Li Zhi Hui | return ret;
|
245 | 16d2fc00 | Li Zhi Hui | } |
246 | 83f64091 | bellard | } else {
|
247 | 16d2fc00 | Li Zhi Hui | memset(buf, 0, n * 512); |
248 | 16d2fc00 | Li Zhi Hui | } |
249 | 83f64091 | bellard | } |
250 | ea2384d3 | bellard | nb_sectors -= n; |
251 | ea2384d3 | bellard | sector_num += n; |
252 | ea2384d3 | bellard | buf += n * 512;
|
253 | ea2384d3 | bellard | } |
254 | ea2384d3 | bellard | return 0; |
255 | ea2384d3 | bellard | } |
256 | ea2384d3 | bellard | |
257 | 2914caa0 | Paolo Bonzini | static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num, |
258 | 2914caa0 | Paolo Bonzini | uint8_t *buf, int nb_sectors)
|
259 | 2914caa0 | Paolo Bonzini | { |
260 | 2914caa0 | Paolo Bonzini | int ret;
|
261 | 2914caa0 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
262 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_lock(&s->lock); |
263 | 2914caa0 | Paolo Bonzini | ret = cow_read(bs, sector_num, buf, nb_sectors); |
264 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_unlock(&s->lock); |
265 | 2914caa0 | Paolo Bonzini | return ret;
|
266 | 2914caa0 | Paolo Bonzini | } |
267 | 2914caa0 | Paolo Bonzini | |
268 | 5fafdf24 | ths | static int cow_write(BlockDriverState *bs, int64_t sector_num, |
269 | ea2384d3 | bellard | const uint8_t *buf, int nb_sectors) |
270 | ea2384d3 | bellard | { |
271 | ea2384d3 | bellard | BDRVCowState *s = bs->opaque; |
272 | 893a9cb4 | Christoph Hellwig | int ret;
|
273 | 3b46e624 | ths | |
274 | 2063392a | Christoph Hellwig | ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
|
275 | 2063392a | Christoph Hellwig | buf, nb_sectors * 512);
|
276 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
277 | 16d2fc00 | Li Zhi Hui | return ret;
|
278 | 16d2fc00 | Li Zhi Hui | } |
279 | 893a9cb4 | Christoph Hellwig | |
280 | 893a9cb4 | Christoph Hellwig | return cow_update_bitmap(bs, sector_num, nb_sectors);
|
281 | ea2384d3 | bellard | } |
282 | ea2384d3 | bellard | |
283 | e183ef75 | Paolo Bonzini | static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num, |
284 | e183ef75 | Paolo Bonzini | const uint8_t *buf, int nb_sectors) |
285 | e183ef75 | Paolo Bonzini | { |
286 | e183ef75 | Paolo Bonzini | int ret;
|
287 | e183ef75 | Paolo Bonzini | BDRVCowState *s = bs->opaque; |
288 | e183ef75 | Paolo Bonzini | qemu_co_mutex_lock(&s->lock); |
289 | e183ef75 | Paolo Bonzini | ret = cow_write(bs, sector_num, buf, nb_sectors); |
290 | e183ef75 | Paolo Bonzini | qemu_co_mutex_unlock(&s->lock); |
291 | e183ef75 | Paolo Bonzini | return ret;
|
292 | e183ef75 | Paolo Bonzini | } |
293 | e183ef75 | Paolo Bonzini | |
294 | e2731add | bellard | static void cow_close(BlockDriverState *bs) |
295 | ea2384d3 | bellard | { |
296 | ea2384d3 | bellard | } |
297 | ea2384d3 | bellard | |
298 | d5124c00 | Max Reitz | static int cow_create(const char *filename, QEMUOptionParameter *options, |
299 | d5124c00 | Max Reitz | Error **errp) |
300 | ea2384d3 | bellard | { |
301 | ea2384d3 | bellard | struct cow_header_v2 cow_header;
|
302 | ea2384d3 | bellard | struct stat st;
|
303 | 0e7e1989 | Kevin Wolf | int64_t image_sectors = 0;
|
304 | 0e7e1989 | Kevin Wolf | const char *image_filename = NULL; |
305 | 34b5d2c6 | Max Reitz | Error *local_err = NULL;
|
306 | 31f38120 | Kirill A. Shutemov | int ret;
|
307 | 3535a9c6 | Li Zhi Hui | BlockDriverState *cow_bs; |
308 | 0e7e1989 | Kevin Wolf | |
309 | 0e7e1989 | Kevin Wolf | /* Read out options */
|
310 | 0e7e1989 | Kevin Wolf | while (options && options->name) {
|
311 | 0e7e1989 | Kevin Wolf | if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
312 | 0e7e1989 | Kevin Wolf | image_sectors = options->value.n / 512;
|
313 | 0e7e1989 | Kevin Wolf | } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { |
314 | 0e7e1989 | Kevin Wolf | image_filename = options->value.s; |
315 | 0e7e1989 | Kevin Wolf | } |
316 | 0e7e1989 | Kevin Wolf | options++; |
317 | 0e7e1989 | Kevin Wolf | } |
318 | ea2384d3 | bellard | |
319 | cc84d90f | Max Reitz | ret = bdrv_create_file(filename, options, &local_err); |
320 | 3535a9c6 | Li Zhi Hui | if (ret < 0) { |
321 | cc84d90f | Max Reitz | qerror_report_err(local_err); |
322 | cc84d90f | Max Reitz | error_free(local_err); |
323 | 3535a9c6 | Li Zhi Hui | return ret;
|
324 | 3535a9c6 | Li Zhi Hui | } |
325 | 3535a9c6 | Li Zhi Hui | |
326 | 34b5d2c6 | Max Reitz | ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
327 | 3535a9c6 | Li Zhi Hui | if (ret < 0) { |
328 | 34b5d2c6 | Max Reitz | qerror_report_err(local_err); |
329 | 34b5d2c6 | Max Reitz | error_free(local_err); |
330 | 3535a9c6 | Li Zhi Hui | return ret;
|
331 | 3535a9c6 | Li Zhi Hui | } |
332 | 3535a9c6 | Li Zhi Hui | |
333 | ea2384d3 | bellard | memset(&cow_header, 0, sizeof(cow_header)); |
334 | ea2384d3 | bellard | cow_header.magic = cpu_to_be32(COW_MAGIC); |
335 | ea2384d3 | bellard | cow_header.version = cpu_to_be32(COW_VERSION); |
336 | ea2384d3 | bellard | if (image_filename) {
|
337 | 83f64091 | bellard | /* Note: if no file, we put a dummy mtime */
|
338 | 83f64091 | bellard | cow_header.mtime = cpu_to_be32(0);
|
339 | 83f64091 | bellard | |
340 | 3535a9c6 | Li Zhi Hui | if (stat(image_filename, &st) != 0) { |
341 | 83f64091 | bellard | goto mtime_fail;
|
342 | ea2384d3 | bellard | } |
343 | ea2384d3 | bellard | cow_header.mtime = cpu_to_be32(st.st_mtime); |
344 | 83f64091 | bellard | mtime_fail:
|
345 | 83f64091 | bellard | pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
346 | 83f64091 | bellard | image_filename); |
347 | ea2384d3 | bellard | } |
348 | ea2384d3 | bellard | cow_header.sectorsize = cpu_to_be32(512);
|
349 | ea2384d3 | bellard | cow_header.size = cpu_to_be64(image_sectors * 512);
|
350 | 3535a9c6 | Li Zhi Hui | ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header)); |
351 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
352 | 31f38120 | Kirill A. Shutemov | goto exit;
|
353 | 31f38120 | Kirill A. Shutemov | } |
354 | 31f38120 | Kirill A. Shutemov | |
355 | ea2384d3 | bellard | /* resize to include at least all the bitmap */
|
356 | 3535a9c6 | Li Zhi Hui | ret = bdrv_truncate(cow_bs, |
357 | 3535a9c6 | Li Zhi Hui | sizeof(cow_header) + ((image_sectors + 7) >> 3)); |
358 | 16d2fc00 | Li Zhi Hui | if (ret < 0) { |
359 | 31f38120 | Kirill A. Shutemov | goto exit;
|
360 | 31f38120 | Kirill A. Shutemov | } |
361 | 31f38120 | Kirill A. Shutemov | |
362 | 31f38120 | Kirill A. Shutemov | exit:
|
363 | 4f6fd349 | Fam Zheng | bdrv_unref(cow_bs); |
364 | 31f38120 | Kirill A. Shutemov | return ret;
|
365 | ea2384d3 | bellard | } |
366 | ea2384d3 | bellard | |
367 | 0e7e1989 | Kevin Wolf | static QEMUOptionParameter cow_create_options[] = {
|
368 | db08adf5 | Kevin Wolf | { |
369 | db08adf5 | Kevin Wolf | .name = BLOCK_OPT_SIZE, |
370 | db08adf5 | Kevin Wolf | .type = OPT_SIZE, |
371 | db08adf5 | Kevin Wolf | .help = "Virtual disk size"
|
372 | db08adf5 | Kevin Wolf | }, |
373 | db08adf5 | Kevin Wolf | { |
374 | db08adf5 | Kevin Wolf | .name = BLOCK_OPT_BACKING_FILE, |
375 | db08adf5 | Kevin Wolf | .type = OPT_STRING, |
376 | db08adf5 | Kevin Wolf | .help = "File name of a base image"
|
377 | db08adf5 | Kevin Wolf | }, |
378 | 0e7e1989 | Kevin Wolf | { NULL }
|
379 | 0e7e1989 | Kevin Wolf | }; |
380 | 0e7e1989 | Kevin Wolf | |
381 | 5efa9d5a | Anthony Liguori | static BlockDriver bdrv_cow = {
|
382 | c68b89ac | Kevin Wolf | .format_name = "cow",
|
383 | c68b89ac | Kevin Wolf | .instance_size = sizeof(BDRVCowState),
|
384 | c68b89ac | Kevin Wolf | |
385 | c68b89ac | Kevin Wolf | .bdrv_probe = cow_probe, |
386 | c68b89ac | Kevin Wolf | .bdrv_open = cow_open, |
387 | c68b89ac | Kevin Wolf | .bdrv_close = cow_close, |
388 | c68b89ac | Kevin Wolf | .bdrv_create = cow_create, |
389 | 3ac21627 | Peter Lieven | .bdrv_has_zero_init = bdrv_has_zero_init_1, |
390 | c68b89ac | Kevin Wolf | |
391 | c68b89ac | Kevin Wolf | .bdrv_read = cow_co_read, |
392 | c68b89ac | Kevin Wolf | .bdrv_write = cow_co_write, |
393 | b6b8a333 | Paolo Bonzini | .bdrv_co_get_block_status = cow_co_get_block_status, |
394 | 0e7e1989 | Kevin Wolf | |
395 | 0e7e1989 | Kevin Wolf | .create_options = cow_create_options, |
396 | ea2384d3 | bellard | }; |
397 | 5efa9d5a | Anthony Liguori | |
398 | 5efa9d5a | Anthony Liguori | static void bdrv_cow_init(void) |
399 | 5efa9d5a | Anthony Liguori | { |
400 | 5efa9d5a | Anthony Liguori | bdrv_register(&bdrv_cow); |
401 | 5efa9d5a | Anthony Liguori | } |
402 | 5efa9d5a | Anthony Liguori | |
403 | 5efa9d5a | Anthony Liguori | block_init(bdrv_cow_init); |