]> git.proxmox.com Git - qemu.git/commitdiff
Expose a mechanism to trace block writes
authorlirans@il.ibm.com <lirans@il.ibm.com>
Mon, 2 Nov 2009 13:40:41 +0000 (15:40 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Tue, 17 Nov 2009 14:03:31 +0000 (08:03 -0600)
To support live migration without shared storage we need to be able to trace
writes to disk while migrating. This Patch expose dirty block tracking per
device to be polled from upper layer.

Changes from v4:
- Register dirty tracking for each block device.
- Minor coding style issues.
- Block.c will now manage a dirty bitmap per device once
  bdrv_set_dirty_tracking() is called. Bitmap is polled by the upper
  layer (block-migration.c).

Signed-off-by: Liran Schour <lirans@il.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
block.c
block.h
block_int.h

diff --git a/block.c b/block.c
index 1e49bc05cca4c4355eec6d05e8999c814033490a..6fdabff12d1159242f55e6a5042b63db55225b67 100644 (file)
--- a/block.c
+++ b/block.c
@@ -43,6 +43,7 @@
 
 #define SECTOR_BITS 9
 #define SECTOR_SIZE (1 << SECTOR_BITS)
+#define SECTORS_PER_DIRTY_CHUNK 8
 
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -641,6 +642,18 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
     return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
 }
 
+static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
+                            int nb_sectors, int dirty)
+{
+    int64_t start, end;
+    start = sector_num / SECTORS_PER_DIRTY_CHUNK;
+    end = (sector_num + nb_sectors) / SECTORS_PER_DIRTY_CHUNK;
+    
+    for(; start <= end; start++) {
+        bs->dirty_bitmap[start] = dirty;
+    }
+}
+
 /* Return < 0 if error. Important errors are:
   -EIO         generic I/O error (may happen for all errors)
   -ENOMEDIUM   No media inserted.
@@ -657,7 +670,11 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
         return -EACCES;
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return -EIO;
-
+    
+    if(bs->dirty_tracking) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+    
     return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
 }
 
@@ -1203,6 +1220,11 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
         return -ENOTSUP;
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return -EIO;
+    
+    if(bs->dirty_tracking) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+    
     return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
 }
 
@@ -1400,6 +1422,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return NULL;
 
+    if(bs->dirty_tracking) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+    
     ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
                                cb, opaque);
 
@@ -1930,7 +1956,57 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
     return NULL;
 }
 
+
+
 void *qemu_blockalign(BlockDriverState *bs, size_t size)
 {
     return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
 }
+
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
+{
+    int64_t bitmap_size;
+    if(enable) {
+        if(bs->dirty_tracking == 0) {
+            int64_t i;
+            uint8_t test;
+            bitmap_size = (bdrv_getlength(bs) >> SECTOR_BITS);
+            bitmap_size /= SECTORS_PER_DIRTY_CHUNK;
+            bitmap_size++;
+           
+            bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+           
+            bs->dirty_tracking = enable;
+            for(i = 0; i < bitmap_size; i++) test = bs->dirty_bitmap[i]; 
+       }
+    } else {
+        if(bs->dirty_tracking != 0) {
+            qemu_free(bs->dirty_bitmap);
+            bs->dirty_tracking = enable;
+       }
+    }
+}
+
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
+{
+    int64_t chunk = sector / (int64_t)SECTORS_PER_DIRTY_CHUNK;
+    
+    if(bs->dirty_bitmap != NULL && 
+       (sector << SECTOR_BITS) <= bdrv_getlength(bs)) {
+        return bs->dirty_bitmap[chunk];
+    } else {
+        return 0;
+    }
+}
+
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, 
+                     int nr_sectors)
+{
+    set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
+}
+
+int bdrv_get_sectors_per_chunk(void)
+{
+    /* size must be 2^x */
+    return SECTORS_PER_DIRTY_CHUNK;
+}
diff --git a/block.h b/block.h
index 6b0146f7cffa2f796c66746ea8631a2de01dbf2a..2d4f066906ef3b95f272dae8ad70aae2ef476a96 100644 (file)
--- a/block.h
+++ b/block.h
@@ -80,7 +80,8 @@ void bdrv_register(BlockDriver *bdrv);
 /* async block I/O */
 typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 typedef void BlockDriverCompletionFunc(void *opaque, int ret);
-
+typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
+                                    int sector_num);
 BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
                                  QEMUIOVector *iov, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque);
@@ -187,4 +188,9 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
                       int64_t pos, int size);
 
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, 
+                     int nr_sectors);
+int bdrv_get_sectors_per_chunk(void);
 #endif
index 8e72abee0cd4dcc6c10f9a91ed38228aab4e44c1..7ebe926f5bad33b9a78e30204372c0ce14da50f0 100644 (file)
@@ -168,6 +168,8 @@ struct BlockDriverState {
     int cyls, heads, secs, translation;
     int type;
     char device_name[32];
+    int dirty_tracking;
+    uint8_t *dirty_bitmap;
     BlockDriverState *next;
     void *private;
 };