Statistics
| Branch: | Revision:

root / block.c @ b67d5959

History | View | Annotate | Download (9.1 kB)

1
/*
2
 * QEMU System Emulator block driver
3
 * 
4
 * Copyright (c) 2003 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
#include <stdlib.h>
25
#include <stdio.h>
26
#include <stdarg.h>
27
#include <string.h>
28
#include <getopt.h>
29
#include <inttypes.h>
30
#include <unistd.h>
31
#include <sys/mman.h>
32
#include <fcntl.h>
33
#include <signal.h>
34
#include <time.h>
35
#include <sys/time.h>
36
#include <malloc.h>
37
#include <termios.h>
38
#include <sys/poll.h>
39
#include <errno.h>
40
#include <sys/wait.h>
41
#include <netinet/in.h>
42

    
43
#include "vl.h"
44

    
45
#define NO_THUNK_TYPE_SIZE
46
#include "thunk.h"
47

    
48
struct BlockDriverState {
49
    int fd; /* if -1, only COW mappings */
50
    int64_t total_sectors;
51
    int read_only;
52

    
53
    uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
54
    uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
55
    int cow_bitmap_size;
56
    int cow_fd;
57
    int64_t cow_sectors_offset;
58
    char filename[1024];
59
};
60

    
61
BlockDriverState *bdrv_open(const char *filename, int snapshot)
62
{
63
    BlockDriverState *bs;
64
    int fd, cow_fd;
65
    int64_t size;
66
    char template[] = "/tmp/vl.XXXXXX";
67
    struct cow_header_v2 cow_header;
68
    struct stat st;
69

    
70
    bs = malloc(sizeof(BlockDriverState));
71
    if(!bs)
72
        return NULL;
73
    bs->read_only = 0;
74
    bs->fd = -1;
75
    bs->cow_fd = -1;
76
    bs->cow_bitmap = NULL;
77
    strcpy(bs->filename, filename);
78

    
79
    /* open standard HD image */
80
    fd = open(filename, O_RDWR | O_LARGEFILE);
81
    if (fd < 0) {
82
        /* read only image on disk */
83
        fd = open(filename, O_RDONLY | O_LARGEFILE);
84
        if (fd < 0) {
85
            perror(filename);
86
            goto fail;
87
        }
88
        if (!snapshot)
89
            bs->read_only = 1;
90
    }
91
    bs->fd = fd;
92

    
93
    /* see if it is a cow image */
94
    if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
95
        fprintf(stderr, "%s: could not read header\n", filename);
96
        goto fail;
97
    }
98
    if (cow_header.magic == htonl(COW_MAGIC) &&
99
        cow_header.version == htonl(COW_VERSION)) {
100
        /* cow image found */
101
        size = cow_header.size;
102
#ifndef WORDS_BIGENDIAN
103
        size = bswap64(size);
104
#endif    
105
        bs->total_sectors = size / 512;
106

    
107
        bs->cow_fd = fd;
108
        bs->fd = -1;
109
        if (cow_header.backing_file[0] != '\0') {
110
            if (stat(cow_header.backing_file, &st) != 0) {
111
                fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
112
                goto fail;
113
            }
114
            if (st.st_mtime != htonl(cow_header.mtime)) {
115
                fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
116
                goto fail;
117
            }
118
            fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
119
            if (fd < 0)
120
                goto fail;
121
            bs->fd = fd;
122
        }
123
        /* mmap the bitmap */
124
        bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
125
        bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 
126
                                   bs->cow_bitmap_size, 
127
                                   PROT_READ | PROT_WRITE,
128
                                   MAP_SHARED, bs->cow_fd, 0);
129
        if (bs->cow_bitmap_addr == MAP_FAILED)
130
            goto fail;
131
        bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
132
        bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
133
        snapshot = 0;
134
    } else {
135
        /* standard raw image */
136
        size = lseek64(fd, 0, SEEK_END);
137
        bs->total_sectors = size / 512;
138
        bs->fd = fd;
139
    }
140

    
141
    if (snapshot) {
142
        /* create a temporary COW file */
143
        cow_fd = mkstemp(template);
144
        if (cow_fd < 0)
145
            goto fail;
146
        bs->cow_fd = cow_fd;
147
        unlink(template);
148
        
149
        /* just need to allocate bitmap */
150
        bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
151
        bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 
152
                                   bs->cow_bitmap_size, 
153
                                   PROT_READ | PROT_WRITE,
154
                                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
155
        if (bs->cow_bitmap_addr == MAP_FAILED)
156
            goto fail;
157
        bs->cow_bitmap = bs->cow_bitmap_addr;
158
        bs->cow_sectors_offset = 0;
159
    }
160
    
161
    return bs;
162
 fail:
163
    bdrv_close(bs);
164
    return NULL;
165
}
166

    
167
void bdrv_close(BlockDriverState *bs)
168
{
169
    /* we unmap the mapping so that it is written to the COW file */
170
    if (bs->cow_bitmap_addr)
171
        munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
172
    if (bs->cow_fd >= 0)
173
        close(bs->cow_fd);
174
    if (bs->fd >= 0)
175
        close(bs->fd);
176
    free(bs);
177
}
178

    
179
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
180
{
181
    bitmap[bitnum / 8] |= (1 << (bitnum%8));
182
}
183

    
184
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
185
{
186
    return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
187
}
188

    
189

    
190
/* Return true if first block has been changed (ie. current version is
191
 * in COW file).  Set the number of continuous blocks for which that
192
 * is true. */
193
static int is_changed(uint8_t *bitmap,
194
                      int64_t sector_num, int nb_sectors,
195
                      int *num_same)
196
{
197
    int changed;
198

    
199
    if (!bitmap || nb_sectors == 0) {
200
        *num_same = nb_sectors;
201
        return 0;
202
    }
203

    
204
    changed = is_bit_set(bitmap, sector_num);
205
    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
206
        if (is_bit_set(bitmap, sector_num + *num_same) != changed)
207
            break;
208
    }
209

    
210
    return changed;
211
}
212

    
213
/* commit COW file into the raw image */
214
int bdrv_commit(BlockDriverState *bs)
215
{
216
    int64_t i;
217
    uint8_t *cow_bitmap;
218

    
219
    if (!bs->cow_bitmap) {
220
        fprintf(stderr, "Already committed to %s\n", bs->filename);
221
        return 0;
222
    }
223

    
224
    if (bs->read_only) {
225
        fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
226
        return -1;
227
    }
228

    
229
    cow_bitmap = bs->cow_bitmap;
230
    for (i = 0; i < bs->total_sectors; i++) {
231
        if (is_bit_set(cow_bitmap, i)) {
232
            unsigned char sector[512];
233
            if (bdrv_read(bs, i, sector, 1) != 0) {
234
                fprintf(stderr, "Error reading sector %lli: aborting commit\n",
235
                        (long long)i);
236
                return -1;
237
            }
238

    
239
            /* Make bdrv_write write to real file for a moment. */
240
            bs->cow_bitmap = NULL;
241
            if (bdrv_write(bs, i, sector, 1) != 0) {
242
                fprintf(stderr, "Error writing sector %lli: aborting commit\n",
243
                        (long long)i);
244
                bs->cow_bitmap = cow_bitmap;
245
                return -1;
246
            }
247
            bs->cow_bitmap = cow_bitmap;
248
        }
249
    }
250
    fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
251
    return 0;
252
}
253

    
254
/* return -1 if error */
255
int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
256
              uint8_t *buf, int nb_sectors)
257
{
258
    int ret, n, fd;
259
    int64_t offset;
260
    
261
    while (nb_sectors > 0) {
262
        if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
263
            fd = bs->cow_fd;
264
            offset = bs->cow_sectors_offset;
265
        } else {
266
            fd = bs->fd;
267
            offset = 0;
268
        }
269

    
270
        if (fd < 0) {
271
            /* no file, just return empty sectors */
272
            memset(buf, 0, n * 512);
273
        } else {
274
            offset += sector_num * 512;
275
            lseek64(fd, offset, SEEK_SET);
276
            ret = read(fd, buf, n * 512);
277
            if (ret != n * 512) {
278
                return -1;
279
            }
280
        }
281
        nb_sectors -= n;
282
        sector_num += n;
283
        buf += n * 512;
284
    }
285
    return 0;
286
}
287

    
288
/* return -1 if error */
289
int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
290
               const uint8_t *buf, int nb_sectors)
291
{
292
    int ret, fd, i;
293
    int64_t offset, retl;
294

    
295
    if (bs->read_only)
296
        return -1;
297

    
298
    if (bs->cow_bitmap) {
299
        fd = bs->cow_fd;
300
        offset = bs->cow_sectors_offset;
301
    } else {
302
        fd = bs->fd;
303
        offset = 0;
304
    }
305
    
306
    offset += sector_num * 512;
307
    retl = lseek64(fd, offset, SEEK_SET);
308
    if (retl == -1) {
309
        return -1;
310
    }
311
    ret = write(fd, buf, nb_sectors * 512);
312
    if (ret != nb_sectors * 512) {
313
        return -1;
314
    }
315

    
316
    if (bs->cow_bitmap) {
317
        for (i = 0; i < nb_sectors; i++)
318
            set_bit(bs->cow_bitmap, sector_num + i);
319
    }
320
    return 0;
321
}
322

    
323
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
324
{
325
    *nb_sectors_ptr = bs->total_sectors;
326
}