|
1 /* |
|
2 * Block driver for the COW format |
|
3 * |
|
4 * Copyright (c) 2004 Fabrice Bellard |
|
5 * |
|
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: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
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 |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 #ifndef _WIN32 |
|
25 #include "qemu-common.h" |
|
26 #include "block_int.h" |
|
27 #include <sys/mman.h> |
|
28 |
|
29 /**************************************************************/ |
|
30 /* COW block driver using file system holes */ |
|
31 |
|
32 /* user mode linux compatible COW file */ |
|
33 #define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
|
34 #define COW_VERSION 2 |
|
35 |
|
36 struct cow_header_v2 { |
|
37 uint32_t magic; |
|
38 uint32_t version; |
|
39 char backing_file[1024]; |
|
40 int32_t mtime; |
|
41 uint64_t size; |
|
42 uint32_t sectorsize; |
|
43 }; |
|
44 |
|
45 typedef struct BDRVCowState { |
|
46 int fd; |
|
47 uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ |
|
48 uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ |
|
49 int cow_bitmap_size; |
|
50 int64_t cow_sectors_offset; |
|
51 } BDRVCowState; |
|
52 |
|
53 static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
54 { |
|
55 const struct cow_header_v2 *cow_header = (const void *)buf; |
|
56 |
|
57 if (buf_size >= sizeof(struct cow_header_v2) && |
|
58 be32_to_cpu(cow_header->magic) == COW_MAGIC && |
|
59 be32_to_cpu(cow_header->version) == COW_VERSION) |
|
60 return 100; |
|
61 else |
|
62 return 0; |
|
63 } |
|
64 |
|
65 static int cow_open(BlockDriverState *bs, const char *filename, int flags) |
|
66 { |
|
67 BDRVCowState *s = bs->opaque; |
|
68 int fd; |
|
69 struct cow_header_v2 cow_header; |
|
70 int64_t size; |
|
71 |
|
72 fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); |
|
73 if (fd < 0) { |
|
74 fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
|
75 if (fd < 0) |
|
76 return -1; |
|
77 } |
|
78 s->fd = fd; |
|
79 /* see if it is a cow image */ |
|
80 if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { |
|
81 goto fail; |
|
82 } |
|
83 |
|
84 if (be32_to_cpu(cow_header.magic) != COW_MAGIC || |
|
85 be32_to_cpu(cow_header.version) != COW_VERSION) { |
|
86 goto fail; |
|
87 } |
|
88 |
|
89 /* cow image found */ |
|
90 size = be64_to_cpu(cow_header.size); |
|
91 bs->total_sectors = size / 512; |
|
92 |
|
93 pstrcpy(bs->backing_file, sizeof(bs->backing_file), |
|
94 cow_header.backing_file); |
|
95 |
|
96 /* mmap the bitmap */ |
|
97 s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
|
98 s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), |
|
99 s->cow_bitmap_size, |
|
100 PROT_READ | PROT_WRITE, |
|
101 MAP_SHARED, s->fd, 0); |
|
102 if (s->cow_bitmap_addr == MAP_FAILED) |
|
103 goto fail; |
|
104 s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header); |
|
105 s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511; |
|
106 return 0; |
|
107 fail: |
|
108 close(fd); |
|
109 return -1; |
|
110 } |
|
111 |
|
112 static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum) |
|
113 { |
|
114 bitmap[bitnum / 8] |= (1 << (bitnum%8)); |
|
115 } |
|
116 |
|
117 static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) |
|
118 { |
|
119 return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); |
|
120 } |
|
121 |
|
122 |
|
123 /* Return true if first block has been changed (ie. current version is |
|
124 * in COW file). Set the number of continuous blocks for which that |
|
125 * is true. */ |
|
126 static inline int is_changed(uint8_t *bitmap, |
|
127 int64_t sector_num, int nb_sectors, |
|
128 int *num_same) |
|
129 { |
|
130 int changed; |
|
131 |
|
132 if (!bitmap || nb_sectors == 0) { |
|
133 *num_same = nb_sectors; |
|
134 return 0; |
|
135 } |
|
136 |
|
137 changed = is_bit_set(bitmap, sector_num); |
|
138 for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { |
|
139 if (is_bit_set(bitmap, sector_num + *num_same) != changed) |
|
140 break; |
|
141 } |
|
142 |
|
143 return changed; |
|
144 } |
|
145 |
|
146 static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, |
|
147 int nb_sectors, int *pnum) |
|
148 { |
|
149 BDRVCowState *s = bs->opaque; |
|
150 return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum); |
|
151 } |
|
152 |
|
153 static int cow_read(BlockDriverState *bs, int64_t sector_num, |
|
154 uint8_t *buf, int nb_sectors) |
|
155 { |
|
156 BDRVCowState *s = bs->opaque; |
|
157 int ret, n; |
|
158 |
|
159 while (nb_sectors > 0) { |
|
160 if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) { |
|
161 lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); |
|
162 ret = read(s->fd, buf, n * 512); |
|
163 if (ret != n * 512) |
|
164 return -1; |
|
165 } else { |
|
166 if (bs->backing_hd) { |
|
167 /* read from the base image */ |
|
168 ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
|
169 if (ret < 0) |
|
170 return -1; |
|
171 } else { |
|
172 memset(buf, 0, n * 512); |
|
173 } |
|
174 } |
|
175 nb_sectors -= n; |
|
176 sector_num += n; |
|
177 buf += n * 512; |
|
178 } |
|
179 return 0; |
|
180 } |
|
181 |
|
182 static int cow_write(BlockDriverState *bs, int64_t sector_num, |
|
183 const uint8_t *buf, int nb_sectors) |
|
184 { |
|
185 BDRVCowState *s = bs->opaque; |
|
186 int ret, i; |
|
187 |
|
188 lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); |
|
189 ret = write(s->fd, buf, nb_sectors * 512); |
|
190 if (ret != nb_sectors * 512) |
|
191 return -1; |
|
192 for (i = 0; i < nb_sectors; i++) |
|
193 cow_set_bit(s->cow_bitmap, sector_num + i); |
|
194 return 0; |
|
195 } |
|
196 |
|
197 static void cow_close(BlockDriverState *bs) |
|
198 { |
|
199 BDRVCowState *s = bs->opaque; |
|
200 munmap(s->cow_bitmap_addr, s->cow_bitmap_size); |
|
201 close(s->fd); |
|
202 } |
|
203 |
|
204 static int cow_create(const char *filename, int64_t image_sectors, |
|
205 const char *image_filename, int flags) |
|
206 { |
|
207 int fd, cow_fd; |
|
208 struct cow_header_v2 cow_header; |
|
209 struct stat st; |
|
210 |
|
211 if (flags) |
|
212 return -ENOTSUP; |
|
213 |
|
214 cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, |
|
215 0644); |
|
216 if (cow_fd < 0) |
|
217 return -1; |
|
218 memset(&cow_header, 0, sizeof(cow_header)); |
|
219 cow_header.magic = cpu_to_be32(COW_MAGIC); |
|
220 cow_header.version = cpu_to_be32(COW_VERSION); |
|
221 if (image_filename) { |
|
222 /* Note: if no file, we put a dummy mtime */ |
|
223 cow_header.mtime = cpu_to_be32(0); |
|
224 |
|
225 fd = open(image_filename, O_RDONLY | O_BINARY); |
|
226 if (fd < 0) { |
|
227 close(cow_fd); |
|
228 goto mtime_fail; |
|
229 } |
|
230 if (fstat(fd, &st) != 0) { |
|
231 close(fd); |
|
232 goto mtime_fail; |
|
233 } |
|
234 close(fd); |
|
235 cow_header.mtime = cpu_to_be32(st.st_mtime); |
|
236 mtime_fail: |
|
237 pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file), |
|
238 image_filename); |
|
239 } |
|
240 cow_header.sectorsize = cpu_to_be32(512); |
|
241 cow_header.size = cpu_to_be64(image_sectors * 512); |
|
242 write(cow_fd, &cow_header, sizeof(cow_header)); |
|
243 /* resize to include at least all the bitmap */ |
|
244 ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); |
|
245 close(cow_fd); |
|
246 return 0; |
|
247 } |
|
248 |
|
249 static void cow_flush(BlockDriverState *bs) |
|
250 { |
|
251 BDRVCowState *s = bs->opaque; |
|
252 fsync(s->fd); |
|
253 } |
|
254 |
|
255 BlockDriver bdrv_cow = { |
|
256 "cow", |
|
257 sizeof(BDRVCowState), |
|
258 cow_probe, |
|
259 cow_open, |
|
260 cow_read, |
|
261 cow_write, |
|
262 cow_close, |
|
263 cow_create, |
|
264 cow_flush, |
|
265 cow_is_allocated, |
|
266 }; |
|
267 #endif |