Statistics
| Branch: | Revision:

root / block.c @ 3e11db9a

History | View | Annotate | Download (13.4 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 "vl.h"
25

    
26
#ifndef _WIN32
27
#include <sys/mman.h>
28
#endif
29

    
30
#include "cow.h"
31

    
32
struct BlockDriverState {
33
    int fd; /* if -1, only COW mappings */
34
    int64_t total_sectors;
35
    int read_only; /* if true, the media is read only */
36
    int inserted; /* if true, the media is present */
37
    int removable; /* if true, the media can be removed */
38
    int locked;    /* if true, the media cannot temporarily be ejected */
39
    /* event callback when inserting/removing */
40
    void (*change_cb)(void *opaque);
41
    void *change_opaque;
42

    
43
    uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
44
    uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
45
    int cow_bitmap_size;
46
    int cow_fd;
47
    int64_t cow_sectors_offset;
48
    int boot_sector_enabled;
49
    uint8_t boot_sector_data[512];
50

    
51
    char filename[1024];
52
    
53
    /* NOTE: the following infos are only hints for real hardware
54
       drivers. They are not used by the block driver */
55
    int cyls, heads, secs;
56
    int type;
57
    char device_name[32];
58
    BlockDriverState *next;
59
};
60

    
61
static BlockDriverState *bdrv_first;
62

    
63
/* create a new block device (by default it is empty) */
64
BlockDriverState *bdrv_new(const char *device_name)
65
{
66
    BlockDriverState **pbs, *bs;
67

    
68
    bs = qemu_mallocz(sizeof(BlockDriverState));
69
    if(!bs)
70
        return NULL;
71
    pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
72
    /* insert at the end */
73
    pbs = &bdrv_first;
74
    while (*pbs != NULL)
75
        pbs = &(*pbs)->next;
76
    *pbs = bs;
77
    return bs;
78
}
79

    
80
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
81
{
82
    int fd;
83
    int64_t size;
84
    struct cow_header_v2 cow_header;
85
#ifndef _WIN32
86
    char template[] = "/tmp/vl.XXXXXX";
87
    int cow_fd;
88
    struct stat st;
89
#endif
90

    
91
    bs->read_only = 0;
92
    bs->fd = -1;
93
    bs->cow_fd = -1;
94
    bs->cow_bitmap = NULL;
95
    pstrcpy(bs->filename, sizeof(bs->filename), filename);
96

    
97
    /* open standard HD image */
98
#ifdef _WIN32
99
    fd = open(filename, O_RDWR | O_BINARY);
100
#else
101
    fd = open(filename, O_RDWR | O_LARGEFILE);
102
#endif
103
    if (fd < 0) {
104
        /* read only image on disk */
105
#ifdef _WIN32
106
        fd = open(filename, O_RDONLY | O_BINARY);
107
#else
108
        fd = open(filename, O_RDONLY | O_LARGEFILE);
109
#endif
110
        if (fd < 0) {
111
            perror(filename);
112
            goto fail;
113
        }
114
        if (!snapshot)
115
            bs->read_only = 1;
116
    }
117
    bs->fd = fd;
118

    
119
    /* see if it is a cow image */
120
    if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
121
        fprintf(stderr, "%s: could not read header\n", filename);
122
        goto fail;
123
    }
124
#ifndef _WIN32
125
    if (be32_to_cpu(cow_header.magic) == COW_MAGIC &&
126
        be32_to_cpu(cow_header.version) == COW_VERSION) {
127
        /* cow image found */
128
        size = cow_header.size;
129
#ifndef WORDS_BIGENDIAN
130
        size = bswap64(size);
131
#endif    
132
        bs->total_sectors = size / 512;
133

    
134
        bs->cow_fd = fd;
135
        bs->fd = -1;
136
        if (cow_header.backing_file[0] != '\0') {
137
            if (stat(cow_header.backing_file, &st) != 0) {
138
                fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
139
                goto fail;
140
            }
141
            if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
142
                fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
143
                goto fail;
144
            }
145
            fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
146
            if (fd < 0)
147
                goto fail;
148
            bs->fd = fd;
149
        }
150
        /* mmap the bitmap */
151
        bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
152
        bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 
153
                                   bs->cow_bitmap_size, 
154
                                   PROT_READ | PROT_WRITE,
155
                                   MAP_SHARED, bs->cow_fd, 0);
156
        if (bs->cow_bitmap_addr == MAP_FAILED)
157
            goto fail;
158
        bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
159
        bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
160
        snapshot = 0;
161
    } else 
162
#endif
163
    {
164
        /* standard raw image */
165
        size = lseek64(fd, 0, SEEK_END);
166
        bs->total_sectors = size / 512;
167
        bs->fd = fd;
168
    }
169

    
170
#ifndef _WIN32
171
    if (snapshot) {
172
        /* create a temporary COW file */
173
        cow_fd = mkstemp64(template);
174
        if (cow_fd < 0)
175
            goto fail;
176
        bs->cow_fd = cow_fd;
177
        unlink(template);
178
        
179
        /* just need to allocate bitmap */
180
        bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
181
        bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), 
182
                                   bs->cow_bitmap_size, 
183
                                   PROT_READ | PROT_WRITE,
184
                                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
185
        if (bs->cow_bitmap_addr == MAP_FAILED)
186
            goto fail;
187
        bs->cow_bitmap = bs->cow_bitmap_addr;
188
        bs->cow_sectors_offset = 0;
189
    }
190
#endif
191
    
192
    bs->inserted = 1;
193

    
194
    /* call the change callback */
195
    if (bs->change_cb)
196
        bs->change_cb(bs->change_opaque);
197

    
198
    return 0;
199
 fail:
200
    bdrv_close(bs);
201
    return -1;
202
}
203

    
204
void bdrv_close(BlockDriverState *bs)
205
{
206
    if (bs->inserted) {
207
#ifndef _WIN32
208
        /* we unmap the mapping so that it is written to the COW file */
209
        if (bs->cow_bitmap_addr)
210
            munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
211
#endif
212
        if (bs->cow_fd >= 0)
213
            close(bs->cow_fd);
214
        if (bs->fd >= 0)
215
            close(bs->fd);
216
        bs->inserted = 0;
217

    
218
        /* call the change callback */
219
        if (bs->change_cb)
220
            bs->change_cb(bs->change_opaque);
221
    }
222
}
223

    
224
void bdrv_delete(BlockDriverState *bs)
225
{
226
    bdrv_close(bs);
227
    qemu_free(bs);
228
}
229

    
230
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
231
{
232
    bitmap[bitnum / 8] |= (1 << (bitnum%8));
233
}
234

    
235
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
236
{
237
    return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
238
}
239

    
240

    
241
/* Return true if first block has been changed (ie. current version is
242
 * in COW file).  Set the number of continuous blocks for which that
243
 * is true. */
244
static int is_changed(uint8_t *bitmap,
245
                      int64_t sector_num, int nb_sectors,
246
                      int *num_same)
247
{
248
    int changed;
249

    
250
    if (!bitmap || nb_sectors == 0) {
251
        *num_same = nb_sectors;
252
        return 0;
253
    }
254

    
255
    changed = is_bit_set(bitmap, sector_num);
256
    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
257
        if (is_bit_set(bitmap, sector_num + *num_same) != changed)
258
            break;
259
    }
260

    
261
    return changed;
262
}
263

    
264
/* commit COW file into the raw image */
265
int bdrv_commit(BlockDriverState *bs)
266
{
267
    int64_t i;
268
    uint8_t *cow_bitmap;
269

    
270
    if (!bs->inserted)
271
        return -1;
272

    
273
    if (!bs->cow_bitmap) {
274
        fprintf(stderr, "Already committed to %s\n", bs->filename);
275
        return 0;
276
    }
277

    
278
    if (bs->read_only) {
279
        fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
280
        return -1;
281
    }
282

    
283
    cow_bitmap = bs->cow_bitmap;
284
    for (i = 0; i < bs->total_sectors; i++) {
285
        if (is_bit_set(cow_bitmap, i)) {
286
            unsigned char sector[512];
287
            if (bdrv_read(bs, i, sector, 1) != 0) {
288
                fprintf(stderr, "Error reading sector %lli: aborting commit\n",
289
                        (long long)i);
290
                return -1;
291
            }
292

    
293
            /* Make bdrv_write write to real file for a moment. */
294
            bs->cow_bitmap = NULL;
295
            if (bdrv_write(bs, i, sector, 1) != 0) {
296
                fprintf(stderr, "Error writing sector %lli: aborting commit\n",
297
                        (long long)i);
298
                bs->cow_bitmap = cow_bitmap;
299
                return -1;
300
            }
301
            bs->cow_bitmap = cow_bitmap;
302
        }
303
    }
304
    fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
305
    return 0;
306
}
307

    
308
/* return -1 if error */
309
int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
310
              uint8_t *buf, int nb_sectors)
311
{
312
    int ret, n, fd;
313
    int64_t offset;
314
    
315
    if (!bs->inserted)
316
        return -1;
317

    
318
    while (nb_sectors > 0) {
319
        if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
320
            fd = bs->cow_fd;
321
            offset = bs->cow_sectors_offset;
322
        } else if (sector_num == 0 && bs->boot_sector_enabled) {
323
            memcpy(buf, bs->boot_sector_data, 512);
324
            n = 1;
325
            goto next;
326
        } else {
327
            fd = bs->fd;
328
            offset = 0;
329
        }
330

    
331
        if (fd < 0) {
332
            /* no file, just return empty sectors */
333
            memset(buf, 0, n * 512);
334
        } else {
335
            offset += sector_num * 512;
336
            lseek64(fd, offset, SEEK_SET);
337
            ret = read(fd, buf, n * 512);
338
            if (ret != n * 512) {
339
                return -1;
340
            }
341
        }
342
    next:
343
        nb_sectors -= n;
344
        sector_num += n;
345
        buf += n * 512;
346
    }
347
    return 0;
348
}
349

    
350
/* return -1 if error */
351
int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
352
               const uint8_t *buf, int nb_sectors)
353
{
354
    int ret, fd, i;
355
    int64_t offset, retl;
356
    
357
    if (!bs->inserted)
358
        return -1;
359
    if (bs->read_only)
360
        return -1;
361

    
362
    if (bs->cow_bitmap) {
363
        fd = bs->cow_fd;
364
        offset = bs->cow_sectors_offset;
365
    } else {
366
        fd = bs->fd;
367
        offset = 0;
368
    }
369
    
370
    offset += sector_num * 512;
371
    retl = lseek64(fd, offset, SEEK_SET);
372
    if (retl == -1) {
373
        return -1;
374
    }
375
    ret = write(fd, buf, nb_sectors * 512);
376
    if (ret != nb_sectors * 512) {
377
        return -1;
378
    }
379

    
380
    if (bs->cow_bitmap) {
381
        for (i = 0; i < nb_sectors; i++)
382
            set_bit(bs->cow_bitmap, sector_num + i);
383
    }
384
    return 0;
385
}
386

    
387
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
388
{
389
    *nb_sectors_ptr = bs->total_sectors;
390
}
391

    
392
/* force a given boot sector. */
393
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
394
{
395
    bs->boot_sector_enabled = 1;
396
    if (size > 512)
397
        size = 512;
398
    memcpy(bs->boot_sector_data, data, size);
399
    memset(bs->boot_sector_data + size, 0, 512 - size);
400
}
401

    
402
void bdrv_set_geometry_hint(BlockDriverState *bs, 
403
                            int cyls, int heads, int secs)
404
{
405
    bs->cyls = cyls;
406
    bs->heads = heads;
407
    bs->secs = secs;
408
}
409

    
410
void bdrv_set_type_hint(BlockDriverState *bs, int type)
411
{
412
    bs->type = type;
413
    bs->removable = ((type == BDRV_TYPE_CDROM ||
414
                      type == BDRV_TYPE_FLOPPY));
415
}
416

    
417
void bdrv_get_geometry_hint(BlockDriverState *bs, 
418
                            int *pcyls, int *pheads, int *psecs)
419
{
420
    *pcyls = bs->cyls;
421
    *pheads = bs->heads;
422
    *psecs = bs->secs;
423
}
424

    
425
int bdrv_get_type_hint(BlockDriverState *bs)
426
{
427
    return bs->type;
428
}
429

    
430
int bdrv_is_removable(BlockDriverState *bs)
431
{
432
    return bs->removable;
433
}
434

    
435
int bdrv_is_read_only(BlockDriverState *bs)
436
{
437
    return bs->read_only;
438
}
439

    
440
int bdrv_is_inserted(BlockDriverState *bs)
441
{
442
    return bs->inserted;
443
}
444

    
445
int bdrv_is_locked(BlockDriverState *bs)
446
{
447
    return bs->locked;
448
}
449

    
450
void bdrv_set_locked(BlockDriverState *bs, int locked)
451
{
452
    bs->locked = locked;
453
}
454

    
455
void bdrv_set_change_cb(BlockDriverState *bs, 
456
                        void (*change_cb)(void *opaque), void *opaque)
457
{
458
    bs->change_cb = change_cb;
459
    bs->change_opaque = opaque;
460
}
461

    
462
BlockDriverState *bdrv_find(const char *name)
463
{
464
    BlockDriverState *bs;
465

    
466
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
467
        if (!strcmp(name, bs->device_name))
468
            return bs;
469
    }
470
    return NULL;
471
}
472

    
473
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
474
{
475
    BlockDriverState *bs;
476

    
477
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
478
        it(opaque, bs->device_name);
479
    }
480
}
481

    
482
void bdrv_info(void)
483
{
484
    BlockDriverState *bs;
485

    
486
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
487
        term_printf("%s:", bs->device_name);
488
        term_printf(" type=");
489
        switch(bs->type) {
490
        case BDRV_TYPE_HD:
491
            term_printf("hd");
492
            break;
493
        case BDRV_TYPE_CDROM:
494
            term_printf("cdrom");
495
            break;
496
        case BDRV_TYPE_FLOPPY:
497
            term_printf("floppy");
498
            break;
499
        }
500
        term_printf(" removable=%d", bs->removable);
501
        if (bs->removable) {
502
            term_printf(" locked=%d", bs->locked);
503
        }
504
        if (bs->inserted) {
505
            term_printf(" file=%s", bs->filename);
506
            term_printf(" ro=%d", bs->read_only);
507
        } else {
508
            term_printf(" [not inserted]");
509
        }
510
        term_printf("\n");
511
    }
512
}