summaryrefslogtreecommitdiff
path: root/block/cow.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/cow.c')
-rw-r--r--block/cow.c98
1 files changed, 61 insertions, 37 deletions
diff --git a/block/cow.c b/block/cow.c
index 1a48ac0cba..ec9a9f72fa 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -21,11 +21,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef _WIN32
#include "qemu-common.h"
#include "block_int.h"
#include "module.h"
-#include <sys/mman.h>
/**************************************************************/
/* COW block driver using file system holes */
@@ -45,9 +43,6 @@ struct cow_header_v2 {
typedef struct BDRVCowState {
int fd;
- uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
- uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
- int cow_bitmap_size;
int64_t cow_sectors_offset;
} BDRVCowState;
@@ -68,6 +63,7 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
BDRVCowState *s = bs->opaque;
int fd;
struct cow_header_v2 cow_header;
+ int bitmap_size;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
@@ -94,61 +90,92 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
- /* mmap the bitmap */
- s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
- s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
- s->cow_bitmap_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, s->fd, 0);
- if (s->cow_bitmap_addr == MAP_FAILED)
- goto fail;
- s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
- s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
+ bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
+ s->cow_sectors_offset = (bitmap_size + 511) & ~511;
return 0;
fail:
close(fd);
return -1;
}
-static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
+/*
+ * XXX(hch): right now these functions are extremly ineffcient.
+ * We should just read the whole bitmap we'll need in one go instead.
+ */
+static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
{
- bitmap[bitnum / 8] |= (1 << (bitnum%8));
+ BDRVCowState *s = bs->opaque;
+ uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
+ uint8_t bitmap;
+
+ if (pread(s->fd, &bitmap, sizeof(bitmap), offset) !=
+ sizeof(bitmap)) {
+ return -errno;
+ }
+
+ bitmap |= (1 << (bitnum % 8));
+
+ if (pwrite(s->fd, &bitmap, sizeof(bitmap), offset) !=
+ sizeof(bitmap)) {
+ return -errno;
+ }
+ return 0;
}
-static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
+static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
{
- return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
-}
+ BDRVCowState *s = bs->opaque;
+ uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
+ uint8_t bitmap;
+ if (pread(s->fd, &bitmap, sizeof(bitmap), offset) !=
+ sizeof(bitmap)) {
+ return -errno;
+ }
+
+ return !!(bitmap & (1 << (bitnum % 8)));
+}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
-static inline int is_changed(uint8_t *bitmap,
- int64_t sector_num, int nb_sectors,
- int *num_same)
+static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int *num_same)
{
int changed;
- if (!bitmap || nb_sectors == 0) {
+ if (nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
- changed = is_bit_set(bitmap, sector_num);
+ changed = is_bit_set(bs, sector_num);
+ if (changed < 0) {
+ return 0; /* XXX: how to return I/O errors? */
+ }
+
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
- if (is_bit_set(bitmap, sector_num + *num_same) != changed)
+ if (is_bit_set(bs, sector_num + *num_same) != changed)
break;
}
return changed;
}
-static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
+static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors)
{
- BDRVCowState *s = bs->opaque;
- return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
+ int error = 0;
+ int i;
+
+ for (i = 0; i < nb_sectors; i++) {
+ error = cow_set_bit(bs, sector_num + i);
+ if (error) {
+ break;
+ }
+ }
+
+ return error;
}
static int cow_read(BlockDriverState *bs, int64_t sector_num,
@@ -158,7 +185,7 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
int ret, n;
while (nb_sectors > 0) {
- if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
+ if (cow_is_allocated(bs, sector_num, nb_sectors, &n)) {
ret = pread(s->fd, buf, n * 512,
s->cow_sectors_offset + sector_num * 512);
if (ret != n * 512)
@@ -184,21 +211,19 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
- int ret, i;
+ int ret;
ret = pwrite(s->fd, buf, nb_sectors * 512,
s->cow_sectors_offset + sector_num * 512);
if (ret != nb_sectors * 512)
return -1;
- for (i = 0; i < nb_sectors; i++)
- cow_set_bit(s->cow_bitmap, sector_num + i);
- return 0;
+
+ return cow_update_bitmap(bs, sector_num, nb_sectors);
}
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
- munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
@@ -308,4 +333,3 @@ static void bdrv_cow_init(void)
}
block_init(bdrv_cow_init);
-#endif