From 037d12cf3d137e08cbb8fa698a1a9c50d20228ea Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Wed, 7 Feb 2018 14:54:40 +0100 Subject: [PATCH 2/7] Add a singleton for NVDIMM namespaces management This currently allows changing mode of the namespace and getting information about available namespaces. --- blivet/static_data/__init__.py | 1 + blivet/static_data/nvdimm.py | 152 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 blivet/static_data/nvdimm.py diff --git a/blivet/static_data/__init__.py b/blivet/static_data/__init__.py index 2c720af3..c5928ab4 100644 --- a/blivet/static_data/__init__.py +++ b/blivet/static_data/__init__.py @@ -1,3 +1,4 @@ from .lvm_info import lvs_info, pvs_info from .luks_data import luks_data from .mpath_info import mpath_members +from .nvdimm import nvdimm diff --git a/blivet/static_data/nvdimm.py b/blivet/static_data/nvdimm.py new file mode 100644 index 00000000..0644c9f6 --- /dev/null +++ b/blivet/static_data/nvdimm.py @@ -0,0 +1,152 @@ +# +# nvdimm.py - nvdimm class +# +# Copyright (C) 2018 Red Hat, Inc. All rights reserved. +# +# 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, see . +# + +import gi +gi.require_version("BlockDev", "2.0") +gi.require_version("GLib", "2.0") +from gi.repository import BlockDev +from gi.repository import GLib + +from .. import util + +import logging +log = logging.getLogger("blivet") + + +class NVDIMMDependencyGuard(util.DependencyGuard): + error_msg = "libblockdev NVDIMM functionality not available" + + def _check_avail(self): + try: + BlockDev.nvdimm_is_tech_avail(BlockDev.NVDIMMTech.NVDIMM_TECH_NAMESPACE, + BlockDev.NVDIMMTechMode.RECONFIGURE | + BlockDev.NVDIMMTechMode.QUERY | + BlockDev.NVDIMMTechMode.ACTIVATE_DEACTIVATE) + except GLib.GError: + return False + return True + +blockdev_nvdimm_required = NVDIMMDependencyGuard() + + +class NVDIMM(object): + """ NVDIMM utility class. + + .. warning:: + Since this is a singleton class, calling deepcopy() on the instance + just returns ``self`` with no copy being created. + """ + + def __init__(self): + self._namespaces = None + + # So that users can write nvdimm() to get the singleton instance + def __call__(self): + return self + + def __deepcopy__(self, memo_dict): + # pylint: disable=unused-argument + return self + + @property + def namespaces(self): + """ Dict of all NVDIMM namespaces, including dax and disabled namespaces + """ + if not self._namespaces: + self.update_namespaces_info() + + return self._namespaces + + @blockdev_nvdimm_required(critical=True, eval_mode=util.EvalMode.onetime) + def update_namespaces_info(self): + """ Update information about the namespaces + """ + namespaces = BlockDev.nvdimm_list_namespaces(idle=True) + + self._namespaces = dict((namespace.dev, namespace) for namespace in namespaces) + + def get_namespace_info(self, device): + """ Get namespace information for a device + :param str device: device name (e.g. 'pmem0') or path + """ + for info in self.namespaces.values(): + if info.blockdev == device or \ + (device.startswith("/dev/") and info.blockdev == device[5:]): + return info + + @blockdev_nvdimm_required(critical=True, eval_mode=util.EvalMode.onetime) + def enable_namespace(self, namespace): + """ Enable a namespace + :param str namespace: devname of the namespace (e.g. 'namespace0.0') + """ + + if namespace not in self.namespaces.keys(): + raise ValueError("Namespace '%s' doesn't exist." % namespace) + + BlockDev.nvdimm_namespace_enable(namespace) + + # and update our namespaces info "cache" + self.update_namespaces_info() + + @blockdev_nvdimm_required(critical=True, eval_mode=util.EvalMode.onetime) + def reconfigure_namespace(self, namespace, mode, **kwargs): + """ Change mode of the namespace + :param str namespace: devname of the namespace (e.g. 'namespace0.0') + :param str mode: new mode of the namespace (one of 'sector', 'memory', 'dax') + :keyword int sector_size: sector size when reconfiguring to the 'sector' mode + :keyword str map_location: map location when reconfiguring to the 'memory' + mode (one of 'mem', 'dev') + + .. note:: + This doesn't change state of the devicetree. It is necessary to + run reset() or populate() to make these changes visible. + """ + + if namespace not in self.namespaces.keys(): + raise ValueError("Namespace '%s' doesn't exist." % namespace) + + info = self.namespaces[namespace] + + sector_size = kwargs.get("sector_size", None) + map_location = kwargs.get("map_location", None) + + if sector_size and mode != "sector": + raise ValueError("Sector size cannot be set for selected mode '%s'." % mode) + + if map_location and mode != "memory": + raise ValueError("Map location cannot be set for selected mode '%s'." % mode) + + mode_t = BlockDev.nvdimm_namespace_get_mode_from_str(mode) + + if sector_size: + extra = {"-l": str(sector_size)} + elif map_location: + extra = {"-M": map_location} + else: + extra = None + + BlockDev.nvdimm_namespace_reconfigure(namespace, mode_t, info.enabled, extra) + + # and update our namespaces info "cache" + self.update_namespaces_info() + + +# Create nvdimm singleton +nvdimm = NVDIMM() +""" An instance of :class:`NVDIMM` """ -- 2.14.3