source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/block-cow.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 8.0 KB
Line 
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 "vl.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
36struct 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
45typedef 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
53static 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
65static int cow_open(BlockDriverState *bs, const char *filename)
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#if 0
97    if (cow_header.backing_file[0] != '\0') {
98        if (stat(cow_header.backing_file, &st) != 0) {
99            fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
100            goto fail;
101        }
102        if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
103            fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
104            goto fail;
105            }
106        fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
107        if (fd < 0)
108            goto fail;
109        bs->fd = fd;
110    }
111#endif
112    /* mmap the bitmap */
113    s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
114    s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), 
115                              s->cow_bitmap_size, 
116                              PROT_READ | PROT_WRITE,
117                              MAP_SHARED, s->fd, 0);
118    if (s->cow_bitmap_addr == MAP_FAILED)
119        goto fail;
120    s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
121    s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
122    return 0;
123 fail:
124    close(fd);
125    return -1;
126}
127
128static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
129{
130    bitmap[bitnum / 8] |= (1 << (bitnum%8));
131}
132
133static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
134{
135    return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
136}
137
138
139/* Return true if first block has been changed (ie. current version is
140 * in COW file).  Set the number of continuous blocks for which that
141 * is true. */
142static inline int is_changed(uint8_t *bitmap,
143                             int64_t sector_num, int nb_sectors,
144                             int *num_same)
145{
146    int changed;
147
148    if (!bitmap || nb_sectors == 0) {
149        *num_same = nb_sectors;
150        return 0;
151    }
152
153    changed = is_bit_set(bitmap, sector_num);
154    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
155        if (is_bit_set(bitmap, sector_num + *num_same) != changed)
156            break;
157    }
158
159    return changed;
160}
161
162static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
163                            int nb_sectors, int *pnum)
164{
165    BDRVCowState *s = bs->opaque;
166    return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
167}
168
169static int cow_read(BlockDriverState *bs, int64_t sector_num, 
170                    uint8_t *buf, int nb_sectors)
171{
172    BDRVCowState *s = bs->opaque;
173    int ret, n;
174   
175    while (nb_sectors > 0) {
176        if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
177            lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
178            ret = read(s->fd, buf, n * 512);
179            if (ret != n * 512) 
180                return -1;
181        } else {
182            memset(buf, 0, n * 512);
183        }
184        nb_sectors -= n;
185        sector_num += n;
186        buf += n * 512;
187    }
188    return 0;
189}
190
191static int cow_write(BlockDriverState *bs, int64_t sector_num, 
192                     const uint8_t *buf, int nb_sectors)
193{
194    BDRVCowState *s = bs->opaque;
195    int ret, i;
196   
197    lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
198    ret = write(s->fd, buf, nb_sectors * 512);
199    if (ret != nb_sectors * 512) 
200        return -1;
201    for (i = 0; i < nb_sectors; i++)
202        cow_set_bit(s->cow_bitmap, sector_num + i);
203    return 0;
204}
205
206static void cow_close(BlockDriverState *bs)
207{
208    BDRVCowState *s = bs->opaque;
209    munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
210    close(s->fd);
211}
212
213static int cow_create(const char *filename, int64_t image_sectors,
214                      const char *image_filename, int flags)
215{
216    int fd, cow_fd;
217    struct cow_header_v2 cow_header;
218    struct stat st;
219
220    if (flags)
221        return -ENOTSUP;
222
223    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
224              0644);
225    if (cow_fd < 0)
226        return -1;
227    memset(&cow_header, 0, sizeof(cow_header));
228    cow_header.magic = cpu_to_be32(COW_MAGIC);
229    cow_header.version = cpu_to_be32(COW_VERSION);
230    if (image_filename) {
231        fd = open(image_filename, O_RDONLY | O_BINARY);
232        if (fd < 0) {
233            close(cow_fd);
234            return -1;
235        }
236        if (fstat(fd, &st) != 0) {
237            close(fd);
238            return -1;
239        }
240        close(fd);
241        cow_header.mtime = cpu_to_be32(st.st_mtime);
242        realpath(image_filename, cow_header.backing_file);
243    }
244    cow_header.sectorsize = cpu_to_be32(512);
245    cow_header.size = cpu_to_be64(image_sectors * 512);
246    write(cow_fd, &cow_header, sizeof(cow_header));
247    /* resize to include at least all the bitmap */
248    ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
249    close(cow_fd);
250    return 0;
251}
252
253static void cow_flush(BlockDriverState *bs)
254{
255    BDRVCowState *s = bs->opaque;
256    fsync(s->fd);
257}
258
259BlockDriver bdrv_cow = {
260    "cow",
261    sizeof(BDRVCowState),
262    cow_probe,
263    cow_open,
264    cow_read,
265    cow_write,
266    cow_close,
267    cow_create,
268    cow_flush,
269    cow_is_allocated,
270};
271#endif
Note: See TracBrowser for help on using the repository browser.