def test_dirty_bitmap(tmpdir): size = 1024**2 # Create image with empty bitmap. img = str(tmpdir.join("img.qcow2")) qemu_img.create(img, "qcow2", size=size) qemu_img.bitmap_add(img, "b0") # Write data to image, modifying the bitmap. with qemu_nbd.open(img, "qcow2") as c: # This will allocate one cluster. By default bitmap granularity is also # one cluster, so this will make the first extent dirty. c.write(0, b"a") c.flush() # Read dirty extents. with qemu_nbd.open(img, "qcow2", read_only=True, bitmap="b0") as c: extents = c.extents(0, size)[nbd.QEMU_DIRTY_BITMAP + "b0"] bitmap = qemu_img.info(img)["format-specific"]["data"]["bitmaps"][0] assert extents == [ nbd.Extent(length=bitmap["granularity"], flags=nbd.EXTENT_DIRTY), nbd.Extent(length=size - bitmap["granularity"], flags=0), ]
def test_add_bitmap(tmpdir): size = 10 * 1024**2 img = str(tmpdir.join("img.qcow2")) qemu_img.create(img, "qcow2", size=size) qemu_img.bitmap_add(img, "b0") bitmaps = qemu_img.info(img)["format-specific"]["data"]["bitmaps"] assert bitmaps == [ {"name": "b0", "flags": ["auto"], "granularity": 65536} ]
def test_dirty_extents(tmpdir): size = 1024**2 # Create base image with empty dirty bitmap. base = str(tmpdir.join("base.qcow2")) qemu_img.create(base, "qcow2", size=size) qemu_img.bitmap_add(base, "b0") # Write data, modifying the dirty bitmap. with qemu_nbd.open(base, "qcow2") as c: c.write(0 * CLUSTER_SIZE, b"A" * CLUSTER_SIZE) c.zero(1 * CLUSTER_SIZE, CLUSTER_SIZE) c.flush() # Create top image with empty dirty bitmap. top = str(tmpdir.join("top.qcow2")) qemu_img.create(top, "qcow2", backing_file=base, backing_format="qcow2") qemu_img.bitmap_add(top, "b0") # Write data, modifying the dirty bitmap. with qemu_nbd.open(top, "qcow2") as c: c.write(3 * CLUSTER_SIZE, b"B" * CLUSTER_SIZE) c.zero(4 * CLUSTER_SIZE, CLUSTER_SIZE) c.flush() dirty_extents = list(client.extents(base, bitmap="b0")) assert dirty_extents == [ DirtyExtent(start=0 * CLUSTER_SIZE, length=2 * CLUSTER_SIZE, dirty=True), DirtyExtent(start=2 * CLUSTER_SIZE, length=size - 2 * CLUSTER_SIZE, dirty=False), ] dirty_extents = list(client.extents(top, bitmap="b0")) # Note: qemu-nbd reports dirty extents only for the top image. assert dirty_extents == [ DirtyExtent(start=0 * CLUSTER_SIZE, length=3 * CLUSTER_SIZE, dirty=False), DirtyExtent(start=3 * CLUSTER_SIZE, length=2 * CLUSTER_SIZE, dirty=True), DirtyExtent(start=5 * CLUSTER_SIZE, length=size - 5 * CLUSTER_SIZE, dirty=False), ]
def test_dirty_extents(tmpdir): size = 1024**2 # Create base image with empty dirty bitmap. base = str(tmpdir.join("base.qcow2")) qemu_img.create(base, "qcow2", size=size) qemu_img.bitmap_add(base, "b0") # Write data, modifying the dirty bitmap. with qemu_nbd.open(base, "qcow2") as c: c.write(0 * CLUSTER_SIZE, b"A" * CLUSTER_SIZE) c.zero(1 * CLUSTER_SIZE, CLUSTER_SIZE) c.flush() # Create top image with empty dirty bitmap. top = str(tmpdir.join("top.qcow2")) qemu_img.create(top, "qcow2", backing_file=base, backing_format="qcow2") qemu_img.bitmap_add(top, "b0") # Write data, modifying the dirty bitmap. with qemu_nbd.open(top, "qcow2") as c: c.write(3 * CLUSTER_SIZE, b"B" * CLUSTER_SIZE) c.zero(4 * CLUSTER_SIZE, CLUSTER_SIZE) c.flush() dirty_extents = list(client.extents(base, bitmap="b0")) expected = [ # First cluster is dirty data. DirtyExtent( start=0 * CLUSTER_SIZE, length=1 * CLUSTER_SIZE, dirty=True, zero=False), # Second cluster is dirty zero. DirtyExtent( start=1 * CLUSTER_SIZE, length=1 * CLUSTER_SIZE, dirty=True, zero=True), # Third cluster is clean zero. DirtyExtent( start=2 * CLUSTER_SIZE, length=size - 2 * CLUSTER_SIZE, dirty=False, zero=True), ] log.debug("base image dirty extents: %s", dirty_extents) assert dirty_extents == expected dirty_extents = list(client.extents(top, bitmap="b0")) # Note: qemu-nbd reports dirty extents only for the top image, but zero # extents are read from the base image. expected = [ # First cluster is clean data, read from base image. DirtyExtent( start=0 * CLUSTER_SIZE, length=1 * CLUSTER_SIZE, dirty=False, zero=False), # Second and third clusters are read from base image. Because they are # both clean zero, they are merged. DirtyExtent( start=1 * CLUSTER_SIZE, length=2 * CLUSTER_SIZE, dirty=False, zero=True), # Forth cluster is a data extent modified in top image. DirtyExtent( start=3 * CLUSTER_SIZE, length=1 * CLUSTER_SIZE, dirty=True, zero=False), # Fifth cluster is a zero extent modifed in to image. DirtyExtent( start=4 * CLUSTER_SIZE, length=1 * CLUSTER_SIZE, dirty=True, zero=True), # The rest is clean zero extent. DirtyExtent( start=5 * CLUSTER_SIZE, length=size - 5 * CLUSTER_SIZE, dirty=False, zero=True), ] log.debug("top image dirty extents: %s", dirty_extents) assert dirty_extents == expected