test/lvol: Snapshot and clone test cases for lvol feature.

Also move snapshot and clone test plan into implementation.

Change-Id: Ifa1f2da651305747ae24c50921deebd0266c5888
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Kaminski <pawelx.kaminski@intel.com>
Reviewed-on: https://review.gerrithub.io/392371
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Tomasz Kulasek 2018-03-08 23:09:32 +01:00 committed by Daniel Verkamp
parent 9b5fd19225
commit ebf079362b
4 changed files with 398 additions and 1 deletions

View File

@ -193,7 +193,7 @@ if [ $SPDK_TEST_LVOL -eq 1 ]; then
timing_enter lvol timing_enter lvol
test_cases="1,50,51,52,53,100,101,102,150,200,201,250,251,252,253,254,255," test_cases="1,50,51,52,53,100,101,102,150,200,201,250,251,252,253,254,255,"
test_cases+="300,301,450,451,452,550,600,601,650,651,652,654,655," test_cases+="300,301,450,451,452,550,600,601,650,651,652,654,655,"
test_cases+="700,701,800,801,802,803,804,10000" test_cases+="700,701,750,751,752,753,754,755,800,801,802,803,804,10000"
run_test ./test/lvol/lvol.sh --test-cases=$test_cases run_test ./test/lvol/lvol.sh --test-cases=$test_cases
report_test_completion "lvol" report_test_completion "lvol"
timing_exit lvol timing_exit lvol

View File

@ -58,6 +58,12 @@ function usage() {
655: 'thin_provisioning_filling_disks_less_than_lvs_size', 655: 'thin_provisioning_filling_disks_less_than_lvs_size',
700: 'tasting_positive', 700: 'tasting_positive',
701: 'tasting_lvol_store_positive', 701: 'tasting_lvol_store_positive',
750: 'snapshot_readonly',
751: 'snapshot_compare_with_lvol_bdev',
752: 'snapshot_during_io_traffic',
753: 'snapshot_of_snapshot',
754: 'clone_bdev_only',
755: 'clone_writing_clone',
800: 'rename_positive', 800: 'rename_positive',
801: 'rename_lvs_nonexistent', 801: 'rename_lvs_nonexistent',
802: 'rename_lvs_EEXIST', 802: 'rename_lvs_EEXIST',

View File

@ -200,3 +200,13 @@ class Commands_Rpc(object):
print("INFO: Renaming lvol bdev from {old} to {new}".format(old=old_name, new=new_name)) print("INFO: Renaming lvol bdev from {old} to {new}".format(old=old_name, new=new_name))
output, rc = self.rpc.rename_lvol_bdev(old_name, new_name) output, rc = self.rpc.rename_lvol_bdev(old_name, new_name)
return rc return rc
def snapshot_lvol_bdev(self, bdev_name, snapshot_name):
print("INFO: RPC COMMAND snapshot_lvol_bdev")
output, rc = self.rpc.snapshot_lvol_bdev(bdev_name, snapshot_name)
return rc
def clone_lvol_bdev(self, snapshot_name, clone_name):
print("INFO: RPC COMMAND clone_lvol_bdev")
output, rc = self.rpc.clone_lvol_bdev(snapshot_name, clone_name)
return rc

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
import io import io
import time
import sys import sys
import random import random
import signal import signal
@ -7,6 +8,7 @@ import subprocess
import pprint import pprint
import socket import socket
import threading import threading
import os
from errno import ESRCH from errno import ESRCH
from os import kill, path, unlink, path, listdir, remove from os import kill, path, unlink, path, listdir, remove
@ -125,6 +127,12 @@ def case_message(func):
655: 'thin_provisioning_filling_disks_less_than_lvs_size', 655: 'thin_provisioning_filling_disks_less_than_lvs_size',
700: 'tasting_positive', 700: 'tasting_positive',
701: 'tasting_lvol_store_positive', 701: 'tasting_lvol_store_positive',
750: 'snapshot_readonly',
751: 'snapshot_compare_with_lvol_bdev',
752: 'snapshot_during_io_traffic',
753: 'snapshot_of_snapshot',
754: 'clone_bdev_only',
755: 'clone_writing_clone',
800: 'rename_positive', 800: 'rename_positive',
801: 'rename_lvs_nonexistent', 801: 'rename_lvs_nonexistent',
802: 'rename_lvs_EEXIST', 802: 'rename_lvs_EEXIST',
@ -1235,6 +1243,379 @@ class TestCases(object):
fail_count += 1 fail_count += 1
return fail_count return fail_count
@case_message
def test_case750(self):
"""
snapshot readonly
Create snaphot of lvol bdev and check if it is readonly.
"""
fail_count = 0
nbd_name0 = "/dev/nbd0"
snapshot_name = "snapshot0"
# Construct malloc bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Construct lvol store on malloc bdev
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()[0]
free_clusters_start = int(lvs['free_clusters'])
bdev_size = int(int(lvs['cluster_size']) * int(lvs['free_clusters']) / MEGABYTE / 3)
# Create lvol bdev with 33% of lvol store space
bdev_name = self.c.construct_lvol_bdev(uuid_store, self.lbd_name,
bdev_size)
lvol_bdev = self.c.get_lvol_bdev_with_name(bdev_name)
# Create snapshot of lvol bdev
fail_count += self.c.snapshot_lvol_bdev(lvol_bdev['name'], snapshot_name)
snapshot_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name)
fail_count += self.c.start_nbd_disk(snapshot_bdev['name'], nbd_name0)
size = bdev_size * MEGABYTE
# Try to perform write operation on created snapshot
# Check if filling snapshot of lvol bdev fails
fail_count += self.run_fio_test(nbd_name0, 0, size, "write", "0xcc", 1)
fail_count += self.c.stop_nbd_disk(nbd_name0)
# Destroy lvol bdev
fail_count += self.c.delete_bdev(lvol_bdev['name'])
# Destroy snapshot
fail_count += self.c.delete_bdev(snapshot_bdev['name'])
# Destroy lvol store
fail_count += self.c.destroy_lvol_store(uuid_store)
# Delete malloc bdev
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - no other operation fails
return fail_count
@case_message
def test_case751(self):
"""
snapshot_compare_with_lvol_bdev
Check if lvol bdevs and snapshots contain the same data.
Check if lvol bdev and snapshot differ when writing to lvol bdev
after creating snapshot.
"""
fail_count = 0
nbd_name = ["/dev/nbd0", "/dev/nbd1", "/dev/nbd2", "/dev/nbd3"]
snapshot_name0 = "snapshot0"
snapshot_name1 = "snapshot1"
# Construct mallov bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Construct lvol store
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()
size = int(int(lvs[0][u'free_clusters'] * lvs[0]['cluster_size']) / 6 / MEGABYTE)
lbd_name0 = self.lbd_name + str(0)
lbd_name1 = self.lbd_name + str(1)
# Create thin provisioned lvol bdev with size less than 25% of lvs
uuid_bdev0 = self.c.construct_lvol_bdev(uuid_store,
lbd_name0, size, thin=True)
# Create thick provisioned lvol bdev with size less than 25% of lvs
uuid_bdev1 = self.c.construct_lvol_bdev(uuid_store,
lbd_name1, size, thin=False)
lvol_bdev0 = self.c.get_lvol_bdev_with_name(uuid_bdev0)
fail_count += self.c.start_nbd_disk(lvol_bdev0['name'], nbd_name[0])
fill_size = int(size * MEGABYTE / 2)
# Fill thin provisoned lvol bdev with 50% of its space
fail_count += self.run_fio_test(nbd_name[0], 0, fill_size, "write", "0xcc", 0)
lvol_bdev1 = self.c.get_lvol_bdev_with_name(uuid_bdev1)
fail_count += self.c.start_nbd_disk(lvol_bdev1['name'], nbd_name[1])
fill_size = int(size * MEGABYTE)
# Fill whole thic provisioned lvol bdev
fail_count += self.run_fio_test(nbd_name[1], 0, fill_size, "write", "0xcc", 0)
# Create snapshots of lvol bdevs
fail_count += self.c.snapshot_lvol_bdev(uuid_bdev0, snapshot_name0)
fail_count += self.c.snapshot_lvol_bdev(uuid_bdev1, snapshot_name1)
fail_count += self.c.start_nbd_disk(self.lvs_name + "/" + snapshot_name0, nbd_name[2])
fail_count += self.c.start_nbd_disk(self.lvs_name + "/" + snapshot_name1, nbd_name[3])
# Compare every lvol bdev with corresponding snapshot
# and check that data are the same
fail_count += self.compare_two_disks(nbd_name[0], nbd_name[2], 0)
fail_count += self.compare_two_disks(nbd_name[1], nbd_name[3], 0)
fill_size = int(size * MEGABYTE / 2)
offset = fill_size
# Fill second half of thin provisioned lvol bdev
fail_count += self.run_fio_test(nbd_name[0], offset, fill_size, "write", "0xaa", 0)
# Compare thin provisioned lvol bdev with its snapshot and check if it fails
fail_count += self.compare_two_disks(nbd_name[0], nbd_name[2], 1)
for nbd in nbd_name:
fail_count += self.c.stop_nbd_disk(nbd)
# Delete lvol bdevs
fail_count += self.c.delete_bdev(lvol_bdev0['name'])
fail_count += self.c.delete_bdev(lvol_bdev1['name'])
# Delete snapshots
fail_count += self.c.delete_bdev(self.lvs_name + "/" + snapshot_name0)
fail_count += self.c.delete_bdev(self.lvs_name + "/" + snapshot_name1)
# Destroy snapshot
fail_count += self.c.destroy_lvol_store(uuid_store)
# Delete malloc bdev
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - removing snapshot should always end with success
# - no other operation fails
return fail_count
@case_message
def test_case752(self):
"""
snapshot_during_io_traffic
Check that when writing to lvol bdev
creating snapshot ends with success
"""
global current_fio_pid
fail_count = 0
nbd_name = "/dev/nbd0"
snapshot_name = "snapshot"
# Create malloc bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Construct lvol store
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()
# Create thin provisioned lvol bdev with size equal to 50% of lvs space
size = int(int(lvs[0][u'free_clusters'] * lvs[0]['cluster_size']) / 2 / MEGABYTE)
uuid_bdev = self.c.construct_lvol_bdev(uuid_store, self.lbd_name,
size, thin=True)
lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev)
fail_count += self.c.start_nbd_disk(lvol_bdev['name'], nbd_name)
fill_size = int(size * MEGABYTE)
# Create thread that will run fio in background
thread = FioThread(nbd_name, 0, fill_size, "write", "0xcc", 0,
extra_params="--time_based --runtime=8")
# Perform write operation with verification to created lvol bdev
thread.start()
time.sleep(4)
fail_count += is_process_alive(current_fio_pid)
# During write operation create snapshot of created lvol bdev
# and check that snapshot has been created successfully
fail_count += self.c.snapshot_lvol_bdev(lvol_bdev['name'], snapshot_name)
fail_count += is_process_alive(current_fio_pid)
thread.join()
# Check that write operation ended with success
fail_count += thread.rv
fail_count += self.c.stop_nbd_disk(nbd_name)
# Destroy lvol bdev
fail_count += self.c.delete_bdev(lvol_bdev['name'])
# Delete snapshot
fail_count += self.c.delete_bdev(self.lvs_name + "/" + snapshot_name)
# Destroy lvol store
fail_count += self.c.destroy_lvol_store(uuid_store)
# Delete malloc bdevs
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - no other operation fails
return fail_count
@case_message
def test_case753(self):
"""
snapshot_of_snapshot
Check that creating snapshot of snapshot will fail
"""
fail_count = 0
snapshot_name0 = "snapshot0"
snapshot_name1 = "snapshot1"
# Create malloc bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Construct lvol store
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()
# Create thick provisioned lvol bdev
size = int(int(lvs[0][u'free_clusters'] * lvs[0]['cluster_size']) / 2 / MEGABYTE)
uuid_bdev = self.c.construct_lvol_bdev(uuid_store, self.lbd_name,
size, thin=False)
lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev)
# Create snapshot of created lvol bdev
fail_count += self.c.snapshot_lvol_bdev(lvol_bdev['name'], snapshot_name0)
# Create snapshot of previously created snapshot
# and check if operation will fail
if self.c.snapshot_lvol_bdev(snapshot_name0, snapshot_name1) == 0:
print("ERROR: Creating snapshot of snapshot should fail")
fail_count += 1
# Delete lvol bdev
fail_count += self.c.delete_bdev(lvol_bdev['name'])
# Destroy snapshot
fail_count += self.c.delete_bdev(self.lvs_name + "/" + snapshot_name0)
# Destroy lvol store
fail_count += self.c.destroy_lvol_store(uuid_store)
# Delete malloc bdev
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - creating snapshot of snapshot should fail
# - no other operation fails
return fail_count
@case_message
def test_case754(self):
"""
clone_bdev_only
Check that only clone of snapshot can be created.
Creating clone of lvol bdev should fail.
"""
fail_count = 0
clone_name = "clone"
snapshot_name = "snapshot"
# Create malloc bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Construct lvol store
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()
# Create thick provisioned lvol bdev with size equal to 50% of lvs space
size = int(int(lvs[0][u'free_clusters'] * lvs[0]['cluster_size']) / 2 / MEGABYTE)
uuid_bdev = self.c.construct_lvol_bdev(uuid_store, self.lbd_name,
size, thin=False)
lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev)
# Create clone of lvol bdev and check if it fails
rv = self.c.clone_lvol_bdev(lvol_bdev['name'], clone_name)
if rv == 0:
print("ERROR: Creating clone of lvol bdev ended with unexpected success")
fail_count += 1
# Create snapshot of lvol bdev
fail_count += self.c.snapshot_lvol_bdev(lvol_bdev['name'], snapshot_name)
# Create again clone of lvol bdev and check if it fails
rv = self.c.clone_lvol_bdev(lvol_bdev['name'], clone_name)
if rv == 0:
print("ERROR: Creating clone of lvol bdev ended with unexpected success")
fail_count += 1
# Create clone of snapshot and check if it ends with success
rv = self.c.clone_lvol_bdev(self.lvs_name + "/" + snapshot_name, clone_name)
if rv != 0:
print("ERROR: Creating clone of snapshot ended with unexpected failure")
fail_count += 1
clone_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + clone_name)
# Delete lvol bdev
fail_count += self.c.delete_bdev(lvol_bdev['name'])
# Destroy clone
fail_count += self.c.delete_bdev(clone_bdev['name'])
# Delete snapshot
fail_count += self.c.delete_bdev(self.lvs_name + "/" + snapshot_name)
# Delete lvol store
fail_count += self.c.destroy_lvol_store(uuid_store)
# Destroy malloc bdev
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - cloning thick provisioned lvol bdev should fail
# - no other operation fails
return fail_count
@case_message
def test_case755(self):
"""
clone_writing_to_clone
"""
fail_count = 0
nbd_name = ["/dev/nbd0", "/dev/nbd1", "/dev/nbd2", "/dev/nbd3"]
snapshot_name = "snapshot"
clone_name0 = "clone0"
clone_name1 = "clone1"
# Create malloc bdev
base_name = self.c.construct_malloc_bdev(self.total_size,
self.block_size)
# Create lvol store
uuid_store = self.c.construct_lvol_store(base_name,
self.lvs_name,
self.cluster_size)
fail_count += self.c.check_get_lvol_stores(base_name, uuid_store,
self.cluster_size)
lvs = self.c.get_lvol_stores()
size = int(int(lvs[0][u'free_clusters'] * lvs[0]['cluster_size']) / 6 / MEGABYTE)
lbd_name0 = self.lbd_name + str(0)
# Construct thick provisioned lvol bdev
uuid_bdev0 = self.c.construct_lvol_bdev(uuid_store,
lbd_name0, size, thin=False)
lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev0)
# Install lvol bdev on /dev/nbd0
fail_count += self.c.start_nbd_disk(lvol_bdev['name'], nbd_name[0])
fill_size = size * MEGABYTE
# Fill lvol bdev with 100% of its space
fail_count += self.run_fio_test(nbd_name[0], 0, fill_size, "write", "0xcc", 0)
# Create snapshot of thick provisioned lvol bdev
fail_count += self.c.snapshot_lvol_bdev(lvol_bdev['name'], snapshot_name)
snapshot_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name)
# Create two clones of created snapshot
fail_count += self.c.clone_lvol_bdev(snapshot_bdev['name'], clone_name0)
fail_count += self.c.clone_lvol_bdev(snapshot_bdev['name'], clone_name1)
lvol_clone0 = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + clone_name0)
fail_count += self.c.start_nbd_disk(lvol_clone0['name'], nbd_name[1])
fill_size = int(size * MEGABYTE / 2)
# Perform write operation to first clone
# Change first half of its space
fail_count += self.run_fio_test(nbd_name[1], 0, fill_size, "write", "0xaa", 0)
fail_count += self.c.start_nbd_disk(self.lvs_name + "/" + snapshot_name, nbd_name[2])
lvol_clone1 = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + clone_name1)
fail_count += self.c.start_nbd_disk(lvol_clone1['name'], nbd_name[3])
# Compare snapshot with second clone. Data on both bdevs should be the same
time.sleep(1)
fail_count += self.compare_two_disks(nbd_name[2], nbd_name[3], 0)
for nbd in nbd_name:
fail_count += self.c.stop_nbd_disk(nbd)
# Destroy lvol bdev
fail_count += self.c.delete_bdev(lvol_bdev['name'])
# Destroy two clones
fail_count += self.c.delete_bdev(lvol_clone0['name'])
fail_count += self.c.delete_bdev(lvol_clone1['name'])
# Delete snapshot
fail_count += self.c.delete_bdev(snapshot_bdev['name'])
# Destroy lvol store
fail_count += self.c.destroy_lvol_store(uuid_store)
# Delete malloc
fail_count += self.c.delete_bdev(base_name)
# Expected result:
# - calls successful, return code = 0
# - no other operation fails
return fail_count
@case_message @case_message
def test_case800(self): def test_case800(self):
fail_count = 0 fail_count = 0