Blame src/plugins/nvdimm.c

Packit 2ba279
/*
Packit 2ba279
 * Copyright (C) 2018  Red Hat, Inc.
Packit 2ba279
 *
Packit 2ba279
 * This library is free software; you can redistribute it and/or
Packit 2ba279
 * modify it under the terms of the GNU Lesser General Public
Packit 2ba279
 * License as published by the Free Software Foundation; either
Packit 2ba279
 * version 2.1 of the License, or (at your option) any later version.
Packit 2ba279
 *
Packit 2ba279
 * This library is distributed in the hope that it will be useful,
Packit 2ba279
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 2ba279
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 2ba279
 * Lesser General Public License for more details.
Packit 2ba279
 *
Packit 2ba279
 * You should have received a copy of the GNU Lesser General Public
Packit 2ba279
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 2ba279
 *
Packit 2ba279
 * Author: Vojtech Trefny <vtrefny@redhat.com>
Packit 2ba279
 */
Packit 2ba279
Packit 2ba279
#include <glib.h>
Packit 2ba279
#include <blockdev/utils.h>
Packit 2ba279
#include <ndctl/libndctl.h>
Packit 2ba279
#include <uuid.h>
Packit 2ba279
#include <string.h>
Packit 2ba279
Packit 2ba279
#include "nvdimm.h"
Packit 2ba279
#include "check_deps.h"
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * SECTION: nvdimm
Packit 2ba279
 * @short_description: plugin for operations with nvdimm space
Packit 2ba279
 * @title: NVDIMM
Packit 2ba279
 * @include: nvdimm.h
Packit 2ba279
 *
Packit 2ba279
 * A plugin for operations with NVDIMM devices.
Packit 2ba279
 */
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_error_quark: (skip)
Packit 2ba279
 */
Packit 2ba279
GQuark bd_nvdimm_error_quark (void) {
Packit 2ba279
    return g_quark_from_static_string ("g-bd-nvdimm-error-quark");
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
void bd_nvdimm_namespace_info_free (BDNVDIMMNamespaceInfo *info) {
Packit 2ba279
    if (info == NULL)
Packit 2ba279
        return;
Packit 2ba279
Packit 2ba279
    g_free (info->dev);
Packit 2ba279
    g_free (info->uuid);
Packit 2ba279
    g_free (info->blockdev);
Packit 2ba279
    g_free (info);
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info_copy (BDNVDIMMNamespaceInfo *info) {
Packit 2ba279
    if (info == NULL)
Packit 2ba279
        return NULL;
Packit 2ba279
Packit 2ba279
    BDNVDIMMNamespaceInfo *new_info = g_new0 (BDNVDIMMNamespaceInfo, 1);
Packit 2ba279
Packit 2ba279
    new_info->dev = g_strdup (info->dev);
Packit 2ba279
    new_info->mode = info->mode;
Packit 2ba279
    new_info->size = info->size;
Packit 2ba279
    new_info->uuid = g_strdup (info->uuid);
Packit 2ba279
    new_info->sector_size = info->sector_size;
Packit 2ba279
    new_info->blockdev = g_strdup (info->blockdev);
Packit 2ba279
    new_info->enabled = info->enabled;
Packit 2ba279
Packit 2ba279
    return new_info;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
Packit 2ba279
static const gchar * const mode_str[BD_NVDIMM_NAMESPACE_MODE_UNKNOWN+1] = {"raw", "sector", "memory", "dax", "fsdax", "devdax", "unknown"};
Packit 2ba279
Packit 2ba279
static volatile guint avail_deps = 0;
Packit 2ba279
static GMutex deps_check_lock;
Packit 2ba279
Packit 2ba279
#define DEPS_NDCTL 0
Packit 2ba279
#define DEPS_NDCTL_MASK (1 << DEPS_NDCTL)
Packit 2ba279
#define DEPS_LAST 1
Packit 2ba279
Packit 2ba279
static const UtilDep deps[DEPS_LAST] = {
Packit 2ba279
    {"ndctl", NULL, NULL, NULL},
Packit 2ba279
};
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_check_deps:
Packit 2ba279
 *
Packit 2ba279
 * Returns: whether the plugin's runtime dependencies are satisfied or not
Packit 2ba279
 *
Packit 2ba279
 * Function checking plugin's runtime dependencies.
Packit 2ba279
 *
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_check_deps (void) {
Packit 2ba279
    GError *error = NULL;
Packit 2ba279
    guint i = 0;
Packit 2ba279
    gboolean status = FALSE;
Packit 2ba279
    gboolean ret = TRUE;
Packit 2ba279
Packit 2ba279
    for (i=0; i < DEPS_LAST; i++) {
Packit 2ba279
        status = bd_utils_check_util_version (deps[i].name, deps[i].version,
Packit 2ba279
                                              deps[i].ver_arg, deps[i].ver_regexp, &error);
Packit 2ba279
        if (!status)
Packit 2ba279
            g_warning ("%s", error->message);
Packit 2ba279
        else
Packit 2ba279
            g_atomic_int_or (&avail_deps, 1 << i);
Packit 2ba279
        g_clear_error (&error);
Packit 2ba279
        ret = ret && status;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    if (!ret)
Packit 2ba279
        g_warning("Cannot load the NVDIMM plugin");
Packit 2ba279
Packit 2ba279
    return ret;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_init:
Packit 2ba279
 *
Packit 2ba279
 * Initializes the plugin. **This function is called automatically by the
Packit 2ba279
 * library's initialization functions.**
Packit 2ba279
 *
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_init (void) {
Packit 2ba279
    /* nothing to do here */
Packit 2ba279
    return TRUE;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_close:
Packit 2ba279
 *
Packit 2ba279
 * Cleans up after the plugin. **This function is called automatically by the
Packit 2ba279
 * library's functions that unload it.**
Packit 2ba279
 *
Packit 2ba279
 */
Packit 2ba279
void bd_nvdimm_close (void) {
Packit 2ba279
    /* nothing to do here */
Packit 2ba279
    return;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
#define UNUSED __attribute__((unused))
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_is_tech_avail:
Packit 2ba279
 * @tech: the queried tech
Packit 2ba279
 * @mode: a bit mask of queried modes of operation (#BDNVDIMMTechMode) for @tech
Packit 2ba279
 * @error: (out): place to store error (details about why the @tech-@mode combination is not available)
Packit 2ba279
 *
Packit 2ba279
 * Returns: whether the @tech-@mode combination is available -- supported by the
Packit 2ba279
 *          plugin implementation and having all the runtime dependencies available
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_is_tech_avail (BDNVDIMMTech tech, guint64 mode, GError **error) {
Packit 2ba279
  /* all tech-mode combinations are supported by this implementation of the
Packit 2ba279
     plugin, namespace reconfigure requires the 'ndctl' utility */
Packit 2ba279
Packit 2ba279
    if (tech == BD_NVDIMM_TECH_NAMESPACE) {
Packit 2ba279
        if (mode & BD_NVDIMM_TECH_MODE_RECONFIGURE)
Packit 2ba279
            return check_deps (&avail_deps, DEPS_NDCTL_MASK, deps, DEPS_LAST, &deps_check_lock, error);
Packit 2ba279
        else
Packit 2ba279
            return TRUE;
Packit 2ba279
    } else {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_TECH_UNAVAIL, "Unknown technology");
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    return TRUE;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_get_mode_from_str:
Packit 2ba279
 * @mode_str: string representation of mode
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: mode matching the @mode_str given or %BD_NVDIMM_NAMESPACE_MODE_UNKNOWN in case of no match
Packit 2ba279
 *
Packit 2ba279
 * Tech category: always available
Packit 2ba279
 */
Packit 2ba279
BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_str, GError **error) {
Packit 2ba279
    if (g_strcmp0 (mode_str, "raw") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_RAW;
Packit 2ba279
    else if (g_strcmp0 (mode_str, "sector") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_SECTOR;
Packit 2ba279
    else if (g_strcmp0 (mode_str, "memory") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_MEMORY;
Packit 2ba279
    else if (g_strcmp0 (mode_str, "dax") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_DAX;
Packit 2ba279
    else if (g_strcmp0 (mode_str, "fsdax") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_FSDAX;
Packit 2ba279
    else if (g_strcmp0 (mode_str, "devdax") == 0)
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_DEVDAX;
Packit 2ba279
    else {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
Packit 2ba279
                     "Invalid mode given: '%s'", mode_str);
Packit 2ba279
        return BD_NVDIMM_NAMESPACE_MODE_UNKNOWN;
Packit 2ba279
    }
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_get_mode_str:
Packit 2ba279
 * @mode: mode to get string representation of
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: (transfer none): string representation of @mode or %NULL in case of error
Packit 2ba279
 *
Packit 2ba279
 * Tech category: always available
Packit 2ba279
 */
Packit 2ba279
const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error) {
Packit 2ba279
    if (mode <= BD_NVDIMM_NAMESPACE_MODE_UNKNOWN)
Packit 2ba279
        return mode_str[mode];
Packit 2ba279
    else {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
Packit 2ba279
                     "Invalid mode given: %d", mode);
Packit 2ba279
        return NULL;
Packit 2ba279
    }
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
static struct ndctl_namespace* get_namespace_by_name (const gchar *namespace, struct ndctl_ctx *ctx) {
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    struct ndctl_region *region = NULL;
Packit 2ba279
    struct ndctl_bus *bus = NULL;
Packit 2ba279
Packit 2ba279
    ndctl_bus_foreach (ctx, bus) {
Packit 2ba279
        ndctl_region_foreach (bus, region) {
Packit 2ba279
            ndctl_namespace_foreach (region, ndns) {
Packit 2ba279
                if (g_strcmp0 (namespace, ndctl_namespace_get_devname (ndns)) == 0)
Packit 2ba279
                    return ndns;
Packit 2ba279
            }
Packit 2ba279
        }
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    return NULL;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_get_devname:
Packit 2ba279
 * @device: name or path of a block device (e.g. "/dev/pmem0")
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: (transfer full): namespace device name (e.g. "namespaceX.Y") for @device
Packit 2ba279
 *                           or %NULL if @device is not a NVDIMM namespace
Packit 2ba279
 *                           (@error may be set to indicate error)
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
Packit 2ba279
 */
Packit 2ba279
gchar* bd_nvdimm_namespace_get_devname (const gchar *device, GError **error) {
Packit 2ba279
    struct ndctl_ctx *ctx = NULL;
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    struct ndctl_region *region = NULL;
Packit 2ba279
    struct ndctl_bus *bus = NULL;
Packit 2ba279
    gint success = 0;
Packit 2ba279
    gchar *ret = NULL;
Packit 2ba279
Packit 2ba279
    /* get rid of the "/dev/" prefix (if any) */
Packit 2ba279
    if (g_str_has_prefix (device, "/dev/"))
Packit 2ba279
        device = device + 5;
Packit 2ba279
Packit 2ba279
    success = ndctl_new (&ctx;;
Packit 2ba279
    if (success != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to create ndctl context");
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_bus_foreach (ctx, bus) {
Packit 2ba279
        ndctl_region_foreach (bus, region) {
Packit 2ba279
            ndctl_namespace_foreach (region, ndns) {
Packit 2ba279
                if (!ndctl_namespace_is_active (ndns))
Packit 2ba279
                    continue;
Packit 2ba279
Packit 2ba279
                struct ndctl_btt *btt = ndctl_namespace_get_btt (ndns);
Packit 2ba279
                struct ndctl_dax *dax = ndctl_namespace_get_dax (ndns);
Packit 2ba279
                struct ndctl_pfn *pfn = ndctl_namespace_get_pfn (ndns);
Packit 2ba279
                const gchar *blockdev = NULL;
Packit 2ba279
Packit 2ba279
                if (dax)
Packit 2ba279
                    continue;
Packit 2ba279
                else if (btt)
Packit 2ba279
                    blockdev = ndctl_btt_get_block_device (btt);
Packit 2ba279
                else if (pfn)
Packit 2ba279
                    blockdev = ndctl_pfn_get_block_device (pfn);
Packit 2ba279
                else
Packit 2ba279
                    blockdev = ndctl_namespace_get_block_device (ndns);
Packit 2ba279
Packit 2ba279
                if (g_strcmp0 (blockdev, device) == 0) {
Packit 2ba279
                    ret = g_strdup (ndctl_namespace_get_devname (ndns));
Packit 2ba279
                    ndctl_unref (ctx);
Packit 2ba279
                    return ret;
Packit 2ba279
                }
Packit 2ba279
            }
Packit 2ba279
        }
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_unref (ctx);
Packit 2ba279
    return NULL;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_enable:
Packit 2ba279
 * @namespace: name of the namespace to enable
Packit 2ba279
 * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: whether the @namespace was successfully enabled or not
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_namespace_enable (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
Packit 2ba279
    struct ndctl_ctx *ctx = NULL;
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    gint ret = 0;
Packit 2ba279
Packit 2ba279
    ret = ndctl_new (&ctx;;
Packit 2ba279
    if (ret != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to create ndctl context");
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndns = get_namespace_by_name (namespace, ctx);
Packit 2ba279
    if (!ndns) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
Packit 2ba279
                     "Failed to enable namespace: namespace '%s' not found.", namespace);
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ret = ndctl_namespace_enable (ndns);
Packit 2ba279
    if (ret < 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to enable namespace: %s", strerror (-ret));
Packit 2ba279
        ndctl_unref (ctx);
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_unref (ctx);
Packit 2ba279
    return TRUE;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_disable:
Packit 2ba279
 * @namespace: name of the namespace to disable
Packit 2ba279
 * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: whether the @namespace was successfully disabled or not
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_namespace_disable (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
Packit 2ba279
    struct ndctl_ctx *ctx = NULL;
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    gint ret = 0;
Packit 2ba279
Packit 2ba279
    ret = ndctl_new (&ctx;;
Packit 2ba279
    if (ret != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to create ndctl context");
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndns = get_namespace_by_name (namespace, ctx);
Packit 2ba279
    if (!ndns) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
Packit 2ba279
                     "Failed to disable namespace: namespace '%s' not found.", namespace);
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ret = ndctl_namespace_disable_safe (ndns);
Packit 2ba279
    if (ret != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to disable namespace: %s", strerror (-ret));
Packit 2ba279
        ndctl_unref (ctx);
Packit 2ba279
        return FALSE;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_unref (ctx);
Packit 2ba279
    return TRUE;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
static BDNVDIMMNamespaceInfo* get_nvdimm_namespace_info (struct ndctl_namespace *ndns, GError **error) {
Packit 2ba279
    struct ndctl_btt *btt;
Packit 2ba279
    struct ndctl_pfn *pfn;
Packit 2ba279
    struct ndctl_dax *dax;
Packit 2ba279
    enum ndctl_namespace_mode mode;
Packit 2ba279
    gchar uuid_buf[37] = {0};
Packit 2ba279
    uuid_t uuid;
Packit 2ba279
Packit 2ba279
    btt = ndctl_namespace_get_btt (ndns);
Packit 2ba279
    dax = ndctl_namespace_get_dax (ndns);
Packit 2ba279
    pfn = ndctl_namespace_get_pfn (ndns);
Packit 2ba279
    mode = ndctl_namespace_get_mode (ndns);
Packit 2ba279
Packit 2ba279
    BDNVDIMMNamespaceInfo *info = g_new0 (BDNVDIMMNamespaceInfo, 1);
Packit 2ba279
Packit 2ba279
    info->dev = g_strdup (ndctl_namespace_get_devname (ndns));
Packit 2ba279
Packit 2ba279
    switch (mode) {
Packit 2ba279
        case NDCTL_NS_MODE_MEMORY:
Packit 2ba279
            if (pfn)
Packit 2ba279
              info->size = ndctl_pfn_get_size (pfn);
Packit 2ba279
            else
Packit 2ba279
              info->size = ndctl_namespace_get_size (ndns);
Packit 2ba279
#ifndef LIBNDCTL_NEW_MODES
Packit 2ba279
          info->mode = BD_NVDIMM_NAMESPACE_MODE_MEMORY;
Packit 2ba279
#else
Packit 2ba279
          info->mode = BD_NVDIMM_NAMESPACE_MODE_FSDAX;
Packit 2ba279
#endif
Packit 2ba279
          break;
Packit 2ba279
        case NDCTL_NS_MODE_DAX:
Packit 2ba279
            if (!dax) {
Packit 2ba279
                g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                             "Failed to get information about namespaces: DAX mode "
Packit 2ba279
                             "detected but no DAX device found.");
Packit 2ba279
                bd_nvdimm_namespace_info_free (info);
Packit 2ba279
                return NULL;
Packit 2ba279
            }
Packit 2ba279
            info->size = ndctl_dax_get_size (dax);
Packit 2ba279
#ifndef LIBNDCTL_NEW_MODES
Packit 2ba279
            info->mode = BD_NVDIMM_NAMESPACE_MODE_DAX;
Packit 2ba279
#else
Packit 2ba279
            info->mode = BD_NVDIMM_NAMESPACE_MODE_DEVDAX;
Packit 2ba279
#endif
Packit 2ba279
            break;
Packit 2ba279
        case NDCTL_NS_MODE_SAFE:
Packit 2ba279
            if (!btt) {
Packit 2ba279
                g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                             "Failed to get information about namespaces: Sector mode "
Packit 2ba279
                             "detected but no BTT device found.");
Packit 2ba279
                bd_nvdimm_namespace_info_free (info);
Packit 2ba279
                return NULL;
Packit 2ba279
            }
Packit 2ba279
            info->size = ndctl_btt_get_size (btt);
Packit 2ba279
            info->mode = BD_NVDIMM_NAMESPACE_MODE_SECTOR;
Packit 2ba279
            break;
Packit 2ba279
        case NDCTL_NS_MODE_RAW:
Packit 2ba279
            info->size = ndctl_namespace_get_size (ndns);
Packit 2ba279
            info->mode = BD_NVDIMM_NAMESPACE_MODE_RAW;
Packit 2ba279
            break;
Packit 2ba279
        default:
Packit 2ba279
            g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                         "Failed to get information about namespaces: Unknow mode.");
Packit 2ba279
            bd_nvdimm_namespace_info_free (info);
Packit 2ba279
            return NULL;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    if (btt) {
Packit 2ba279
        ndctl_btt_get_uuid (btt, uuid);
Packit 2ba279
        uuid_unparse (uuid, uuid_buf);
Packit 2ba279
        info->uuid = g_strdup (uuid_buf);
Packit 2ba279
Packit 2ba279
        info->blockdev = g_strdup (ndctl_btt_get_block_device (btt));
Packit 2ba279
    } else if (pfn) {
Packit 2ba279
        ndctl_pfn_get_uuid (pfn, uuid);
Packit 2ba279
        uuid_unparse (uuid, uuid_buf);
Packit 2ba279
        info->uuid = g_strdup (uuid_buf);
Packit 2ba279
Packit 2ba279
        info->blockdev = g_strdup (ndctl_pfn_get_block_device (pfn));
Packit 2ba279
    } else if (dax) {
Packit 2ba279
        ndctl_dax_get_uuid (dax, uuid);
Packit 2ba279
        uuid_unparse (uuid, uuid_buf);
Packit 2ba279
        info->uuid = g_strdup (uuid_buf);
Packit 2ba279
Packit 2ba279
        /* no blockdev for dax mode */
Packit 2ba279
        info->blockdev = NULL;
Packit 2ba279
    } else {
Packit 2ba279
        ndctl_namespace_get_uuid (ndns, uuid);
Packit 2ba279
Packit 2ba279
        if (uuid_is_null (uuid))
Packit 2ba279
            info->uuid = NULL;
Packit 2ba279
        else {
Packit 2ba279
            uuid_unparse (uuid, uuid_buf);
Packit 2ba279
            info->uuid = g_strdup (uuid_buf);
Packit 2ba279
        }
Packit 2ba279
Packit 2ba279
        info->blockdev = g_strdup (ndctl_namespace_get_block_device (ndns));
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    if (btt)
Packit 2ba279
        info->sector_size = ndctl_btt_get_sector_size (btt);
Packit 2ba279
    else if (dax)
Packit 2ba279
        /* no sector size for dax mode */
Packit 2ba279
        info->sector_size = 0;
Packit 2ba279
    else {
Packit 2ba279
        info->sector_size = ndctl_namespace_get_sector_size (ndns);
Packit 2ba279
Packit 2ba279
        /* apparently the default value for sector size is 512
Packit 2ba279
           on non DAX namespaces even if libndctl says it's 0
Packit 2ba279
           https://github.com/pmem/ndctl/commit/a7320456f1bca5edf15352ce977e757fdf78ed58
Packit 2ba279
         */
Packit 2ba279
Packit 2ba279
        if (info->sector_size == 0)
Packit 2ba279
            info->sector_size = 512;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    info->enabled = ndctl_namespace_is_active (ndns);
Packit 2ba279
Packit 2ba279
    return info;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_info:
Packit 2ba279
 * @namespace: namespace to get information about
Packit 2ba279
 * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: (transfer full): information about given namespace or %NULL if no such
Packit 2ba279
 *                           namespace was found (@error may be set to indicate error)
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
Packit 2ba279
 */
Packit 2ba279
BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
Packit 2ba279
    struct ndctl_ctx *ctx = NULL;
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    BDNVDIMMNamespaceInfo *info = NULL;
Packit 2ba279
    gint ret = 0;
Packit 2ba279
Packit 2ba279
    ret = ndctl_new (&ctx;;
Packit 2ba279
    if (ret != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to create ndctl context");
Packit 2ba279
        return NULL;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndns = get_namespace_by_name (namespace, ctx);
Packit 2ba279
    if (ndns) {
Packit 2ba279
        info = get_nvdimm_namespace_info (ndns, error);
Packit 2ba279
        ndctl_unref (ctx);
Packit 2ba279
        return info;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_unref (ctx);
Packit 2ba279
    return NULL;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_list_namespaces:
Packit 2ba279
 * @bus_name: (allow-none): return only namespaces on given bus (specified by name),
Packit 2ba279
 *                          %NULL may be specified to return namespaces from all buses
Packit 2ba279
 * @region_name: (allow-none): return only namespaces on given region (specified by 'regionX' name),
Packit 2ba279
 *                             %NULL may be specified to return namespaces from all regions
Packit 2ba279
 * @idle: whether to list idle (not enabled) namespaces too
Packit 2ba279
 * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
Packit 2ba279
 * @error: (out): place to store error (if any)
Packit 2ba279
 *
Packit 2ba279
 * Returns: (array zero-terminated=1): information about the namespaces on @bus and @region or
Packit 2ba279
 *                                     %NULL if no namespaces were found (@error may be set to indicate error)
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
Packit 2ba279
 */
Packit 2ba279
BDNVDIMMNamespaceInfo** bd_nvdimm_list_namespaces (const gchar *bus_name, const gchar *region_name, gboolean idle, const BDExtraArg **extra UNUSED, GError **error) {
Packit 2ba279
    struct ndctl_ctx *ctx = NULL;
Packit 2ba279
    struct ndctl_namespace *ndns = NULL;
Packit 2ba279
    struct ndctl_region *region = NULL;
Packit 2ba279
    struct ndctl_bus *bus = NULL;
Packit 2ba279
    gint ret = 0;
Packit 2ba279
    BDNVDIMMNamespaceInfo **info = NULL;
Packit 2ba279
Packit 2ba279
    GPtrArray *namespaces = g_ptr_array_new ();
Packit 2ba279
Packit 2ba279
    ret = ndctl_new (&ctx;;
Packit 2ba279
    if (ret != 0) {
Packit 2ba279
        g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
Packit 2ba279
                     "Failed to create ndctl context");
Packit 2ba279
        return NULL;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    ndctl_bus_foreach (ctx, bus) {
Packit 2ba279
        if (bus_name && g_strcmp0 (bus_name, ndctl_bus_get_devname (bus)) != 0)
Packit 2ba279
            continue;
Packit 2ba279
Packit 2ba279
        ndctl_region_foreach (bus, region) {
Packit 2ba279
            if (region_name && g_strcmp0 (bus_name, ndctl_region_get_devname (region)) != 0)
Packit 2ba279
                continue;
Packit 2ba279
Packit 2ba279
            ndctl_namespace_foreach (region, ndns) {
Packit 2ba279
                if (!idle && !ndctl_namespace_is_active (ndns))
Packit 2ba279
                    continue;
Packit 2ba279
Packit 2ba279
                BDNVDIMMNamespaceInfo *info = get_nvdimm_namespace_info (ndns, error);
Packit 2ba279
                if (!info) {
Packit 2ba279
                    g_ptr_array_foreach (namespaces, (GFunc) (void *) bd_nvdimm_namespace_info_free, NULL);
Packit 2ba279
                    g_ptr_array_free (namespaces, FALSE);
Packit 2ba279
                    ndctl_unref (ctx);
Packit 2ba279
                    return NULL;
Packit 2ba279
                }
Packit 2ba279
Packit 2ba279
                g_ptr_array_add (namespaces, info);
Packit 2ba279
            }
Packit 2ba279
        }
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    if (namespaces->len == 0) {
Packit 2ba279
        ndctl_unref (ctx);
Packit 2ba279
        return NULL;
Packit 2ba279
    }
Packit 2ba279
Packit 2ba279
    g_ptr_array_add (namespaces, NULL);
Packit 2ba279
Packit 2ba279
    info = (BDNVDIMMNamespaceInfo **) g_ptr_array_free (namespaces, FALSE);
Packit 2ba279
    ndctl_unref (ctx);
Packit 2ba279
Packit 2ba279
    return info;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namespace_reconfigure:
Packit 2ba279
 * @namespace: name of the namespace to recofigure
Packit 2ba279
 * @mode: mode type to set
Packit 2ba279
 * @error: (out): place to store error if any
Packit 2ba279
 * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now
Packit 2ba279
 *                                                 passed to the 'ndctl' utility)
Packit 2ba279
 *
Packit 2ba279
 * Returns: whether @namespace was successfully reconfigured or not
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_RECONFIGURE
Packit 2ba279
 */
Packit 2ba279
gboolean bd_nvdimm_namespace_reconfigure (const gchar* namespace, BDNVDIMMNamespaceMode mode, gboolean force, const BDExtraArg **extra, GError** error) {
Packit 2ba279
    const gchar *args[8] = {"ndctl", "create-namespace", "-e", namespace, "-m", NULL, NULL, NULL};
Packit 2ba279
    gboolean ret = FALSE;
Packit 2ba279
    const gchar *mode_str = NULL;
Packit 2ba279
Packit 2ba279
    if (!check_deps (&avail_deps, DEPS_NDCTL_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit 2ba279
      return FALSE;
Packit 2ba279
Packit 2ba279
    mode_str = bd_nvdimm_namespace_get_mode_str (mode, error);
Packit 2ba279
    if (!mode_str)
Packit 2ba279
        /* error is already populated */
Packit 2ba279
        return FALSE;
Packit 2ba279
Packit 2ba279
    args[5] = g_strdup (mode_str);
Packit 2ba279
Packit 2ba279
    if (force)
Packit 2ba279
      args[6] = "-f";
Packit 2ba279
Packit 2ba279
    ret = bd_utils_exec_and_report_error (args, extra, error);
Packit 2ba279
Packit 2ba279
    g_free ((gchar *) args[5]);
Packit 2ba279
    return ret;
Packit 2ba279
}
Packit 2ba279
Packit 2ba279
Packit 2ba279
static guint64 blk_sector_sizes[] = { 512, 520, 528, 4096, 4104, 4160, 4224, 0 };
Packit 2ba279
static guint64 pmem_sector_sizes[] = { 512, 4096, 0 };
Packit 2ba279
static guint64 io_sector_sizes[] = { 0 };
Packit 2ba279
Packit 2ba279
/**
Packit 2ba279
 * bd_nvdimm_namepace_get_supported_sector_sizes:
Packit 2ba279
 * @mode: namespace mode
Packit 2ba279
 * @error: (out): place to store error if any
Packit 2ba279
 *
Packit 2ba279
 * Returns: (transfer none) (array zero-terminated=1): list of supported sector sizes for @mode
Packit 2ba279
 *
Packit 2ba279
 * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
Packit 2ba279
 */
Packit 2ba279
const guint64 *bd_nvdimm_namepace_get_supported_sector_sizes (BDNVDIMMNamespaceMode mode, GError **error) {
Packit 2ba279
    switch (mode) {
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_RAW:
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_MEMORY:
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_FSDAX:
Packit 2ba279
            return pmem_sector_sizes;
Packit 2ba279
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_DAX:
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_DEVDAX:
Packit 2ba279
            return io_sector_sizes;
Packit 2ba279
Packit 2ba279
        case BD_NVDIMM_NAMESPACE_MODE_SECTOR:
Packit 2ba279
            return blk_sector_sizes;
Packit 2ba279
Packit 2ba279
        default:
Packit 2ba279
            g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
Packit 2ba279
                         "Invalid/unknown mode specified.");
Packit 2ba279
            return NULL;
Packit 2ba279
    }
Packit 2ba279
}