Statistics
| Branch: | Revision:

root / block.c @ 4bb2fcc7

History | View | Annotate | Download (13.3 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
#include "cow.h"
49

    
50
struct BlockDriverState {
51
    int fd; /* if -1, only COW mappings */
52
    int64_t total_sectors;
53
    int read_only; /* if true, the media is read only */
54
    int inserted; /* if true, the media is present */
55
    int removable; /* if true, the media can be removed */
56
    int locked;    /* if true, the media cannot temporarily be ejected */
57
    /* event callback when inserting/removing */
58
    void (*change_cb)(void *opaque);
59
    void *change_opaque;
60

    
61
    uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
62
    uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
63
    int cow_bitmap_size;
64
    int cow_fd;
65
    int64_t cow_sectors_offset;
66
    int boot_sector_enabled;
67
    uint8_t boot_sector_data[512];
68

    
69
    char filename[1024];
70
    
71
    /* NOTE: the following infos are only hints for real hardware
72
       drivers. They are not used by the block driver */
73
    int cyls, heads, secs;
74
    int type;
75
    char device_name[32];
76
    BlockDriverState *next;
77
};
78

    
79
static BlockDriverState *bdrv_first;
80

    
81
/* create a new block device (by default it is empty) */
82
BlockDriverState *bdrv_new(const char *device_name)
83
{
84
    BlockDriverState **pbs, *bs;
85

    
86
    bs = qemu_mallocz(sizeof(BlockDriverState));
87
    if(!bs)
88
        return NULL;
89
    pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
90
    /* insert at the end */
91
    pbs = &bdrv_first;
92
    while (*pbs != NULL)
93
        pbs = &(*pbs)->next;
94
    *pbs = bs;
95
    return bs;
96
}
97

    
98
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
99
{
100
    int fd, cow_fd;
101
    int64_t size;
102
    char template[] = "/tmp/vl.XXXXXX";
103
    struct cow_header_v2 cow_header;
104
    struct stat st;
105

    
106
    bs->read_only = 0;
107
    bs->fd = -1;
108
    bs->cow_fd = -1;
109
    bs->cow_bitmap = NULL;
110
    strcpy(bs->filename, filename);
111

    
112
    /* open standard HD image */
113
    fd = open(filename, O_RDWR | O_LARGEFILE);
114
    if (fd < 0) {
115
        /* read only image on disk */
116
        fd = open(filename, O_RDONLY | O_LARGEFILE);
117
        if (fd < 0) {
118
            perror(filename);
119
            goto fail;
120
        }
121
        if (!snapshot)
122
            bs->read_only = 1;
123
    }
124
    bs->fd = fd;
125

    
126
    /* see if it is a cow image */
127
    if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
128
        fprintf(stderr, "%s: could not read header\n", filename);
129
        goto fail;
130
    }
131
    if (cow_header.magic == htonl(COW_MAGIC) &&
132
        cow_header.version == htonl(COW_VERSION)) {
133
        /* cow image found */
134
        size = cow_header.size;
135
#ifndef WORDS_BIGENDIAN
136
        size = bswap64(size);
137
#endif    
138
        bs->total_sectors = size / 512;
139

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

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

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

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

    
206
void bdrv_close(BlockDriverState *bs)
207
{
208
    if (bs->inserted) {
209
        /* we unmap the mapping so that it is written to the COW file */
210
        if (bs->cow_bitmap_addr)
211
            munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
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_info(void)
474
{
475
    BlockDriverState *bs;
476

    
477
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
478
        term_printf("%s:", bs->device_name);
479
        term_printf(" type=");
480
        switch(bs->type) {
481
        case BDRV_TYPE_HD:
482
            term_printf("hd");
483
            break;
484
        case BDRV_TYPE_CDROM:
485
            term_printf("cdrom");
486
            break;
487
        case BDRV_TYPE_FLOPPY:
488
            term_printf("floppy");
489
            break;
490
        }
491
        term_printf(" removable=%d", bs->removable);
492
        if (bs->removable) {
493
            term_printf(" locked=%d", bs->locked);
494
        }
495
        if (bs->inserted) {
496
            term_printf(" file=%s", bs->filename);
497
            term_printf(" ro=%d", bs->read_only);
498
        } else {
499
            term_printf(" [not inserted]");
500
        }
501
        term_printf("\n");
502
    }
503
}