Statistics
| Branch: | Revision:

root / block.c @ 97eb5b14

History | View | Annotate | Download (9.6 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
    int boot_sector_enabled;
59
    uint8_t boot_sector_data[512];
60

    
61
    char filename[1024];
62
};
63

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

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

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

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

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

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

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

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

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

    
192

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

    
202
    if (!bitmap || nb_sectors == 0) {
203
        *num_same = nb_sectors;
204
        return 0;
205
    }
206

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

    
213
    return changed;
214
}
215

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

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

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

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

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

    
257
/* return -1 if error */
258
int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
259
              uint8_t *buf, int nb_sectors)
260
{
261
    int ret, n, fd;
262
    int64_t offset;
263
    
264
    while (nb_sectors > 0) {
265
        if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
266
            fd = bs->cow_fd;
267
            offset = bs->cow_sectors_offset;
268
        } else if (sector_num == 0 && bs->boot_sector_enabled) {
269
            memcpy(buf, bs->boot_sector_data, 512);
270
            n = 1;
271
            goto next;
272
        } else {
273
            fd = bs->fd;
274
            offset = 0;
275
        }
276

    
277
        if (fd < 0) {
278
            /* no file, just return empty sectors */
279
            memset(buf, 0, n * 512);
280
        } else {
281
            offset += sector_num * 512;
282
            lseek64(fd, offset, SEEK_SET);
283
            ret = read(fd, buf, n * 512);
284
            if (ret != n * 512) {
285
                return -1;
286
            }
287
        }
288
    next:
289
        nb_sectors -= n;
290
        sector_num += n;
291
        buf += n * 512;
292
    }
293
    return 0;
294
}
295

    
296
/* return -1 if error */
297
int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
298
               const uint8_t *buf, int nb_sectors)
299
{
300
    int ret, fd, i;
301
    int64_t offset, retl;
302
    
303
    if (bs->read_only)
304
        return -1;
305

    
306
    if (bs->cow_bitmap) {
307
        fd = bs->cow_fd;
308
        offset = bs->cow_sectors_offset;
309
    } else {
310
        fd = bs->fd;
311
        offset = 0;
312
    }
313
    
314
    offset += sector_num * 512;
315
    retl = lseek64(fd, offset, SEEK_SET);
316
    if (retl == -1) {
317
        return -1;
318
    }
319
    ret = write(fd, buf, nb_sectors * 512);
320
    if (ret != nb_sectors * 512) {
321
        return -1;
322
    }
323

    
324
    if (bs->cow_bitmap) {
325
        for (i = 0; i < nb_sectors; i++)
326
            set_bit(bs->cow_bitmap, sector_num + i);
327
    }
328
    return 0;
329
}
330

    
331
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
332
{
333
    *nb_sectors_ptr = bs->total_sectors;
334
}
335

    
336
/* force a given boot sector. */
337
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
338
{
339
    bs->boot_sector_enabled = 1;
340
    if (size > 512)
341
        size = 512;
342
    memcpy(bs->boot_sector_data, data, size);
343
    memset(bs->boot_sector_data + size, 0, 512 - size);
344
}