[PATCH V2 15/46] nvmftests-nvmf: add support for host ns
Chaitanya Kulkarni
ckulkarnilinux at gmail.com
Tue Oct 24 18:30:32 PDT 2017
From: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
This adds a new class to handle the host namespace operations.
Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
.../selftests/nvmftests/nvmf/host/host_ns.py | 262 +++++++++++++++++++++
1 file changed, 262 insertions(+)
create mode 100644 tools/testing/selftests/nvmftests/nvmf/host/host_ns.py
diff --git a/tools/testing/selftests/nvmftests/nvmf/host/host_ns.py b/tools/testing/selftests/nvmftests/nvmf/host/host_ns.py
new file mode 100644
index 0000000..42d6f6b
--- /dev/null
+++ b/tools/testing/selftests/nvmftests/nvmf/host/host_ns.py
@@ -0,0 +1,262 @@
+# Copyright (c) 2016-2017 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
+#
+""" Represents NVMe Over Fabric Host Namespace.
+"""
+
+import Queue
+import time
+import copy
+import threading
+
+from utils.fs import Ext4FS
+from utils.log import Log
+from utils.shell import Cmd
+
+
+class NVMFNSThread(threading.Thread):
+ """
+ Represents a worker thread.
+
+ - Attributes :
+ - target : thread Target.
+ - workq : workqueue shared between producer and worker thread.
+ """
+ def __init__(self, group=None, target=None, name=None,
+ args=[], kwargs=None, verbose=None):
+ """Default Thread Constructor."""
+ super(NVMFNSThread, self).__init__()
+ self.target = target
+ self.name = name
+ self.workq = args[0]
+ self.q_cond_var = args[1]
+
+ def run(self):
+ """ Default Thread Function """
+ while True:
+ with self.q_cond_var:
+ # if queue is empty wait
+ if self.workq.empty():
+ self.q_cond_var.wait()
+
+ # get the item from the queue if None exit
+ # use None as signal to exit worker queue
+ item = self.workq.get()
+ if item is None:
+ break
+
+ ret = item['THREAD'](item)
+ # On Error just shutdown the worker thread
+ # complete all the remaining operations and quit
+ if ret is False:
+ self.workq.put(None)
+
+
+class NVMFHostNamespace(object):
+ """
+ Represents a host namespace.
+
+ - Attributes :
+ - ns_dev : block device associated with this namespace.
+ - mount_path : mounted directory.
+ - worker_thread : handle for io worker thread.
+ - workq : workqueue shared between producer and worker thread.
+ - q_cond_var : condition variable for queue operations.
+ - fs_type : file system type for mkfs.
+ - fs : file system object.
+ """
+ def __init__(self, ns_dev):
+ self.ns_dev = ns_dev
+ self.mount_path = None
+ self.worker_thread = None
+ self.workq = Queue.Queue()
+ self.q_cond_var = threading.Condition()
+ self.fs_type = None
+ self.fs = None
+ self.logger = Log.get_logger(__name__, 'host_ns')
+
+ def init(self):
+ """ Create worker thread.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False on failure.
+ """
+ if self.id_ns() is False:
+ return False
+
+ # Create worker thread for this ns
+ self.worker_thread = NVMFNSThread(args=[self.workq, self.q_cond_var])
+ self.worker_thread.setDaemon(True)
+ self.worker_thread.start()
+ return True
+
+ def id_ns(self):
+ """ Wrapper for id-ns command.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False on failure.
+ """
+ id_ns_cmd = "nvme id-ns " + self.ns_dev
+ return Cmd.exec_cmd(id_ns_cmd)
+
+ def ns_descs(self):
+ """ Wrapper for ns-descs command.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False on failure.
+ """
+ ns_descs_cmd = "nvme ns-descs " + self.ns_dev
+ return Cmd.exec_cmd(ns_descs_cmd)
+
+ def get_ns_id(self):
+ """ Wrapper for get-ns-id command.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False on failure.
+ """
+ get_ns_id_cmd = "nvme get-ns-id " + self.ns_dev
+ return Cmd.exec_cmd(get_ns_id_cmd)
+
+ def mkfs(self, fs_type):
+ """ Format namespace with file system and mount on the unique
+ namespace directory.
+ - Args :
+ - fs_type : file system type.
+ - Returns :
+ - True on success, False on failure.
+ """
+ if fs_type == "ext4":
+ self.fs = Ext4FS(self.ns_dev)
+ if self.fs.mkfs() is True and self.fs.mount() is True:
+ return True
+ else:
+ self.logger.error("mkfs failed for " + self.ns_dev + ".")
+ return False
+ else:
+ self.logger.error("file system is not supported.")
+
+ return False
+
+ def run_fs_ios(self, iocfg):
+ """ Run IOs on mounted file system.
+ - Args :
+ - iocfg : io configuration.
+ - Returns :
+ - True on success, False on failure.
+ """
+ if self.fs.is_mounted() is False:
+ return False
+
+ mount_path = self.fs.get_mount_path()
+ iocfg['directory'] = mount_path + "/"
+
+ if self.worker_thread.is_alive():
+ with self.q_cond_var:
+ self.workq.put(iocfg)
+ self.q_cond_var.notifyAll()
+ else:
+ self.logger.error("worker thread is not running.")
+ return False
+ return True
+
+ def start_io(self, iocfg):
+ """ Add new work IO item to workqueue and notify worker thread.
+ - Args :
+ - IO Configuration passed to worker thread.
+ - Returns :
+ - True on success, False on failure.
+ """
+ iocfg = copy.deepcopy(iocfg)
+ self.logger.info(iocfg)
+ if iocfg['IO_TYPE'] == 'dd':
+ if iocfg['IODIR'] == "read":
+ iocfg['IF'] = self.ns_dev
+ elif iocfg['IODIR'] == "write":
+ iocfg['OF'] = self.ns_dev
+ else:
+ self.logger.error("io config " + iocfg + " not supported.")
+ return False
+ elif iocfg['IO_TYPE'] == 'fio':
+ iocfg['filename'] = self.ns_dev
+ else:
+ self.logger.error("invalid IO type " + iocfg['IO_TYPE'])
+ if self.worker_thread.is_alive():
+ with self.q_cond_var:
+ self.workq.put(iocfg)
+ self.q_cond_var.notifyAll()
+ else:
+ self.logger.error("worker thread is not running.")
+ return False
+
+ return True
+
+ def wait_io(self):
+ """ Wait until queue is empty.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False otherwise.
+ """
+ self.logger.info("Checking for worker thread " + self.ns_dev + ".")
+ if self.worker_thread.is_alive():
+ self.logger.info("Waiting for thread " + self.ns_dev + ".")
+ while not self.workq.empty() and \
+ self.worker_thread.is_alive() is True:
+ # Wait till waorker thread is alive.
+ time.sleep(1)
+ else:
+ self.logger.error("worker thread is not alive")
+ return False
+ self.logger.info("# WAIT COMPLETE " + self.ns_dev + ".")
+ return True
+
+ def unmount_cleanup(self):
+ """ Unmount the namespace and cleanup the mount path.
+ - Args :
+ - None.
+ - Returns :
+ - True on success, False on failure.
+ """
+ if self.fs is not None:
+ return self.fs.umount()
+
+ return True
+
+ def delete(self):
+ """ Namespace clanup.
+ - Args :
+ - None.
+ - Returns :
+ - None.
+ """
+ self.logger.info("delete ns waiting for workq to finish all items")
+ if self.worker_thread.is_alive():
+ with self.q_cond_var:
+ self.workq.put(None)
+ self.q_cond_var.notifyAll()
+
+ while not self.workq.empty() and \
+ self.worker_thread.is_alive() is True:
+ time.sleep(1)
+
+ self.unmount_cleanup()
--
1.8.3.1
More information about the Linux-nvme
mailing list