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_zero_extents_from_ova(tmpdir): size = 10 * 1024**2 # Create image with data, zero and hole clusters. disk = str(tmpdir.join("disk.qcow2")) qemu_img.create(disk, "qcow2", size=size) with qemu_nbd.open(disk, "qcow2") as c: c.write(0 * CLUSTER_SIZE, b"A" * CLUSTER_SIZE) c.zero(1 * CLUSTER_SIZE, CLUSTER_SIZE) c.flush() # Create OVA whith this image. ova = str(tmpdir.join("vm.ova")) with tarfile.open(ova, "w") as tar: tar.add(disk, arcname=os.path.basename(disk)) extents = list(client.extents(ova, member="disk.qcow2")) assert extents == [ ZeroExtent(start=0 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=False, hole=False), ZeroExtent(start=1 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=True, hole=False), ZeroExtent(start=2 * CLUSTER_SIZE, length=size - 2 * CLUSTER_SIZE, zero=True, hole=True), ]
def test_zero_extents_raw(tmpdir): size = 10 * 1024**2 # Create image with some data, zero and holes. image = str(tmpdir.join("image.raw")) qemu_img.create(image, "raw", size=size) with qemu_nbd.open(image, "raw") as c: c.write(0 * CLUSTER_SIZE, b"A" * CLUSTER_SIZE) c.zero(1 * CLUSTER_SIZE, CLUSTER_SIZE) c.write(2 * CLUSTER_SIZE, b"B" * CLUSTER_SIZE) c.flush() extents = list(client.extents(image)) # Note: raw files report unallocated as zero, not a a hole. assert extents == [ ZeroExtent(start=0 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=False, hole=False), ZeroExtent(start=1 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=True, hole=False), ZeroExtent(start=2 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=False, hole=False), ZeroExtent(start=3 * CLUSTER_SIZE, length=size - 3 * CLUSTER_SIZE, zero=True, hole=False), ]
def test_zero_extents_qcow2(tmpdir): size = 10 * 1024**2 # Create base image with one data and one zero cluster. base = str(tmpdir.join("base.qcow2")) qemu_img.create(base, "qcow2", size=size) 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 one data and one zero cluster. top = str(tmpdir.join("top.qcow2")) qemu_img.create( top, "qcow2", backing_file=base, backing_format="qcow2") 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() extents = list(client.extents(top)) assert extents == [ # Extents from base... ZeroExtent( start=0 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=False, hole=False), ZeroExtent( start=1 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=True, hole=False), ZeroExtent( start=2 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=True, hole=True), # Extents from top... ZeroExtent( start=3 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=False, hole=False), ZeroExtent( start=4 * CLUSTER_SIZE, length=CLUSTER_SIZE, zero=True, hole=False), # Rest of unallocated data... ZeroExtent( start=5 * CLUSTER_SIZE, length=size - 5 * CLUSTER_SIZE, zero=True, hole=True), ]
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