Revision 893a9cb4 block/cow.c

b/block/cow.c
21 21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 22
 * THE SOFTWARE.
23 23
 */
24
#ifndef _WIN32
25 24
#include "qemu-common.h"
26 25
#include "block_int.h"
27 26
#include "module.h"
28
#include <sys/mman.h>
29 27

  
30 28
/**************************************************************/
31 29
/* COW block driver using file system holes */
......
45 43

  
46 44
typedef struct BDRVCowState {
47 45
    int fd;
48
    uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
49
    uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
50
    int cow_bitmap_size;
51 46
    int64_t cow_sectors_offset;
52 47
} BDRVCowState;
53 48

  
......
68 63
    BDRVCowState *s = bs->opaque;
69 64
    int fd;
70 65
    struct cow_header_v2 cow_header;
66
    int bitmap_size;
71 67
    int64_t size;
72 68

  
73 69
    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
......
94 90
    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
95 91
            cow_header.backing_file);
96 92

  
97
    /* mmap the bitmap */
98
    s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
99
    s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
100
                                      s->cow_bitmap_size,
101
                                      PROT_READ | PROT_WRITE,
102
                                      MAP_SHARED, s->fd, 0);
103
    if (s->cow_bitmap_addr == MAP_FAILED)
104
        goto fail;
105
    s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
106
    s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
93
    bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
94
    s->cow_sectors_offset = (bitmap_size + 511) & ~511;
107 95
    return 0;
108 96
 fail:
109 97
    close(fd);
110 98
    return -1;
111 99
}
112 100

  
113
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
101
/*
102
 * XXX(hch): right now these functions are extremly ineffcient.
103
 * We should just read the whole bitmap we'll need in one go instead.
104
 */
105
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
114 106
{
115
    bitmap[bitnum / 8] |= (1 << (bitnum%8));
107
    BDRVCowState *s = bs->opaque;
108
    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
109
    uint8_t bitmap;
110

  
111
    if (pread(s->fd, &bitmap, sizeof(bitmap), offset) !=
112
	    sizeof(bitmap)) {
113
       return -errno;
114
    }
115

  
116
    bitmap |= (1 << (bitnum % 8));
117

  
118
    if (pwrite(s->fd, &bitmap, sizeof(bitmap), offset) !=
119
	    sizeof(bitmap)) {
120
       return -errno;
121
    }
122
    return 0;
116 123
}
117 124

  
118
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
125
static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
119 126
{
120
    return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
121
}
127
    BDRVCowState *s = bs->opaque;
128
    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
129
    uint8_t bitmap;
122 130

  
131
    if (pread(s->fd, &bitmap, sizeof(bitmap), offset) !=
132
	    sizeof(bitmap)) {
133
       return -errno;
134
    }
135

  
136
    return !!(bitmap & (1 << (bitnum % 8)));
137
}
123 138

  
124 139
/* Return true if first block has been changed (ie. current version is
125 140
 * in COW file).  Set the number of continuous blocks for which that
126 141
 * is true. */
127
static inline int is_changed(uint8_t *bitmap,
128
                             int64_t sector_num, int nb_sectors,
129
                             int *num_same)
142
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
143
        int nb_sectors, int *num_same)
130 144
{
131 145
    int changed;
132 146

  
133
    if (!bitmap || nb_sectors == 0) {
147
    if (nb_sectors == 0) {
134 148
	*num_same = nb_sectors;
135 149
	return 0;
136 150
    }
137 151

  
138
    changed = is_bit_set(bitmap, sector_num);
152
    changed = is_bit_set(bs, sector_num);
153
    if (changed < 0) {
154
        return 0; /* XXX: how to return I/O errors? */
155
    }
156

  
139 157
    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
140
	if (is_bit_set(bitmap, sector_num + *num_same) != changed)
158
	if (is_bit_set(bs, sector_num + *num_same) != changed)
141 159
	    break;
142 160
    }
143 161

  
144 162
    return changed;
145 163
}
146 164

  
147
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
148
                            int nb_sectors, int *pnum)
165
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
166
        int nb_sectors)
149 167
{
150
    BDRVCowState *s = bs->opaque;
151
    return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
168
    int error = 0;
169
    int i;
170

  
171
    for (i = 0; i < nb_sectors; i++) {
172
        error = cow_set_bit(bs, sector_num + i);
173
        if (error) {
174
            break;
175
        }
176
    }
177

  
178
    return error;
152 179
}
153 180

  
154 181
static int cow_read(BlockDriverState *bs, int64_t sector_num,
......
158 185
    int ret, n;
159 186

  
160 187
    while (nb_sectors > 0) {
161
        if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
188
        if (cow_is_allocated(bs, sector_num, nb_sectors, &n)) {
162 189
            ret = pread(s->fd, buf, n * 512,
163 190
                        s->cow_sectors_offset + sector_num * 512);
164 191
            if (ret != n * 512)
......
184 211
                     const uint8_t *buf, int nb_sectors)
185 212
{
186 213
    BDRVCowState *s = bs->opaque;
187
    int ret, i;
214
    int ret;
188 215

  
189 216
    ret = pwrite(s->fd, buf, nb_sectors * 512,
190 217
                 s->cow_sectors_offset + sector_num * 512);
191 218
    if (ret != nb_sectors * 512)
192 219
        return -1;
193
    for (i = 0; i < nb_sectors; i++)
194
        cow_set_bit(s->cow_bitmap, sector_num + i);
195
    return 0;
220

  
221
    return cow_update_bitmap(bs, sector_num, nb_sectors);
196 222
}
197 223

  
198 224
static void cow_close(BlockDriverState *bs)
199 225
{
200 226
    BDRVCowState *s = bs->opaque;
201
    munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
202 227
    close(s->fd);
203 228
}
204 229

  
......
308 333
}
309 334

  
310 335
block_init(bdrv_cow_init);
311
#endif

Also available in: Unified diff