Revision 33e3963e block.c

b/block.c
38 38
#include <sys/poll.h>
39 39
#include <errno.h>
40 40
#include <sys/wait.h>
41
#include <netinet/in.h>
41 42

  
42 43
#include "vl.h"
43 44

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

  
44 48
struct BlockDriverState {
45
    int fd;
49
    int fd; /* if -1, only COW mappings */
46 50
    int64_t total_sectors;
47 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];
48 59
};
49 60

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

  
56 70
    bs = malloc(sizeof(BlockDriverState));
57 71
    if(!bs)
58 72
        return NULL;
59 73
    bs->read_only = 0;
60
    fd = open(filename, O_RDWR);
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);
61 81
    if (fd < 0) {
62
        fd = open(filename, O_RDONLY);
82
        /* read only image on disk */
83
        fd = open(filename, O_RDONLY | O_LARGEFILE);
63 84
        if (fd < 0) {
64
            close(fd);
65
            free(bs);
66
            return NULL;
85
            perror(filename);
86
            goto fail;
67 87
        }
68
        bs->read_only = 1;
88
        if (!snapshot)
89
            bs->read_only = 1;
69 90
    }
70
    size = lseek64(fd, 0, SEEK_END);
71
    bs->total_sectors = size / 512;
72 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
    
73 161
    return bs;
162
 fail:
163
    bdrv_close(bs);
164
    return NULL;
74 165
}
75 166

  
76 167
void bdrv_close(BlockDriverState *bs)
77 168
{
78
    close(bs->fd);
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);
79 176
    free(bs);
80 177
}
81 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

  
82 254
/* return -1 if error */
83 255
int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
84 256
              uint8_t *buf, int nb_sectors)
85 257
{
86
    int ret;
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
        }
87 269

  
88
    lseek64(bs->fd, sector_num * 512, SEEK_SET);
89
    ret = read(bs->fd, buf, nb_sectors * 512);
90
    if (ret != nb_sectors * 512)
91
        return -1;
92
    else
93
        return 0;
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;
94 286
}
95 287

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

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

  
105
    lseek64(bs->fd, sector_num * 512, SEEK_SET);
106
    ret = write(bs->fd, buf, nb_sectors * 512);
107
    if (ret != nb_sectors * 512)
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) {
108 309
        return -1;
109
    else
110
        return 0;
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;
111 321
}
112 322

  
113 323
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)

Also available in: Unified diff