1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #ifndef _WIN32
25: #include "qemu-common.h"
26: #include "block_int.h"
27: #include <sys/mman.h>
28:
29:
30:
31:
32:
33: #define COW_MAGIC 0x4f4f4f4d
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;
48: uint8_t *cow_bitmap_addr;
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:
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:
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:
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:
124:
125:
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:
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:
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:
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